core, core/state: move TriesInMemory to state package (#29701)

pull/29714/head
Guillaume Ballet 6 months ago committed by GitHub
parent a09a610384
commit 43cbcd78ea
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 17
      core/blockchain.go
  2. 36
      core/blockchain_test.go
  3. 9
      core/state/statedb.go

@ -100,7 +100,6 @@ const (
blockCacheLimit = 256 blockCacheLimit = 256
receiptsCacheLimit = 32 receiptsCacheLimit = 32
txLookupCacheLimit = 1024 txLookupCacheLimit = 1024
TriesInMemory = 128
// BlockChainVersion ensures that an incompatible database forces a resync from scratch. // BlockChainVersion ensures that an incompatible database forces a resync from scratch.
// //
@ -1128,7 +1127,7 @@ func (bc *BlockChain) Stop() {
if !bc.cacheConfig.TrieDirtyDisabled { if !bc.cacheConfig.TrieDirtyDisabled {
triedb := bc.triedb triedb := bc.triedb
for _, offset := range []uint64{0, 1, TriesInMemory - 1} { for _, offset := range []uint64{0, 1, state.TriesInMemory - 1} {
if number := bc.CurrentBlock().Number.Uint64(); number > offset { if number := bc.CurrentBlock().Number.Uint64(); number > offset {
recent := bc.GetBlockByNumber(number - offset) recent := bc.GetBlockByNumber(number - offset)
@ -1452,7 +1451,7 @@ func (bc *BlockChain) writeKnownBlock(block *types.Block) error {
// writeBlockWithState writes block, metadata and corresponding state data to the // writeBlockWithState writes block, metadata and corresponding state data to the
// database. // database.
func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types.Receipt, state *state.StateDB) error { func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types.Receipt, statedb *state.StateDB) error {
// Calculate the total difficulty of the block // Calculate the total difficulty of the block
ptd := bc.GetTd(block.ParentHash(), block.NumberU64()-1) ptd := bc.GetTd(block.ParentHash(), block.NumberU64()-1)
if ptd == nil { if ptd == nil {
@ -1469,12 +1468,12 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types.
rawdb.WriteTd(blockBatch, block.Hash(), block.NumberU64(), externTd) rawdb.WriteTd(blockBatch, block.Hash(), block.NumberU64(), externTd)
rawdb.WriteBlock(blockBatch, block) rawdb.WriteBlock(blockBatch, block)
rawdb.WriteReceipts(blockBatch, block.Hash(), block.NumberU64(), receipts) rawdb.WriteReceipts(blockBatch, block.Hash(), block.NumberU64(), receipts)
rawdb.WritePreimages(blockBatch, state.Preimages()) rawdb.WritePreimages(blockBatch, statedb.Preimages())
if err := blockBatch.Write(); err != nil { if err := blockBatch.Write(); err != nil {
log.Crit("Failed to write block into disk", "err", err) log.Crit("Failed to write block into disk", "err", err)
} }
// Commit all cached state changes into underlying memory database. // Commit all cached state changes into underlying memory database.
root, err := state.Commit(block.NumberU64(), bc.chainConfig.IsEIP158(block.Number())) root, err := statedb.Commit(block.NumberU64(), bc.chainConfig.IsEIP158(block.Number()))
if err != nil { if err != nil {
return err return err
} }
@ -1493,7 +1492,7 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types.
// Flush limits are not considered for the first TriesInMemory blocks. // Flush limits are not considered for the first TriesInMemory blocks.
current := block.NumberU64() current := block.NumberU64()
if current <= TriesInMemory { if current <= state.TriesInMemory {
return nil return nil
} }
// If we exceeded our memory allowance, flush matured singleton nodes to disk // If we exceeded our memory allowance, flush matured singleton nodes to disk
@ -1505,7 +1504,7 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types.
bc.triedb.Cap(limit - ethdb.IdealBatchSize) bc.triedb.Cap(limit - ethdb.IdealBatchSize)
} }
// Find the next state trie we need to commit // Find the next state trie we need to commit
chosen := current - TriesInMemory chosen := current - state.TriesInMemory
flushInterval := time.Duration(bc.flushInterval.Load()) flushInterval := time.Duration(bc.flushInterval.Load())
// If we exceeded time allowance, flush an entire trie to disk // If we exceeded time allowance, flush an entire trie to disk
if bc.gcproc > flushInterval { if bc.gcproc > flushInterval {
@ -1517,8 +1516,8 @@ func (bc *BlockChain) writeBlockWithState(block *types.Block, receipts []*types.
} else { } else {
// If we're exceeding limits but haven't reached a large enough memory gap, // If we're exceeding limits but haven't reached a large enough memory gap,
// warn the user that the system is becoming unstable. // warn the user that the system is becoming unstable.
if chosen < bc.lastWrite+TriesInMemory && bc.gcproc >= 2*flushInterval { if chosen < bc.lastWrite+state.TriesInMemory && bc.gcproc >= 2*flushInterval {
log.Info("State in memory for too long, committing", "time", bc.gcproc, "allowance", flushInterval, "optimum", float64(chosen-bc.lastWrite)/TriesInMemory) log.Info("State in memory for too long, committing", "time", bc.gcproc, "allowance", flushInterval, "optimum", float64(chosen-bc.lastWrite)/state.TriesInMemory)
} }
// Flush an entire trie and restart the counters // Flush an entire trie and restart the counters
bc.triedb.Commit(header.Root, true) bc.triedb.Commit(header.Root, true)

@ -1712,7 +1712,7 @@ func TestTrieForkGC(t *testing.T) {
Config: params.TestChainConfig, Config: params.TestChainConfig,
BaseFee: big.NewInt(params.InitialBaseFee), BaseFee: big.NewInt(params.InitialBaseFee),
} }
genDb, blocks, _ := GenerateChainWithGenesis(genesis, engine, 2*TriesInMemory, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{1}) }) genDb, blocks, _ := GenerateChainWithGenesis(genesis, engine, 2*state.TriesInMemory, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{1}) })
// Generate a bunch of fork blocks, each side forking from the canonical chain // Generate a bunch of fork blocks, each side forking from the canonical chain
forks := make([]*types.Block, len(blocks)) forks := make([]*types.Block, len(blocks))
@ -1740,7 +1740,7 @@ func TestTrieForkGC(t *testing.T) {
} }
} }
// Dereference all the recent tries and ensure no past trie is left in // Dereference all the recent tries and ensure no past trie is left in
for i := 0; i < TriesInMemory; i++ { for i := 0; i < state.TriesInMemory; i++ {
chain.TrieDB().Dereference(blocks[len(blocks)-1-i].Root()) chain.TrieDB().Dereference(blocks[len(blocks)-1-i].Root())
chain.TrieDB().Dereference(forks[len(blocks)-1-i].Root()) chain.TrieDB().Dereference(forks[len(blocks)-1-i].Root())
} }
@ -1764,8 +1764,8 @@ func testLargeReorgTrieGC(t *testing.T, scheme string) {
BaseFee: big.NewInt(params.InitialBaseFee), BaseFee: big.NewInt(params.InitialBaseFee),
} }
genDb, shared, _ := GenerateChainWithGenesis(genesis, engine, 64, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{1}) }) genDb, shared, _ := GenerateChainWithGenesis(genesis, engine, 64, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{1}) })
original, _ := GenerateChain(genesis.Config, shared[len(shared)-1], engine, genDb, 2*TriesInMemory, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{2}) }) original, _ := GenerateChain(genesis.Config, shared[len(shared)-1], engine, genDb, 2*state.TriesInMemory, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{2}) })
competitor, _ := GenerateChain(genesis.Config, shared[len(shared)-1], engine, genDb, 2*TriesInMemory+1, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{3}) }) competitor, _ := GenerateChain(genesis.Config, shared[len(shared)-1], engine, genDb, 2*state.TriesInMemory+1, func(i int, b *BlockGen) { b.SetCoinbase(common.Address{3}) })
// Import the shared chain and the original canonical one // Import the shared chain and the original canonical one
db, _ := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), t.TempDir(), "", false) db, _ := rawdb.NewDatabaseWithFreezer(rawdb.NewMemoryDatabase(), t.TempDir(), "", false)
@ -1804,7 +1804,7 @@ func testLargeReorgTrieGC(t *testing.T, scheme string) {
} }
// In path-based trie database implementation, it will keep 128 diff + 1 disk // In path-based trie database implementation, it will keep 128 diff + 1 disk
// layers, totally 129 latest states available. In hash-based it's 128. // layers, totally 129 latest states available. In hash-based it's 128.
states := TriesInMemory states := state.TriesInMemory
if scheme == rawdb.PathScheme { if scheme == rawdb.PathScheme {
states = states + 1 states = states + 1
} }
@ -1972,7 +1972,7 @@ func testLowDiffLongChain(t *testing.T, scheme string) {
} }
// We must use a pretty long chain to ensure that the fork doesn't overtake us // We must use a pretty long chain to ensure that the fork doesn't overtake us
// until after at least 128 blocks post tip // until after at least 128 blocks post tip
genDb, blocks, _ := GenerateChainWithGenesis(genesis, engine, 6*TriesInMemory, func(i int, b *BlockGen) { genDb, blocks, _ := GenerateChainWithGenesis(genesis, engine, 6*state.TriesInMemory, func(i int, b *BlockGen) {
b.SetCoinbase(common.Address{1}) b.SetCoinbase(common.Address{1})
b.OffsetTime(-9) b.OffsetTime(-9)
}) })
@ -1992,7 +1992,7 @@ func testLowDiffLongChain(t *testing.T, scheme string) {
} }
// Generate fork chain, starting from an early block // Generate fork chain, starting from an early block
parent := blocks[10] parent := blocks[10]
fork, _ := GenerateChain(genesis.Config, parent, engine, genDb, 8*TriesInMemory, func(i int, b *BlockGen) { fork, _ := GenerateChain(genesis.Config, parent, engine, genDb, 8*state.TriesInMemory, func(i int, b *BlockGen) {
b.SetCoinbase(common.Address{2}) b.SetCoinbase(common.Address{2})
}) })
@ -2055,7 +2055,7 @@ func testSideImport(t *testing.T, numCanonBlocksInSidechain, blocksBetweenCommon
// Set the terminal total difficulty in the config // Set the terminal total difficulty in the config
gspec.Config.TerminalTotalDifficulty = big.NewInt(0) gspec.Config.TerminalTotalDifficulty = big.NewInt(0)
} }
genDb, blocks, _ := GenerateChainWithGenesis(gspec, engine, 2*TriesInMemory, func(i int, gen *BlockGen) { genDb, blocks, _ := GenerateChainWithGenesis(gspec, engine, 2*state.TriesInMemory, func(i int, gen *BlockGen) {
tx, err := types.SignTx(types.NewTransaction(nonce, common.HexToAddress("deadbeef"), big.NewInt(100), 21000, big.NewInt(int64(i+1)*params.GWei), nil), signer, key) tx, err := types.SignTx(types.NewTransaction(nonce, common.HexToAddress("deadbeef"), big.NewInt(100), 21000, big.NewInt(int64(i+1)*params.GWei), nil), signer, key)
if err != nil { if err != nil {
t.Fatalf("failed to create tx: %v", err) t.Fatalf("failed to create tx: %v", err)
@ -2070,9 +2070,9 @@ func testSideImport(t *testing.T, numCanonBlocksInSidechain, blocksBetweenCommon
t.Fatalf("block %d: failed to insert into chain: %v", n, err) t.Fatalf("block %d: failed to insert into chain: %v", n, err)
} }
lastPrunedIndex := len(blocks) - TriesInMemory - 1 lastPrunedIndex := len(blocks) - state.TriesInMemory - 1
lastPrunedBlock := blocks[lastPrunedIndex] lastPrunedBlock := blocks[lastPrunedIndex]
firstNonPrunedBlock := blocks[len(blocks)-TriesInMemory] firstNonPrunedBlock := blocks[len(blocks)-state.TriesInMemory]
// Verify pruning of lastPrunedBlock // Verify pruning of lastPrunedBlock
if chain.HasBlockAndState(lastPrunedBlock.Hash(), lastPrunedBlock.NumberU64()) { if chain.HasBlockAndState(lastPrunedBlock.Hash(), lastPrunedBlock.NumberU64()) {
@ -2099,7 +2099,7 @@ func testSideImport(t *testing.T, numCanonBlocksInSidechain, blocksBetweenCommon
// Generate fork chain, make it longer than canon // Generate fork chain, make it longer than canon
parentIndex := lastPrunedIndex + blocksBetweenCommonAncestorAndPruneblock parentIndex := lastPrunedIndex + blocksBetweenCommonAncestorAndPruneblock
parent := blocks[parentIndex] parent := blocks[parentIndex]
fork, _ := GenerateChain(gspec.Config, parent, engine, genDb, 2*TriesInMemory, func(i int, b *BlockGen) { fork, _ := GenerateChain(gspec.Config, parent, engine, genDb, 2*state.TriesInMemory, func(i int, b *BlockGen) {
b.SetCoinbase(common.Address{2}) b.SetCoinbase(common.Address{2})
if int(b.header.Number.Uint64()) >= mergeBlock { if int(b.header.Number.Uint64()) >= mergeBlock {
b.SetPoS() b.SetPoS()
@ -2742,7 +2742,7 @@ func testSideImportPrunedBlocks(t *testing.T, scheme string) {
BaseFee: big.NewInt(params.InitialBaseFee), BaseFee: big.NewInt(params.InitialBaseFee),
} }
// Generate and import the canonical chain // Generate and import the canonical chain
_, blocks, _ := GenerateChainWithGenesis(genesis, engine, 2*TriesInMemory, nil) _, blocks, _ := GenerateChainWithGenesis(genesis, engine, 2*state.TriesInMemory, nil)
chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), genesis, nil, engine, vm.Config{}, nil, nil) chain, err := NewBlockChain(rawdb.NewMemoryDatabase(), DefaultCacheConfigWithScheme(scheme), genesis, nil, engine, vm.Config{}, nil, nil)
if err != nil { if err != nil {
@ -2755,9 +2755,9 @@ func testSideImportPrunedBlocks(t *testing.T, scheme string) {
} }
// In path-based trie database implementation, it will keep 128 diff + 1 disk // In path-based trie database implementation, it will keep 128 diff + 1 disk
// layers, totally 129 latest states available. In hash-based it's 128. // layers, totally 129 latest states available. In hash-based it's 128.
states := TriesInMemory states := state.TriesInMemory
if scheme == rawdb.PathScheme { if scheme == rawdb.PathScheme {
states = TriesInMemory + 1 states = state.TriesInMemory + 1
} }
lastPrunedIndex := len(blocks) - states - 1 lastPrunedIndex := len(blocks) - states - 1
lastPrunedBlock := blocks[lastPrunedIndex] lastPrunedBlock := blocks[lastPrunedIndex]
@ -3638,7 +3638,7 @@ func testSetCanonical(t *testing.T, scheme string) {
engine = ethash.NewFaker() engine = ethash.NewFaker()
) )
// Generate and import the canonical chain // Generate and import the canonical chain
_, canon, _ := GenerateChainWithGenesis(gspec, engine, 2*TriesInMemory, func(i int, gen *BlockGen) { _, canon, _ := GenerateChainWithGenesis(gspec, engine, 2*state.TriesInMemory, func(i int, gen *BlockGen) {
tx, err := types.SignTx(types.NewTransaction(gen.TxNonce(address), common.Address{0x00}, big.NewInt(1000), params.TxGas, gen.header.BaseFee, nil), signer, key) tx, err := types.SignTx(types.NewTransaction(gen.TxNonce(address), common.Address{0x00}, big.NewInt(1000), params.TxGas, gen.header.BaseFee, nil), signer, key)
if err != nil { if err != nil {
panic(err) panic(err)
@ -3659,7 +3659,7 @@ func testSetCanonical(t *testing.T, scheme string) {
} }
// Generate the side chain and import them // Generate the side chain and import them
_, side, _ := GenerateChainWithGenesis(gspec, engine, 2*TriesInMemory, func(i int, gen *BlockGen) { _, side, _ := GenerateChainWithGenesis(gspec, engine, 2*state.TriesInMemory, func(i int, gen *BlockGen) {
tx, err := types.SignTx(types.NewTransaction(gen.TxNonce(address), common.Address{0x00}, big.NewInt(1), params.TxGas, gen.header.BaseFee, nil), signer, key) tx, err := types.SignTx(types.NewTransaction(gen.TxNonce(address), common.Address{0x00}, big.NewInt(1), params.TxGas, gen.header.BaseFee, nil), signer, key)
if err != nil { if err != nil {
panic(err) panic(err)
@ -3698,8 +3698,8 @@ func testSetCanonical(t *testing.T, scheme string) {
verify(side[len(side)-1]) verify(side[len(side)-1])
// Reset the chain head to original chain // Reset the chain head to original chain
chain.SetCanonical(canon[TriesInMemory-1]) chain.SetCanonical(canon[state.TriesInMemory-1])
verify(canon[TriesInMemory-1]) verify(canon[state.TriesInMemory-1])
} }
// TestCanonicalHashMarker tests all the canonical hash markers are updated/deleted // TestCanonicalHashMarker tests all the canonical hash markers are updated/deleted

@ -41,6 +41,9 @@ import (
"golang.org/x/sync/errgroup" "golang.org/x/sync/errgroup"
) )
// TriesInMemory represents the number of layers that are kept in RAM.
const TriesInMemory = 128
type revision struct { type revision struct {
id int id int
journalIndex int journalIndex int
@ -1269,12 +1272,12 @@ func (s *StateDB) Commit(block uint64, deleteEmptyObjects bool) (common.Hash, er
if err := s.snaps.Update(root, parent, s.convertAccountSet(s.stateObjectsDestruct), s.accounts, s.storages); err != nil { if err := s.snaps.Update(root, parent, s.convertAccountSet(s.stateObjectsDestruct), s.accounts, s.storages); err != nil {
log.Warn("Failed to update snapshot tree", "from", parent, "to", root, "err", err) log.Warn("Failed to update snapshot tree", "from", parent, "to", root, "err", err)
} }
// Keep 128 diff layers in the memory, persistent layer is 129th. // Keep TriesInMemory diff layers in the memory, persistent layer is 129th.
// - head layer is paired with HEAD state // - head layer is paired with HEAD state
// - head-1 layer is paired with HEAD-1 state // - head-1 layer is paired with HEAD-1 state
// - head-127 layer(bottom-most diff layer) is paired with HEAD-127 state // - head-127 layer(bottom-most diff layer) is paired with HEAD-127 state
if err := s.snaps.Cap(root, 128); err != nil { if err := s.snaps.Cap(root, TriesInMemory); err != nil {
log.Warn("Failed to cap snapshot tree", "root", root, "layers", 128, "err", err) log.Warn("Failed to cap snapshot tree", "root", root, "layers", TriesInMemory, "err", err)
} }
} }
s.SnapshotCommits += time.Since(start) s.SnapshotCommits += time.Since(start)

Loading…
Cancel
Save