159 lines
4.3 KiB
Go
159 lines
4.3 KiB
Go
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))
|
|
}
|