github.com/unicornultrafoundation/go-u2u@v1.0.0-rc1.0.20240205080301-e74a83d3fadc/gossip/emitter/sync.go (about) 1 package emitter 2 3 import ( 4 "fmt" 5 "time" 6 7 "github.com/unicornultrafoundation/go-helios/emitter/doublesign" 8 "github.com/unicornultrafoundation/go-helios/hash" 9 10 "github.com/unicornultrafoundation/go-u2u/native" 11 "github.com/unicornultrafoundation/go-u2u/utils/errlock" 12 ) 13 14 type syncStatus struct { 15 startup time.Time 16 lastConnected time.Time 17 p2pSynced time.Time 18 prevLocalEmittedID hash.Event 19 externalSelfEventCreated time.Time 20 externalSelfEventDetected time.Time 21 becameValidator time.Time 22 } 23 24 func (em *Emitter) onNewExternalEvent(e native.EventPayloadI) { 25 em.syncStatus.externalSelfEventDetected = time.Now() 26 em.syncStatus.externalSelfEventCreated = e.CreationTime().Time() 27 status := em.currentSyncStatus() 28 if doublesign.DetectParallelInstance(status, em.config.EmitIntervals.ParallelInstanceProtection) { 29 passedSinceEvent := status.Since(status.ExternalSelfEventCreated) 30 reason := "Received a recent event (event id=%s) from this validator (validator ID=%d) which wasn't created on this node.\n" + 31 "This external event was created %s, %s ago at the time of this error.\n" + 32 "It might mean that a duplicating instance of the same validator is running simultaneously, which may eventually lead to a doublesign.\n" + 33 "The node was stopped by one of the doublesign protection heuristics.\n" + 34 "There's no guaranteed automatic protection against a doublesign, " + 35 "please always ensure that no more than one instance of the same validator is running." 36 errlock.Permanent(fmt.Errorf(reason, e.ID().String(), em.config.Validator.ID, e.CreationTime().Time().Local().String(), passedSinceEvent.String())) 37 panic("unreachable") 38 } 39 } 40 41 func (em *Emitter) currentSyncStatus() doublesign.SyncStatus { 42 s := doublesign.SyncStatus{ 43 Now: time.Now(), 44 PeersNum: em.world.PeersNum(), 45 Startup: em.syncStatus.startup, 46 LastConnected: em.syncStatus.lastConnected, 47 ExternalSelfEventCreated: em.syncStatus.externalSelfEventCreated, 48 ExternalSelfEventDetected: em.syncStatus.externalSelfEventDetected, 49 BecameValidator: em.syncStatus.becameValidator, 50 } 51 if em.world.IsSynced() { 52 s.P2PSynced = em.syncStatus.p2pSynced 53 } 54 prevEmitted := em.readLastEmittedEventID() 55 if prevEmitted != nil && (em.world.GetEvent(*prevEmitted) == nil && em.epoch <= prevEmitted.Epoch()) { 56 s.P2PSynced = time.Time{} 57 } 58 return s 59 } 60 61 func (em *Emitter) isSyncedToEmit() (time.Duration, error) { 62 if em.intervals.DoublesignProtection == 0 { 63 return 0, nil // protection disabled 64 } 65 return doublesign.SyncedToEmit(em.currentSyncStatus(), em.intervals.DoublesignProtection) 66 } 67 68 func (em *Emitter) logSyncStatus(wait time.Duration, syncErr error) bool { 69 if syncErr == nil { 70 return true 71 } 72 73 if wait == 0 { 74 em.Periodic.Info(7*time.Second, "Emitting is paused", "reason", syncErr) 75 } else { 76 em.Periodic.Info(7*time.Second, "Emitting is paused", "reason", syncErr, "wait", wait) 77 } 78 return false 79 }