Skip to content

Commit addac58

Browse files
committed
Merge upstream commit ethereum#28124
eth/downloader: fix genesis state missing due to state sync (ethereum#28124) Conflicts: core/blockchain.go These conflicts were dut to our changes in setHeadBeyondRoot. In the function call upstream only indented the code, but tested Upstream also added to the file an assumption that genesis is block 0, which we removed.
2 parents 9f6dbf5 + c53b0fe commit addac58

File tree

5 files changed

+69
-49
lines changed

5 files changed

+69
-49
lines changed

core/blockchain.go

Lines changed: 57 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -379,31 +379,41 @@ func NewBlockChain(db ethdb.Database, cacheConfig *CacheConfig, chainConfig *par
379379
// Make sure the state associated with the block is available
380380
head := bc.CurrentBlock()
381381
if !bc.HasState(head.Root) {
382-
// Head state is missing, before the state recovery, find out the
383-
// disk layer point of snapshot(if it's enabled). Make sure the
384-
// rewound point is lower than disk layer.
385-
var diskRoot common.Hash
386-
if bc.cacheConfig.SnapshotLimit > 0 {
387-
diskRoot = rawdb.ReadSnapshotRoot(bc.db)
388-
}
389-
if diskRoot != (common.Hash{}) {
390-
log.Warn("Head state missing, repairing", "number", head.Number, "hash", head.Hash(), "snaproot", diskRoot)
391-
392-
snapDisk, diskRootFound, err := bc.setHeadBeyondRoot(head.Number.Uint64(), 0, diskRoot, true, bc.cacheConfig.SnapshotRestoreMaxGas)
393-
if err != nil {
394-
return nil, err
382+
if head.Number.Uint64() <= bc.genesisBlock.NumberU64() {
383+
// The genesis state is missing, which is only possible in the path-based
384+
// scheme. This situation occurs when the state syncer overwrites it.
385+
//
386+
// The solution is to reset the state to the genesis state. Although it may not
387+
// match the sync target, the state healer will later address and correct any
388+
// inconsistencies.
389+
bc.resetState()
390+
} else {
391+
// Head state is missing, before the state recovery, find out the
392+
// disk layer point of snapshot(if it's enabled). Make sure the
393+
// rewound point is lower than disk layer.
394+
var diskRoot common.Hash
395+
if bc.cacheConfig.SnapshotLimit > 0 {
396+
diskRoot = rawdb.ReadSnapshotRoot(bc.db)
395397
}
396-
// Chain rewound, persist old snapshot number to indicate recovery procedure
397-
if diskRootFound {
398-
rawdb.WriteSnapshotRecoveryNumber(bc.db, snapDisk)
398+
if diskRoot != (common.Hash{}) {
399+
log.Warn("Head state missing, repairing", "number", head.Number, "hash", head.Hash(), "snaproot", diskRoot)
400+
401+
snapDisk, diskRootFound, err := bc.setHeadBeyondRoot(head.Number.Uint64(), 0, diskRoot, true, bc.cacheConfig.SnapshotRestoreMaxGas)
402+
if err != nil {
403+
return nil, err
404+
}
405+
// Chain rewound, persist old snapshot number to indicate recovery procedure
406+
if diskRootFound {
407+
rawdb.WriteSnapshotRecoveryNumber(bc.db, snapDisk)
408+
} else {
409+
log.Warn("Snapshot root not found or too far back. Recreating snapshot from scratch.")
410+
rawdb.DeleteSnapshotRecoveryNumber(bc.db)
411+
}
399412
} else {
400-
log.Warn("Snapshot root not found or too far back. Recreating snapshot from scratch.")
401-
rawdb.DeleteSnapshotRecoveryNumber(bc.db)
402-
}
403-
} else {
404-
log.Warn("Head state missing, repairing", "number", head.Number, "hash", head.Hash())
405-
if _, _, err := bc.setHeadBeyondRoot(head.Number.Uint64(), 0, common.Hash{}, true, 0); err != nil {
406-
return nil, err
413+
log.Warn("Head state missing, repairing", "number", head.Number, "hash", head.Hash())
414+
if _, _, err := bc.setHeadBeyondRoot(head.Number.Uint64(), 0, common.Hash{}, true, 0); err != nil {
415+
return nil, err
416+
}
407417
}
408418
}
409419
}
@@ -662,6 +672,28 @@ func (bc *BlockChain) SetSafe(header *types.Header) {
662672
}
663673
}
664674

675+
// resetState resets the persistent state to genesis state if it's not present.
676+
func (bc *BlockChain) resetState() {
677+
// Short circuit if the genesis state is already present.
678+
root := bc.genesisBlock.Root()
679+
if bc.HasState(root) {
680+
return
681+
}
682+
// Reset the state database to empty for committing genesis state.
683+
// Note, it should only happen in path-based scheme and Reset function
684+
// is also only call-able in this mode.
685+
if bc.triedb.Scheme() == rawdb.PathScheme {
686+
if err := bc.triedb.Reset(types.EmptyRootHash); err != nil {
687+
log.Crit("Failed to clean state", "err", err) // Shouldn't happen
688+
}
689+
}
690+
// Write genesis state into database.
691+
if err := CommitGenesisState(bc.db, bc.triedb, bc.genesisBlock.Hash()); err != nil {
692+
log.Crit("Failed to commit genesis state", "err", err)
693+
}
694+
log.Info("Reset state to genesis", "root", root)
695+
}
696+
665697
// setHeadBeyondRoot rewinds the local chain to a new head with the extra condition
666698
// that the rewind must pass the specified state root. The extra condition is
667699
// ignored if it causes rolling back more than rewindLimit Gas (0 meaning infinte).
@@ -691,25 +723,6 @@ func (bc *BlockChain) setHeadBeyondRoot(head uint64, time uint64, root common.Ha
691723
pivot := rawdb.ReadLastPivotNumber(bc.db)
692724
frozen, _ := bc.db.Ancients()
693725

694-
// resetState resets the persistent state to genesis if it's not available.
695-
resetState := func() {
696-
// Short circuit if the genesis state is already present.
697-
if bc.HasState(bc.genesisBlock.Root()) {
698-
return
699-
}
700-
// Reset the state database to empty for committing genesis state.
701-
// Note, it should only happen in path-based scheme and Reset function
702-
// is also only call-able in this mode.
703-
if bc.triedb.Scheme() == rawdb.PathScheme {
704-
if err := bc.triedb.Reset(types.EmptyRootHash); err != nil {
705-
log.Crit("Failed to clean state", "err", err) // Shouldn't happen
706-
}
707-
}
708-
// Write genesis state into database.
709-
if err := CommitGenesisState(bc.db, bc.triedb, bc.genesisBlock.Hash()); err != nil {
710-
log.Crit("Failed to commit genesis state", "err", err)
711-
}
712-
}
713726
updateFn := func(db ethdb.KeyValueWriter, header *types.Header) (*types.Header, bool) {
714727
// Rewind the blockchain, ensuring we don't end up with a stateless head
715728
// block. Note, depth equality is permitted to allow using SetHead as a
@@ -719,7 +732,7 @@ func (bc *BlockChain) setHeadBeyondRoot(head uint64, time uint64, root common.Ha
719732
if newHeadBlock == nil {
720733
log.Error("Gap in the chain, rewinding to genesis", "number", header.Number, "hash", header.Hash())
721734
newHeadBlock = bc.genesisBlock
722-
resetState()
735+
bc.resetState()
723736
} else {
724737
// Block exists, keep rewinding until we find one with state,
725738
// keeping rewinding until we exceed the optional threshold
@@ -772,7 +785,7 @@ func (bc *BlockChain) setHeadBeyondRoot(head uint64, time uint64, root common.Ha
772785
}
773786
if rootFound || newHeadBlock.NumberU64() <= bc.genesisBlock.NumberU64() {
774787
if newHeadBlock.NumberU64() <= bc.genesisBlock.NumberU64() {
775-
resetState()
788+
bc.resetState()
776789
} else if !bc.HasState(newHeadBlock.Root()) {
777790
// Rewind to a block with recoverable state. If the state is
778791
// missing, run the state recovery here.

eth/downloader/downloader.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -398,7 +398,14 @@ func (d *Downloader) synchronise(id string, hash common.Hash, td, ttd *big.Int,
398398
log.Info("Block synchronisation started")
399399
}
400400
if mode == SnapSync {
401-
// Snap sync uses the snapshot namespace to store potentially flakey data until
401+
// Snap sync will directly modify the persistent state, making the entire
402+
// trie database unusable until the state is fully synced. To prevent any
403+
// subsequent state reads, explicitly disable the trie database and state
404+
// syncer is responsible to address and correct any state missing.
405+
if d.blockchain.TrieDB().Scheme() == rawdb.PathScheme {
406+
d.blockchain.TrieDB().Reset(types.EmptyRootHash)
407+
}
408+
// Snap sync uses the snapshot namespace to store potentially flaky data until
402409
// sync completely heals and finishes. Pause snapshot maintenance in the mean-
403410
// time to prevent access.
404411
if snapshots := d.blockchain.Snapshots(); snapshots != nil { // Only nil in tests

internal/ethapi/api.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1706,8 +1706,8 @@ func newRPCTransaction(tx *types.Transaction, blockHash common.Hash, blockNumber
17061706
func effectiveGasPrice(tx *types.Transaction, baseFee *big.Int) *big.Int {
17071707
fee := tx.GasTipCap()
17081708
fee = fee.Add(fee, baseFee)
1709-
if tx.GasTipCapIntCmp(fee) < 0 {
1710-
return tx.GasTipCap()
1709+
if tx.GasFeeCapIntCmp(fee) < 0 {
1710+
return tx.GasFeeCap()
17111711
}
17121712
return fee
17131713
}

internal/flags/helpers.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,7 @@ func wordWrap(s string, width int) string {
225225
return output.String()
226226
}
227227

228-
// AutoEnvVars extens all the specific CLI flags with automatically generated
228+
// AutoEnvVars extends all the specific CLI flags with automatically generated
229229
// env vars by capitalizing the flag, replacing . with _ and prefixing it with
230230
// the specified string.
231231
//

params/config.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -364,7 +364,7 @@ func (c *CliqueConfig) String() string {
364364
func (c *ChainConfig) Description() string {
365365
var banner string
366366

367-
// Create some basinc network config output
367+
// Create some basic network config output
368368
network := NetworkNames[c.ChainID.String()]
369369
if network == "" {
370370
network = "unknown"

0 commit comments

Comments
 (0)