mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-20 11:46:44 +00:00
core: improve chain reset head
This commit is contained in:
parent
07dd8e052f
commit
135927b5c9
1 changed files with 35 additions and 19 deletions
|
|
@ -966,14 +966,11 @@ func (bc *BlockChain) rewindPathHead(head *types.Header, root common.Hash) (*typ
|
|||
return head, rootNumber
|
||||
}
|
||||
}
|
||||
// Recover if the target state if it's not available yet.
|
||||
if !bc.HasState(head.Root) {
|
||||
if err := bc.triedb.Recover(head.Root); err != nil {
|
||||
log.Error("Failed to rollback state, resetting to genesis", "err", err)
|
||||
return bc.genesisBlock.Header(), rootNumber
|
||||
}
|
||||
}
|
||||
log.Info("Rewound to block with state", "number", head.Number, "hash", head.Hash())
|
||||
// Note, the state of the located head may not be physically present yet if
|
||||
// it's only recoverable. The actual recovery is intentionally deferred once
|
||||
// the new head is finalized, so that a deep rewind rolls the state back in
|
||||
// one shot.
|
||||
log.Info("Rewound to block with available state", "number", head.Number, "hash", head.Hash())
|
||||
return head, rootNumber
|
||||
}
|
||||
|
||||
|
|
@ -1034,17 +1031,11 @@ func (bc *BlockChain) setHeadBeyondRoot(head uint64, time uint64, root common.Ha
|
|||
bc.currentBlock.Store(newHeadBlock)
|
||||
headBlockGauge.Update(int64(newHeadBlock.Number.Uint64()))
|
||||
|
||||
// The head state is missing, which is only possible in the path-based
|
||||
// scheme. This situation occurs when the chain head is rewound below
|
||||
// the pivot point. In this scenario, there is no possible recovery
|
||||
// approach except for rerunning a snap sync. Do nothing here until the
|
||||
// state syncer picks it up.
|
||||
if !bc.HasState(newHeadBlock.Root) {
|
||||
if newHeadBlock.Number.Uint64() != 0 {
|
||||
log.Crit("Chain is stateless at a non-genesis block")
|
||||
}
|
||||
log.Info("Chain is stateless, wait state sync", "number", newHeadBlock.Number, "hash", newHeadBlock.Hash())
|
||||
}
|
||||
// Note, the located head state might not be physically present yet; in
|
||||
// the path-based scheme a recoverable state is materialized in a single
|
||||
// shot once the rewind is finalized (see below). The stateless-head
|
||||
// handling is therefore deferred until then, also avoiding a per-block
|
||||
// recoverability check whose cost would grow as the rewind goes deeper.
|
||||
}
|
||||
// Rewind the snap block in a simpleton way to the target head
|
||||
if currentSnapBlock := bc.CurrentSnapBlock(); currentSnapBlock != nil && header.Number.Uint64() < currentSnapBlock.Number.Uint64() {
|
||||
|
|
@ -1113,6 +1104,31 @@ func (bc *BlockChain) setHeadBeyondRoot(head uint64, time uint64, root common.Ha
|
|||
bc.hc.SetHead(head, updateFn, delFn)
|
||||
}
|
||||
}
|
||||
// In the path-based scheme, the rewind loop above only locates the new head
|
||||
// without materializing its state, so the potentially deep rollback is done
|
||||
// here in a single shot. This rolls back the whole rewound range at once,
|
||||
// performing a single fsync rather than one per block, which is critical when
|
||||
// rewinding a large number of blocks.
|
||||
if newHeadBlock := bc.CurrentBlock(); !bc.HasState(newHeadBlock.Root) {
|
||||
switch {
|
||||
case bc.stateRecoverable(newHeadBlock.Root):
|
||||
if err := bc.triedb.Recover(newHeadBlock.Root); err != nil {
|
||||
// The state was confirmed recoverable just above, so a failure here
|
||||
// can only stem from an unexpected I/O error. There is no safe way to
|
||||
// continue with a half-rolled-back state, hence crash hard.
|
||||
log.Crit("Failed to recover state", "number", newHeadBlock.Number, "hash", newHeadBlock.Hash(), "err", err)
|
||||
}
|
||||
case newHeadBlock.Number.Uint64() != 0:
|
||||
// rewindHead only returns a non-genesis head when its state is present
|
||||
// or recoverable, so this branch should be unreachable.
|
||||
log.Crit("Chain is stateless at a non-genesis block", "number", newHeadBlock.Number, "hash", newHeadBlock.Hash())
|
||||
default:
|
||||
// The chain head was rewound below the snap-sync pivot to a stateless
|
||||
// genesis. There is no recovery approach except rerunning a snap sync;
|
||||
// do nothing here until the state syncer picks it up.
|
||||
log.Info("Chain is stateless, wait state sync", "number", newHeadBlock.Number, "hash", newHeadBlock.Hash())
|
||||
}
|
||||
}
|
||||
// Clear out any stale content from the caches
|
||||
bc.bodyCache.Purge()
|
||||
bc.bodyRLPCache.Purge()
|
||||
|
|
|
|||
Loading…
Reference in a new issue