refactor
This commit is contained in:
138
cmd/ots/upgrade.go
Normal file
138
cmd/ots/upgrade.go
Normal file
@@ -0,0 +1,138 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log/slog"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"git.intruders.space/public/opentimestamps"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var (
|
||||
// Upgrade command flags
|
||||
upgradeOutput string
|
||||
upgradeTimeout time.Duration
|
||||
upgradeDryRun bool
|
||||
)
|
||||
|
||||
// upgradeCmd represents the upgrade command
|
||||
var upgradeCmd = &cobra.Command{
|
||||
Use: "upgrade [flags] <file.ots>",
|
||||
Short: "Upgrade a timestamp",
|
||||
Long: `Upgrade a timestamp by checking if pending attestations have been confirmed in the Bitcoin blockchain.
|
||||
If confirmed, the timestamp will be updated with the Bitcoin block information.`,
|
||||
Args: cobra.ExactArgs(1),
|
||||
Run: runUpgradeCmd,
|
||||
}
|
||||
|
||||
func init() {
|
||||
// Local flags for the upgrade command
|
||||
upgradeCmd.Flags().StringVarP(&upgradeOutput, "output", "o", "", "Output filename (default: overwrites the input file)")
|
||||
upgradeCmd.Flags().DurationVar(&upgradeTimeout, "timeout", 30*time.Second, "Timeout for calendar server connections")
|
||||
upgradeCmd.Flags().BoolVar(&upgradeDryRun, "dry-run", false, "Don't write output file, just check if upgrade is possible")
|
||||
}
|
||||
|
||||
func runUpgradeCmd(cmd *cobra.Command, args []string) {
|
||||
inputPath := args[0]
|
||||
|
||||
// Determine output file path
|
||||
outputPath := upgradeOutput
|
||||
if outputPath == "" {
|
||||
outputPath = inputPath
|
||||
}
|
||||
|
||||
// Read and parse the OTS file
|
||||
otsData, err := os.ReadFile(inputPath)
|
||||
if err != nil {
|
||||
slog.Error("Failed to read OTS file", "file", inputPath, "error", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
timestampFile, err := opentimestamps.ReadFromFile(otsData)
|
||||
if err != nil {
|
||||
slog.Error("Failed to parse OTS file", "file", inputPath, "error", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
// Get pending sequences to upgrade
|
||||
pendingSequences := timestampFile.GetPendingSequences()
|
||||
if len(pendingSequences) == 0 {
|
||||
slog.Info("No pending timestamps found, file is already fully upgraded", "file", inputPath)
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
slog.Info("Found pending timestamps", "count", len(pendingSequences))
|
||||
|
||||
// Create context with timeout
|
||||
ctx, cancel := context.WithTimeout(context.Background(), upgradeTimeout)
|
||||
defer cancel()
|
||||
|
||||
// Try to upgrade each pending sequence
|
||||
upgradedCount := 0
|
||||
for i, seq := range pendingSequences {
|
||||
att := seq.GetAttestation()
|
||||
slog.Info("Attempting to upgrade timestamp",
|
||||
"index", i+1,
|
||||
"calendar", att.CalendarServerURL)
|
||||
|
||||
upgraded, err := opentimestamps.UpgradeSequence(ctx, seq, timestampFile.Digest)
|
||||
if err != nil {
|
||||
slog.Warn("Upgrade failed",
|
||||
"calendar", att.CalendarServerURL,
|
||||
"error", err)
|
||||
continue
|
||||
}
|
||||
|
||||
// Replace the pending sequence with the upgraded one
|
||||
for j, origSeq := range timestampFile.Sequences {
|
||||
if origSeq[len(origSeq)-1].Attestation != nil &&
|
||||
origSeq[len(origSeq)-1].Attestation.CalendarServerURL == att.CalendarServerURL {
|
||||
timestampFile.Sequences[j] = upgraded
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
upgradedCount++
|
||||
|
||||
newAtt := upgraded.GetAttestation()
|
||||
if newAtt.BitcoinBlockHeight > 0 {
|
||||
slog.Info("Timestamp upgraded successfully",
|
||||
"calendar", att.CalendarServerURL,
|
||||
"block", newAtt.BitcoinBlockHeight)
|
||||
} else {
|
||||
slog.Info("Timestamp replaced but still pending", "calendar", att.CalendarServerURL)
|
||||
}
|
||||
}
|
||||
|
||||
if upgradedCount == 0 {
|
||||
slog.Warn("No timestamps could be upgraded at this time. Try again later.", "file", inputPath)
|
||||
if !upgradeDryRun {
|
||||
os.Exit(1)
|
||||
}
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
// In dry run mode, don't write the file
|
||||
if upgradeDryRun {
|
||||
slog.Info("Dry run completed", "upgraded", upgradedCount, "total", len(pendingSequences))
|
||||
os.Exit(0)
|
||||
}
|
||||
|
||||
// Write the updated OTS file
|
||||
newOtsData := timestampFile.SerializeToFile()
|
||||
err = os.WriteFile(outputPath, newOtsData, 0644)
|
||||
if err != nil {
|
||||
slog.Error("Failed to write updated OTS file", "file", outputPath, "error", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
slog.Info("Timestamp file upgraded successfully",
|
||||
"file", outputPath,
|
||||
"upgraded", upgradedCount,
|
||||
"total", len(pendingSequences))
|
||||
|
||||
// Print human-readable representation
|
||||
slog.Debug("Updated timestamp details", "info", timestampFile.Human(false))
|
||||
}
|
||||
Reference in New Issue
Block a user