diff --git a/packages/taiko-client/driver/chain_syncer/beaconsync/progress_tracker.go b/packages/taiko-client/driver/chain_syncer/beaconsync/progress_tracker.go index d86e47408bf..faa909907c4 100644 --- a/packages/taiko-client/driver/chain_syncer/beaconsync/progress_tracker.go +++ b/packages/taiko-client/driver/chain_syncer/beaconsync/progress_tracker.go @@ -29,6 +29,11 @@ type SyncProgressTracker struct { lastSyncedBlockID *big.Int lastSyncedBlockHash common.Hash + // latest verified block ID. + verifyBlockID *big.Int + // current syncing block ID. + syncBlockID *big.Int + // Out-of-sync check related lastSyncProgress *ethereum.SyncProgress lastProgressedTime time.Time @@ -133,6 +138,33 @@ func (t *SyncProgressTracker) track(ctx context.Context) { } } +// ShouldSync checks whether sync is needed. +func (t *SyncProgressTracker) ShouldSync(verifyBlockID *big.Int) (uint64, bool) { + if t.verifyBlockID == nil { + t.verifyBlockID = new(big.Int).Set(verifyBlockID) + } + // If sync blockID is null or the new verifyBlockID is ahead of the current sync block ID, sync again. + if t.syncBlockID == nil || t.syncBlockID.Cmp(verifyBlockID) > 0 { + t.syncBlockID = new(big.Int).Set(verifyBlockID) + return t.syncBlockID.Uint64(), true + } + + // This check means that the current syncing work is finished syncing, update syncBlockID and sync again. + lastSyncedBlockID := t.LastSyncedBlockID() + if lastSyncedBlockID != nil && t.syncBlockID.Cmp(lastSyncedBlockID) == 0 { + t.syncBlockID = new(big.Int).Set(verifyBlockID) + return t.syncBlockID.Uint64(), true + } + + // If the latest verified block is ahead of the current sync block ID 32 blocks, trigger the current syncing again. + if t.verifyBlockID.Uint64()+32 <= verifyBlockID.Uint64() { + t.verifyBlockID = new(big.Int).Set(verifyBlockID) + return t.syncBlockID.Uint64(), true + } + + return t.syncBlockID.Uint64(), false +} + // UpdateMeta updates the inner beacon sync metadata. func (t *SyncProgressTracker) UpdateMeta(id *big.Int, blockHash common.Hash) { t.mutex.Lock() @@ -162,18 +194,6 @@ func (t *SyncProgressTracker) ClearMeta() { t.outOfSync = false } -// HeadChanged checks if a new beacon sync request will be needed. -func (t *SyncProgressTracker) HeadChanged(newID *big.Int) bool { - t.mutex.RLock() - defer t.mutex.RUnlock() - - if !t.triggered { - return true - } - - return t.lastSyncedBlockID != nil && t.lastSyncedBlockID != newID -} - // OutOfSync tells whether the L2 execution engine is marked as out of sync. func (t *SyncProgressTracker) OutOfSync() bool { t.mutex.RLock() diff --git a/packages/taiko-client/driver/chain_syncer/beaconsync/progress_tracker_test.go b/packages/taiko-client/driver/chain_syncer/beaconsync/progress_tracker_test.go index 084e57c41f7..fe9d5eaa157 100644 --- a/packages/taiko-client/driver/chain_syncer/beaconsync/progress_tracker_test.go +++ b/packages/taiko-client/driver/chain_syncer/beaconsync/progress_tracker_test.go @@ -55,12 +55,6 @@ func (s *BeaconSyncProgressTrackerTestSuite) TestClearMeta() { s.False(s.t.triggered) } -func (s *BeaconSyncProgressTrackerTestSuite) TestHeadChanged() { - s.True(s.t.HeadChanged(common.Big256)) - s.t.triggered = true - s.False(s.t.HeadChanged(common.Big256)) -} - func (s *BeaconSyncProgressTrackerTestSuite) TestOutOfSync() { s.False(s.t.OutOfSync()) } diff --git a/packages/taiko-client/driver/chain_syncer/beaconsync/syncer.go b/packages/taiko-client/driver/chain_syncer/beaconsync/syncer.go index f03a9309d1d..9b68736ebe5 100644 --- a/packages/taiko-client/driver/chain_syncer/beaconsync/syncer.go +++ b/packages/taiko-client/driver/chain_syncer/beaconsync/syncer.go @@ -38,15 +38,15 @@ func NewSyncer( // TriggerBeaconSync triggers the L2 execution engine to start performing a beacon sync, if the // latest verified block has changed. -func (s *Syncer) TriggerBeaconSync(blockID uint64) error { - latestVerifiedHeadPayload, err := s.getVerifiedBlockPayload(s.ctx, blockID) - if err != nil { - return err +func (s *Syncer) TriggerBeaconSync(verifyBlockID uint64) error { + syncBlockID, shouldSync := s.progressTracker.ShouldSync(new(big.Int).SetUint64(verifyBlockID)) + if !shouldSync { + return nil } - if !s.progressTracker.HeadChanged(new(big.Int).SetUint64(blockID)) { - log.Debug("Verified head has not changed", "blockID", blockID, "hash", latestVerifiedHeadPayload.BlockHash) - return nil + latestVerifiedHeadPayload, err := s.getVerifiedBlockPayload(s.ctx, syncBlockID, verifyBlockID) + if err != nil { + return err } if s.progressTracker.Triggered() { @@ -54,7 +54,7 @@ func (s *Syncer) TriggerBeaconSync(blockID uint64) error { log.Info( "Syncing beacon headers, please check L2 execution engine logs for progress", "currentSyncHead", s.progressTracker.LastSyncedBlockID(), - "newBlockID", blockID, + "newBlockID", syncBlockID, ) } } @@ -80,12 +80,14 @@ func (s *Syncer) TriggerBeaconSync(blockID uint64) error { return fmt.Errorf("unexpected ForkchoiceUpdate response status: %s", fcRes.PayloadStatus.Status) } - // Update sync status. - s.progressTracker.UpdateMeta(new(big.Int).SetUint64(blockID), latestVerifiedHeadPayload.BlockHash) + // If the beacon sync is not in progress, update the sync progress. + if fcRes.PayloadStatus.Status != engine.SYNCING { + s.progressTracker.UpdateMeta(new(big.Int).SetUint64(syncBlockID), latestVerifiedHeadPayload.BlockHash) + } log.Info( "⛓️ Beacon sync triggered", - "newHeadID", blockID, + "newHeadID", syncBlockID, "newHeadHash", s.progressTracker.LastSyncedBlockHash(), ) @@ -94,14 +96,20 @@ func (s *Syncer) TriggerBeaconSync(blockID uint64) error { // getVerifiedBlockPayload fetches the latest verified block's header, and converts it to an Engine API executable data, // which will be used to let the node start beacon syncing. -func (s *Syncer) getVerifiedBlockPayload(ctx context.Context, blockID uint64) (*engine.ExecutableData, error) { - header, err := s.rpc.L2CheckPoint.HeaderByNumber(s.ctx, new(big.Int).SetUint64(blockID)) +func (s *Syncer) getVerifiedBlockPayload( + ctx context.Context, + syncBlockID, + verifyBlockID uint64, +) (*engine.ExecutableData, error) { + header, err := s.rpc.L2CheckPoint.HeaderByNumber(s.ctx, new(big.Int).SetUint64(syncBlockID)) if err != nil { return nil, err } - if s.syncMode == downloader.FullSync.String() { - blockInfo, err := s.rpc.GetL2BlockInfo(ctx, new(big.Int).SetUint64(blockID)) + // Check block hash if the sync mode is full sync + // and the latest verified block is the same as the block we are trying to sync. + if s.syncMode == downloader.FullSync.String() && verifyBlockID == syncBlockID { + blockInfo, err := s.rpc.GetL2BlockInfo(ctx, new(big.Int).SetUint64(syncBlockID)) if err != nil { return nil, err }