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  }