package main import ( "context" "crypto/sha256" "fmt" "os" "time" "git.intruders.space/public/opentimestamps" "git.intruders.space/public/opentimestamps/ots" ) func main() { // Read a file to timestamp fileData, err := os.ReadFile("document.txt") if err != nil { fmt.Println("Error reading file:", err) return } // Calculate the digest digest := sha256.Sum256(fileData) fmt.Printf("File digest: %x\n", digest) // Define calendar servers calendars := []string{ "https://alice.btc.calendar.opentimestamps.org", "https://bob.btc.calendar.opentimestamps.org", "https://finney.calendar.eternitywall.com", } // Create a timestamp using each calendar ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) defer cancel() var sequences []ots.Sequence for _, calendarURL := range calendars { fmt.Printf("Submitting to %s...\n", calendarURL) seq, err := opentimestamps.Stamp(ctx, calendarURL, digest) if err != nil { fmt.Printf("Failed to submit to %s: %v\n", calendarURL, err) continue } fmt.Printf("Submission to %s successful\n", calendarURL) sequences = append(sequences, seq) } if len(sequences) == 0 { fmt.Println("Failed to create any timestamps") return } // Create the timestamp file file := &ots.File{ Digest: digest[:], Sequences: sequences, } // Save the OTS file otsData := file.SerializeToFile() if err := os.WriteFile("document.txt.ots", otsData, 0644); err != nil { fmt.Println("Failed to save OTS file:", err) return } fmt.Println("Timestamp file created successfully") // Display initial timestamp info fmt.Println("\nInitial timestamp info:") fmt.Println(file.Human(false)) // Attempt to upgrade the timestamp every 20 minutes fmt.Println("\nWill check for upgrades every 20 minutes...") maxAttempts := 12 // Try for about 4 hours (12 * 20 minutes) for attempt := 0; attempt < maxAttempts; attempt++ { if attempt > 0 { fmt.Printf("\nWaiting 20 minutes before next upgrade attempt (%d/%d)...\n", attempt+1, maxAttempts) time.Sleep(20 * time.Minute) } upgraded := false pendingSequences := file.GetPendingSequences() if len(pendingSequences) == 0 { fmt.Println("No pending sequences to upgrade") break } fmt.Printf("Attempting to upgrade %d pending sequences...\n", len(pendingSequences)) upgradeCtx, upgradeCancel := context.WithTimeout(context.Background(), 30*time.Second) for _, seq := range pendingSequences { att := seq.GetAttestation() fmt.Printf("Trying to upgrade sequence from %s...\n", att.CalendarServerURL) upgradedSeq, err := opentimestamps.UpgradeSequence(upgradeCtx, seq, digest[:]) if err != nil { fmt.Printf("Failed to upgrade sequence from %s: %v\n", att.CalendarServerURL, err) continue } // Replace the sequence in the file for i, origSeq := range file.Sequences { origAtt := origSeq.GetAttestation() if origAtt.CalendarServerURL == att.CalendarServerURL { file.Sequences[i] = upgradedSeq upgraded = true newAtt := upgradedSeq.GetAttestation() if newAtt.BitcoinBlockHeight > 0 { fmt.Printf("Sequence upgraded! Confirmed in Bitcoin block %d\n", newAtt.BitcoinBlockHeight) } else { fmt.Println("Sequence updated but still pending") } break } } } upgradeCancel() if upgraded { // Save the upgraded file otsData = file.SerializeToFile() if err := os.WriteFile("document.txt.ots", otsData, 0644); err != nil { fmt.Println("Failed to save upgraded OTS file:", err) } else { fmt.Println("Upgraded timestamp file saved") } } // If all sequences are confirmed, we're done if len(file.GetPendingSequences()) == 0 { fmt.Println("All sequences are now confirmed in the Bitcoin blockchain!") break } } // Final report fmt.Println("\nFinal timestamp status:") confirmedSeqs := file.GetBitcoinAttestedSequences() pendingSeqs := file.GetPendingSequences() fmt.Printf("Confirmed attestations: %d\n", len(confirmedSeqs)) for _, seq := range confirmedSeqs { att := seq.GetAttestation() fmt.Printf("- Confirmed in Bitcoin block %d\n", att.BitcoinBlockHeight) } fmt.Printf("Pending attestations: %d\n", len(pendingSeqs)) for _, seq := range pendingSeqs { att := seq.GetAttestation() fmt.Printf("- Still pending at %s\n", att.CalendarServerURL) } fmt.Println("\nDetailed timestamp info:") fmt.Println(file.Human(true)) }