From f35abea1e54edee083042769a17ca3ae8c459a1f Mon Sep 17 00:00:00 2001 From: setunapo Date: Fri, 25 Nov 2022 14:05:19 +0800 Subject: [PATCH] worker: reused triePrefetch when multi-fillTransactions to mine a block. avoid too much trie prefetch routines when several fillTransactions are called. --- core/state/statedb.go | 19 +++++++++++++++++++ miner/worker.go | 32 ++++++++++++++++++++------------ 2 files changed, 39 insertions(+), 12 deletions(-) diff --git a/core/state/statedb.go b/core/state/statedb.go index e7bf3c9491..f02908e881 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -200,6 +200,25 @@ func (s *StateDB) EnableWriteOnSharedStorage() { s.writeOnSharedStorage = true } +// In mining mode, we will try multi-fillTransactions to get the most profitable one. +// StateDB will be created for each fillTransactions with same block height. +// Share a single triePrefetcher to avoid too much prefetch routines. +func (s *StateDB) TransferPrefetcher(prev *StateDB) { + if prev == nil { + return + } + var fetcher *triePrefetcher + + prev.prefetcherLock.Lock() + fetcher = prev.prefetcher + prev.prefetcher = nil + prev.prefetcherLock.Unlock() + + s.prefetcherLock.Lock() + s.prefetcher = fetcher + s.prefetcherLock.Unlock() +} + // StartPrefetcher initializes a new trie prefetcher to pull in nodes from the // state trie concurrently while the state is mutated so that when we reach the // commit phase, most of the needed data is already hot. diff --git a/miner/worker.go b/miner/worker.go index 200ffb88b2..77ce47f73e 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -718,14 +718,19 @@ func (w *worker) resultLoop() { } // makeEnv creates a new environment for the sealing block. -func (w *worker) makeEnv(parent *types.Block, header *types.Header, coinbase common.Address) (*environment, error) { +func (w *worker) makeEnv(parent *types.Block, header *types.Header, coinbase common.Address, + prevEnv *environment) (*environment, error) { // Retrieve the parent state to execute on top and start a prefetcher for // the miner to speed block sealing up a bit state, err := w.chain.StateAtWithSharedPool(parent.Root()) if err != nil { return nil, err } - state.StartPrefetcher("miner") + if prevEnv == nil { + state.StartPrefetcher("miner") + } else { + state.TransferPrefetcher(prevEnv.state) + } // Note the passed coinbase may be different with header.Coinbase. env := &environment{ @@ -941,6 +946,7 @@ type generateParams struct { random common.Hash // The randomness generated by beacon chain, empty before the merge noUncle bool // Flag whether the uncle block inclusion is allowed noExtra bool // Flag whether the extra field assignment is allowed + prevWork *environment } // prepareWork constructs the sealing task according to the given parameters, @@ -999,7 +1005,7 @@ func (w *worker) prepareWork(genParams *generateParams) (*environment, error) { // Could potentially happen if starting to mine in an odd state. // Note genParams.coinbase can be different with header.Coinbase // since clique algorithm can modify the coinbase field in header. - env, err := w.makeEnv(parent, header, genParams.coinbase) + env, err := w.makeEnv(parent, header, genParams.coinbase, genParams.prevWork) if err != nil { log.Error("Failed to create sealing context", "err", err) return nil, err @@ -1105,27 +1111,29 @@ func (w *worker) commitWork(interruptCh chan int32, timestamp int64) { // validator can try several times to get the most profitable block, // as long as the timestamp is not reached. workList := make([]*environment, 0, 10) - var bestWork *environment + var prevWork *environment // workList clean up defer func() { - for _, w := range workList { + for _, wk := range workList { // only keep the best work, discard others. - if w == bestWork { + if wk == w.current { continue } - w.discard() + wk.discard() } }() + LOOP: for { work, err := w.prepareWork(&generateParams{ timestamp: uint64(timestamp), coinbase: coinbase, + prevWork: prevWork, }) if err != nil { return } - + prevWork = work workList = append(workList, work) delay := w.engine.Delay(w.chain, work.header, &w.config.DelayLeftOver) @@ -1215,13 +1223,13 @@ LOOP: } } // get the most profitable work - bestWork = workList[0] + bestWork := workList[0] bestReward := new(big.Int) - for i, w := range workList { - balance := w.state.GetBalance(consensus.SystemAddress) + for i, wk := range workList { + balance := wk.state.GetBalance(consensus.SystemAddress) log.Debug("Get the most profitable work", "index", i, "balance", balance, "bestReward", bestReward) if balance.Cmp(bestReward) > 0 { - bestWork = w + bestWork = wk bestReward = balance } }