From d902287314bd352df2e040a09e2a272ba62c70dc Mon Sep 17 00:00:00 2001 From: fudongbai <296179868@qq.com> Date: Thu, 3 Jun 2021 21:45:53 +0800 Subject: [PATCH] lazy init trie tree of statedb --- core/blockchain.go | 22 ++++++++++++---------- core/state/statedb.go | 29 ++++++++++++++++++++++++----- 2 files changed, 36 insertions(+), 15 deletions(-) diff --git a/core/blockchain.go b/core/blockchain.go index 095f83168f..03db0518e4 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -1854,7 +1854,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, verifySeals bool) (int, er if parent == nil { parent = bc.GetHeader(block.ParentHash(), block.NumberU64()-1) } - statedb, err := state.New(parent.Root, bc.stateCache, bc.snaps) + statedb, err := state.LazyNew(parent.Root, bc.stateCache, bc.snaps) if err != nil { return it.index, err } @@ -1867,16 +1867,18 @@ func (bc *BlockChain) insertChain(chain types.Blocks, verifySeals bool) (int, er var followupInterrupt uint32 if !bc.cacheConfig.TrieCleanNoPrefetch { if followup, err := it.peek(); followup != nil && err == nil { - throwaway, _ := state.New(parent.Root, bc.stateCache, bc.snaps) - - go func(start time.Time, followup *types.Block, throwaway *state.StateDB, interrupt *uint32) { - bc.prefetcher.Prefetch(followup, throwaway, bc.vmConfig, &followupInterrupt) + if throwaway, err := state.New(parent.Root, bc.stateCache, bc.snaps); err != nil { + log.Error("Can not prefetch state", "err", err) + } else { + go func(start time.Time, followup *types.Block, throwaway *state.StateDB, interrupt *uint32) { + bc.prefetcher.Prefetch(followup, throwaway, bc.vmConfig, &followupInterrupt) - blockPrefetchExecuteTimer.Update(time.Since(start)) - if atomic.LoadUint32(interrupt) == 1 { - blockPrefetchInterruptMeter.Mark(1) - } - }(time.Now(), followup, throwaway, &followupInterrupt) + blockPrefetchExecuteTimer.Update(time.Since(start)) + if atomic.LoadUint32(interrupt) == 1 { + blockPrefetchInterruptMeter.Mark(1) + } + }(time.Now(), followup, throwaway, &followupInterrupt) + } } } preloadWg := sync.WaitGroup{} diff --git a/core/state/statedb.go b/core/state/statedb.go index 78e492cd5d..d1c910911b 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -126,13 +126,17 @@ type StateDB struct { // New creates a new state from a given trie. func New(root common.Hash, db Database, snaps *snapshot.Tree) (*StateDB, error) { - tr, err := db.OpenTrie(root) - if err != nil { - return nil, err - } + return newStateDB(root, db, snaps, false) +} + +// New creates a new state, but do not open the trie tree at first. +func LazyNew(root common.Hash, db Database, snaps *snapshot.Tree) (*StateDB, error) { + return newStateDB(root, db, snaps, true) +} + +func newStateDB(root common.Hash, db Database, snaps *snapshot.Tree, lazy bool) (*StateDB, error) { sdb := &StateDB{ db: db, - trie: tr, originalRoot: root, snaps: snaps, stateObjects: make(map[common.Address]*stateObject), @@ -151,6 +155,14 @@ func New(root common.Hash, db Database, snaps *snapshot.Tree) (*StateDB, error) sdb.snapStorage = make(map[common.Hash]map[common.Hash][]byte) } } + // if without snaps, still init with trie tree + if !lazy || sdb.snap == nil { + tr, err := db.OpenTrie(root) + if err != nil { + return nil, err + } + sdb.trie = tr + } return sdb, nil } @@ -948,6 +960,13 @@ func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash { s.trie = trie } } + if s.trie == nil { + tr, err := s.db.OpenTrie(s.originalRoot) + if err != nil { + panic(fmt.Sprintf("Failed to open trie tree")) + } + s.trie = tr + } usedAddrs := make([][]byte, 0, len(s.stateObjectsPending)) for addr := range s.stateObjectsPending { if obj := s.stateObjects[addr]; obj.deleted {