mirror of
https://github.com/OffchainLabs/prysm.git
synced 2026-01-08 23:18:15 -05:00
Replace statefeed Initialize (#12285)
* refactor initialization to blocking startup method * require genesisSetter in blockchain, fix tests * work-around gazelle weirdness * fix dep gazelle ignores * only call SetGenesis once * fix typo * validator test setup and fix to return right error * move waitForChainStart to Start * wire up sync Service.genesisWaiter * fix p2p genesisWaiter plumbing * remove extra clock type, integrate into genesis and rename * use time.Now when no Nower is specified * remove unused ClockSetter * simplify rpc context checking * fix typo * use clock everywhere in sync; [32]byte val root * don't use DeepEqual to compare [32]byte and []byte * don't use clock in init sync, not wired up yet * use clock waiter in blockchain as well * use cancelable contexts in tests with goroutines * missed a reference to WithClockSetter * Update beacon-chain/startup/genesis.go Co-authored-by: Radosław Kapka <rkapka@wp.pl> * Update beacon-chain/blockchain/service_test.go Co-authored-by: Radosław Kapka <rkapka@wp.pl> * more clear docs * doc for NewClock * move clock typedef to more logical file name * adding documentation * gaz * fixes for capella * reducing test raciness * fix races in committee cache tests * lint * add tests on Duration slot math helper * startup package test coverage * fix bad merge * set non-zero genesis time in tests that call Start * happy deepsource, happy me-epsource * replace Synced event with channel * remove unused error * remove accidental wip commit * gaz! * remove unused event constants * remove sync statefeed subscription to fix deadlock * remove state notifier * fix build --------- Co-authored-by: Kasey Kirkham <kasey@users.noreply.github.com> Co-authored-by: Radosław Kapka <rkapka@wp.pl> Co-authored-by: prylabs-bulldozer[bot] <58059840+prylabs-bulldozer[bot]@users.noreply.github.com> Co-authored-by: nisdas <nishdas93@gmail.com>
This commit is contained in:
@@ -11,11 +11,11 @@ import (
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prysmaticlabs/prysm/v4/async/abool"
|
||||
"github.com/prysmaticlabs/prysm/v4/beacon-chain/blockchain"
|
||||
"github.com/prysmaticlabs/prysm/v4/beacon-chain/core/feed"
|
||||
blockfeed "github.com/prysmaticlabs/prysm/v4/beacon-chain/core/feed/block"
|
||||
statefeed "github.com/prysmaticlabs/prysm/v4/beacon-chain/core/feed/state"
|
||||
"github.com/prysmaticlabs/prysm/v4/beacon-chain/db"
|
||||
"github.com/prysmaticlabs/prysm/v4/beacon-chain/p2p"
|
||||
"github.com/prysmaticlabs/prysm/v4/beacon-chain/startup"
|
||||
"github.com/prysmaticlabs/prysm/v4/cmd/beacon-chain/flags"
|
||||
"github.com/prysmaticlabs/prysm/v4/config/params"
|
||||
"github.com/prysmaticlabs/prysm/v4/runtime"
|
||||
@@ -34,11 +34,13 @@ type blockchainService interface {
|
||||
|
||||
// Config to set up the initial sync service.
|
||||
type Config struct {
|
||||
P2P p2p.P2P
|
||||
DB db.ReadOnlyDatabase
|
||||
Chain blockchainService
|
||||
StateNotifier statefeed.Notifier
|
||||
BlockNotifier blockfeed.Notifier
|
||||
P2P p2p.P2P
|
||||
DB db.ReadOnlyDatabase
|
||||
Chain blockchainService
|
||||
StateNotifier statefeed.Notifier
|
||||
BlockNotifier blockfeed.Notifier
|
||||
ClockWaiter startup.ClockWaiter
|
||||
InitialSyncComplete chan struct{}
|
||||
}
|
||||
|
||||
// Service service.
|
||||
@@ -50,6 +52,7 @@ type Service struct {
|
||||
chainStarted *abool.AtomicBool
|
||||
counter *ratecounter.RateCounter
|
||||
genesisChan chan time.Time
|
||||
clock *startup.Clock
|
||||
}
|
||||
|
||||
// NewService configures the initial sync service responsible for bringing the node up to the
|
||||
@@ -66,31 +69,34 @@ func NewService(ctx context.Context, cfg *Config) *Service {
|
||||
genesisChan: make(chan time.Time),
|
||||
}
|
||||
|
||||
// The reason why we have this goroutine in the constructor is to avoid a race condition
|
||||
// between services' Start method and the initialization event.
|
||||
// See https://github.com/prysmaticlabs/prysm/issues/10602 for details.
|
||||
go s.waitForStateInitialization()
|
||||
|
||||
return s
|
||||
}
|
||||
|
||||
// Start the initial sync service.
|
||||
func (s *Service) Start() {
|
||||
// Wait for state initialized event.
|
||||
genesis := <-s.genesisChan
|
||||
if genesis.IsZero() {
|
||||
log.Info("Waiting for state to be initialized")
|
||||
clock, err := s.cfg.ClockWaiter.WaitForClock(s.ctx)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("initial-sync failed to receive startup event")
|
||||
return
|
||||
}
|
||||
s.clock = clock
|
||||
log.Info("Received state initialized event")
|
||||
|
||||
gt := clock.GenesisTime()
|
||||
if gt.IsZero() {
|
||||
log.Debug("Exiting Initial Sync Service")
|
||||
return
|
||||
}
|
||||
if genesis.After(prysmTime.Now()) {
|
||||
s.markSynced(genesis)
|
||||
log.WithField("genesisTime", genesis).Info("Genesis time has not arrived - not syncing")
|
||||
if gt.After(prysmTime.Now()) {
|
||||
s.markSynced()
|
||||
log.WithField("genesisTime", gt).Info("Genesis time has not arrived - not syncing")
|
||||
return
|
||||
}
|
||||
currentSlot := slots.Since(genesis)
|
||||
currentSlot := clock.CurrentSlot()
|
||||
if slots.ToEpoch(currentSlot) == 0 {
|
||||
log.WithField("genesisTime", genesis).Info("Chain started within the last epoch - not syncing")
|
||||
s.markSynced(genesis)
|
||||
log.WithField("genesisTime", gt).Info("Chain started within the last epoch - not syncing")
|
||||
s.markSynced()
|
||||
return
|
||||
}
|
||||
s.chainStarted.Set()
|
||||
@@ -98,18 +104,18 @@ func (s *Service) Start() {
|
||||
// Are we already in sync, or close to it?
|
||||
if slots.ToEpoch(s.cfg.Chain.HeadSlot()) == slots.ToEpoch(currentSlot) {
|
||||
log.Info("Already synced to the current chain head")
|
||||
s.markSynced(genesis)
|
||||
s.markSynced()
|
||||
return
|
||||
}
|
||||
s.waitForMinimumPeers()
|
||||
if err := s.roundRobinSync(genesis); err != nil {
|
||||
if err := s.roundRobinSync(gt); err != nil {
|
||||
if errors.Is(s.ctx.Err(), context.Canceled) {
|
||||
return
|
||||
}
|
||||
panic(err)
|
||||
}
|
||||
log.Infof("Synced up to slot %d", s.cfg.Chain.HeadSlot())
|
||||
s.markSynced(genesis)
|
||||
s.markSynced()
|
||||
}
|
||||
|
||||
// Stop initial sync.
|
||||
@@ -181,48 +187,8 @@ func (s *Service) waitForMinimumPeers() {
|
||||
}
|
||||
}
|
||||
|
||||
// waitForStateInitialization makes sure that beacon node is ready to be accessed: it is either
|
||||
// already properly configured or system waits up until state initialized event is triggered.
|
||||
func (s *Service) waitForStateInitialization() {
|
||||
// Wait for state to be initialized.
|
||||
stateChannel := make(chan *feed.Event, 1)
|
||||
stateSub := s.cfg.StateNotifier.StateFeed().Subscribe(stateChannel)
|
||||
defer stateSub.Unsubscribe()
|
||||
log.Info("Waiting for state to be initialized")
|
||||
for {
|
||||
select {
|
||||
case event := <-stateChannel:
|
||||
if event.Type == statefeed.Initialized {
|
||||
data, ok := event.Data.(*statefeed.InitializedData)
|
||||
if !ok {
|
||||
log.Error("Event feed data is not type *statefeed.InitializedData")
|
||||
continue
|
||||
}
|
||||
log.WithField("starttime", data.StartTime).Debug("Received state initialized event")
|
||||
s.genesisChan <- data.StartTime
|
||||
return
|
||||
}
|
||||
case <-s.ctx.Done():
|
||||
log.Debug("Context closed, exiting goroutine")
|
||||
// Send a zero time in the event we are exiting.
|
||||
s.genesisChan <- time.Time{}
|
||||
return
|
||||
case err := <-stateSub.Err():
|
||||
log.WithError(err).Error("Subscription to state notifier failed")
|
||||
// Send a zero time in the event we are exiting.
|
||||
s.genesisChan <- time.Time{}
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// markSynced marks node as synced and notifies feed listeners.
|
||||
func (s *Service) markSynced(genesis time.Time) {
|
||||
func (s *Service) markSynced() {
|
||||
s.synced.Set()
|
||||
s.cfg.StateNotifier.StateFeed().Send(&feed.Event{
|
||||
Type: statefeed.Synced,
|
||||
Data: &statefeed.SyncedData{
|
||||
StartTime: genesis,
|
||||
},
|
||||
})
|
||||
close(s.cfg.InitialSyncComplete)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user