Skip to content

Commit 658e67a

Browse files
Merge pull request #439 from OffchainLabs/fix-rewinding
flush batch during chain rewinding, make head rewind block limit configurable
2 parents 3083ee8 + 1800215 commit 658e67a

File tree

2 files changed

+28
-8
lines changed

2 files changed

+28
-8
lines changed

core/blockchain.go

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,9 @@ type CacheConfig struct {
157157
StateHistory uint64 // Number of blocks from head whose state histories are reserved.
158158
StateScheme string // Scheme used to store ethereum states and merkle tree nodes on top
159159

160+
// Arbitrum: configure head rewinding limits
160161
SnapshotRestoreMaxGas uint64 // Rollback up to this much gas to restore snapshot (otherwise snapshot recalculated from nothing)
162+
HeadRewindBlocksLimit uint64 // Rollback up to this many blocks to restore chain head (0 = preserve default upstream behaviour), only for HashScheme
161163

162164
// Arbitrum: configure GC window
163165
TriesInMemory uint64 // Height difference before which a trie may not be garbage-collected
@@ -202,6 +204,11 @@ func (c *CacheConfig) triedbConfig(isVerkle bool) *triedb.Config {
202204
var defaultCacheConfig = &CacheConfig{
203205

204206
// Arbitrum Config Options
207+
// note: some of the defaults are overwritten by nitro side config defaults
208+
209+
SnapshotRestoreMaxGas: 0,
210+
HeadRewindBlocksLimit: 0,
211+
205212
TriesInMemory: state.DefaultTriesInMemory,
206213
TrieRetention: 30 * time.Minute,
207214
TrieTimeLimitRandomOffset: 0,
@@ -691,7 +698,7 @@ func (bc *BlockChain) SetSafe(header *types.Header) {
691698
}
692699

693700
// rewindHashHead implements the logic of rewindHead in the context of hash scheme.
694-
func (bc *BlockChain) rewindHashHead(head *types.Header, root common.Hash, rewindLimit uint64) (*types.Header, uint64, bool) {
701+
func (bc *BlockChain) rewindHashHead(head *types.Header, root common.Hash, rewindGasLimit uint64) (*types.Header, uint64, bool) {
695702
var (
696703
limit uint64 // The oldest block that will be searched for this rewinding
697704
rootFound = root == common.Hash{} // Flag whether we're beyond the requested root (no root, always true)
@@ -718,6 +725,12 @@ func (bc *BlockChain) rewindHashHead(head *types.Header, root common.Hash, rewin
718725
} else if head.Number.Uint64() > params.FullImmutabilityThreshold {
719726
limit = head.Number.Uint64() - params.FullImmutabilityThreshold
720727
}
728+
729+
// arbitrum: overwrite the oldest block limit if pivot block is not available and HeadRewindBlocksLimit is configured
730+
if pivot == nil && bc.cacheConfig.HeadRewindBlocksLimit > 0 && head.Number.Uint64() > bc.cacheConfig.HeadRewindBlocksLimit {
731+
limit = head.Number.Uint64() - bc.cacheConfig.HeadRewindBlocksLimit
732+
}
733+
721734
lastFullBlock := uint64(0)
722735
lastFullBlockHash := common.Hash{}
723736
gasRolledBack := uint64(0)
@@ -729,7 +742,7 @@ func (bc *BlockChain) rewindHashHead(head *types.Header, root common.Hash, rewin
729742
}
730743
logger("Block state missing, rewinding further", "number", head.Number, "hash", head.Hash(), "elapsed", common.PrettyDuration(time.Since(start)))
731744

732-
if rewindLimit > 0 && lastFullBlock != 0 {
745+
if rewindGasLimit > 0 && lastFullBlock != 0 {
733746
// Arbitrum: track the amount of gas rolled back and stop the rollback early if necessary
734747
gasUsedInBlock := head.GasUsed
735748
if bc.chainConfig.IsArbitrum() {
@@ -739,7 +752,7 @@ func (bc *BlockChain) rewindHashHead(head *types.Header, root common.Hash, rewin
739752
}
740753
}
741754
gasRolledBack += gasUsedInBlock
742-
if gasRolledBack >= rewindLimit {
755+
if gasRolledBack >= rewindGasLimit {
743756
rootNumber = lastFullBlock
744757
head = bc.GetHeader(lastFullBlockHash, lastFullBlock)
745758
log.Debug("Rewound to block with state but not snapshot", "number", head.Number.Uint64(), "hash", head.Hash())
@@ -873,17 +886,17 @@ func (bc *BlockChain) rewindPathHead(head *types.Header, root common.Hash) (*typ
873886
// representing the state corresponding to snapshot disk layer, is deemed impassable,
874887
// then block number zero is returned, indicating that snapshot recovery is disabled
875888
// and the whole snapshot should be auto-generated in case of head mismatch.
876-
func (bc *BlockChain) rewindHead(head *types.Header, root common.Hash, rewindLimit uint64) (*types.Header, uint64, bool) {
889+
func (bc *BlockChain) rewindHead(head *types.Header, root common.Hash, rewindGasLimit uint64) (*types.Header, uint64, bool) {
877890
if bc.triedb.Scheme() == rawdb.PathScheme {
878891
newHead, rootNumber := bc.rewindPathHead(head, root)
879892
return newHead, rootNumber, head.Number.Uint64() != 0
880893
}
881-
return bc.rewindHashHead(head, root, rewindLimit)
894+
return bc.rewindHashHead(head, root, rewindGasLimit)
882895
}
883896

884897
// setHeadBeyondRoot rewinds the local chain to a new head with the extra condition
885898
// that the rewind must pass the specified state root. The extra condition is
886-
// ignored if it causes rolling back more than rewindLimit Gas (0 meaning infinte).
899+
// ignored if it causes rolling back more than rewindGasLimit Gas (0 meaning infinte).
887900
// If the limit was hit, rewind to last block with state. This method is meant to be
888901
// used when rewinding with snapshots enabled to ensure that we go back further than
889902
// persistent disk layer. Depending on whether the node was snap synced or full, and
@@ -895,7 +908,7 @@ func (bc *BlockChain) rewindHead(head *types.Header, root common.Hash, rewindLim
895908
// requested time. If both `head` and `time` is 0, the chain is rewound to genesis.
896909
//
897910
// The method returns the block number where the requested root cap was found.
898-
func (bc *BlockChain) setHeadBeyondRoot(head uint64, time uint64, root common.Hash, repair bool, rewindLimit uint64) (uint64, bool, error) {
911+
func (bc *BlockChain) setHeadBeyondRoot(head uint64, time uint64, root common.Hash, repair bool, rewindGasLimit uint64) (uint64, bool, error) {
899912
if !bc.chainmu.TryLock() {
900913
return 0, false, errChainStopped
901914
}
@@ -915,7 +928,7 @@ func (bc *BlockChain) setHeadBeyondRoot(head uint64, time uint64, root common.Ha
915928
// chain reparation mechanism without deleting any data!
916929
if currentBlock := bc.CurrentBlock(); currentBlock != nil && header.Number.Uint64() <= currentBlock.Number.Uint64() {
917930
var newHeadBlock *types.Header
918-
newHeadBlock, blockNumber, rootFound = bc.rewindHead(header, root, rewindLimit)
931+
newHeadBlock, blockNumber, rootFound = bc.rewindHead(header, root, rewindGasLimit)
919932
rawdb.WriteHeadBlockHash(db, newHeadBlock.Hash())
920933

921934
// Degrade the chain markers if they are explicitly reverted.

core/headerchain.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -595,6 +595,13 @@ func (hc *HeaderChain) setHead(headBlock uint64, headTime uint64, updateFn Updat
595595
rawdb.DeleteHeader(batch, hash, num)
596596
}
597597
rawdb.DeleteCanonicalHash(batch, num)
598+
599+
// flush after each deleted header and its side forks
600+
// on the first iteration (when origin==true) len(nums) can be considerable
601+
if batch.ValueSize() >= ethdb.IdealBatchSize {
602+
batch.Write()
603+
batch.Reset()
604+
}
598605
}
599606
}
600607
// Flush all accumulated deletions.

0 commit comments

Comments
 (0)