mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-06-08 07:58:40 +00:00
core/rawdb, eth/downloader: persist partial-sync completion across restarts
d.partialSyncComplete is consulted by beaconBackfiller.resume() to skip redundant downloader cycles after the initial partial-state sync has finished. It was an in-memory atomic.Bool, so every process restart reset it to false, and the next forkchoiceUpdated from the CL would re-enter the sync loop. Persist the flag in leveldb via a new PartialSyncComplete marker: - Add ReadPartialSyncComplete / WritePartialSyncComplete / DeletePartialSyncComplete accessors in core/rawdb/accessors_chain.go backed by a single-byte value under the PartialSyncComplete key. - Write the marker in the downloader right after AdvancePartialHead succeeds (same spot we flip the in-memory flag). - Rehydrate the in-memory flag from leveldb in Downloader.New() so a freshly-started process with a completed partial-state sync keeps the resume short-circuit active from the first beacon forkchoice. Without this, the restart invariant relied on HasState(header.Root) accidentally returning false to reroute the downloader back to SnapSync; with this the resume guard is the primary protection regardless of how header-root convergence evolves.
This commit is contained in:
parent
e131e7708b
commit
e0c5cff4df
3 changed files with 42 additions and 0 deletions
|
|
@ -200,6 +200,32 @@ func WriteLastPivotNumber(db ethdb.KeyValueWriter, pivot uint64) {
|
|||
}
|
||||
}
|
||||
|
||||
// ReadPartialSyncComplete reports whether the partial-state initial sync
|
||||
// completed successfully on this datadir. Returns false if the flag is
|
||||
// unset or absent (fresh database, non-partial-state node, or sync in
|
||||
// progress).
|
||||
func ReadPartialSyncComplete(db ethdb.KeyValueReader) bool {
|
||||
data, _ := db.Get(partialSyncCompleteKey)
|
||||
return len(data) > 0 && data[0] == 1
|
||||
}
|
||||
|
||||
// WritePartialSyncComplete marks the partial-state initial sync as finished.
|
||||
// The downloader uses this on restart to skip redundant sync cycles.
|
||||
func WritePartialSyncComplete(db ethdb.KeyValueWriter) {
|
||||
if err := db.Put(partialSyncCompleteKey, []byte{1}); err != nil {
|
||||
log.Crit("Failed to store partial-sync-complete flag", "err", err)
|
||||
}
|
||||
}
|
||||
|
||||
// DeletePartialSyncComplete clears the partial-state sync completion flag.
|
||||
// Used when the node is reset to genesis or rewound behind the pivot so a
|
||||
// fresh partial sync can run.
|
||||
func DeletePartialSyncComplete(db ethdb.KeyValueWriter) {
|
||||
if err := db.Delete(partialSyncCompleteKey); err != nil {
|
||||
log.Crit("Failed to delete partial-sync-complete flag", "err", err)
|
||||
}
|
||||
}
|
||||
|
||||
// ReadTxIndexTail retrieves the number of oldest indexed block
|
||||
// whose transaction indices has been indexed.
|
||||
func ReadTxIndexTail(db ethdb.KeyValueReader) *uint64 {
|
||||
|
|
|
|||
|
|
@ -104,6 +104,12 @@ var (
|
|||
// snapSyncStatusFlagKey flags that status of snap sync.
|
||||
snapSyncStatusFlagKey = []byte("SnapSyncStatus")
|
||||
|
||||
// partialSyncCompleteKey flags that the partial-state initial sync
|
||||
// (snap sync + second state sync to HEAD + AdvancePartialHead) has
|
||||
// finished successfully on this datadir. Consumed by the downloader
|
||||
// so beaconBackfiller.resume() keeps short-circuiting across restarts.
|
||||
partialSyncCompleteKey = []byte("PartialSyncComplete")
|
||||
|
||||
// Data item prefixes (use single byte to avoid mixing data types, avoid `i`, used for indexes).
|
||||
headerPrefix = []byte("h") // headerPrefix + num (uint64 big endian) + hash -> header
|
||||
headerTDSuffix = []byte("t") // headerPrefix + num (uint64 big endian) + hash + headerTDSuffix -> td (deprecated)
|
||||
|
|
|
|||
|
|
@ -268,6 +268,13 @@ func New(stateDb ethdb.Database, mode ethconfig.SyncMode, mux *event.TypeMux, ch
|
|||
stateSyncStart: make(chan *stateSync),
|
||||
syncStartBlock: chain.CurrentSnapBlock().Number.Uint64(),
|
||||
}
|
||||
// Rehydrate the partial-state completion flag across restarts. Without
|
||||
// this, a freshly-started process would re-enter the downloader loop for
|
||||
// every beacon forkchoice update, defeating beaconBackfiller.resume()'s
|
||||
// short-circuit.
|
||||
if partialFilter != nil && rawdb.ReadPartialSyncComplete(stateDb) {
|
||||
dl.partialSyncComplete.Store(true)
|
||||
}
|
||||
// Create the post-merge skeleton syncer and start the process
|
||||
dl.skeleton = newSkeleton(stateDb, dl.peers, dropPeer, newBeaconBackfiller(dl, success), chain)
|
||||
|
||||
|
|
@ -1027,6 +1034,9 @@ func (d *Downloader) processSnapSyncContent() error {
|
|||
return err
|
||||
}
|
||||
d.partialSyncComplete.Store(true)
|
||||
// Persist the completion flag so a restart does not
|
||||
// re-run the sync cycle on every beacon forkchoice.
|
||||
rawdb.WritePartialSyncComplete(d.stateDB)
|
||||
log.Info("Partial state initial sync complete")
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue