diff --git a/miner/worker.go b/miner/worker.go index 64b195b30fa1..635e931b9f13 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -131,6 +131,7 @@ type worker struct { snapshotMu sync.RWMutex // The lock used to protect the block snapshot and state snapshot snapshotBlock *types.Block snapshotReceipts types.Receipts + snapshotState *state.StateDB currentMu sync.Mutex current *Work @@ -193,39 +194,28 @@ func (self *worker) setExtra(extra []byte) { self.extra = extra } -func (self *worker) pending() (*types.Block, *state.StateDB) { - self.currentMu.Lock() - defer self.currentMu.Unlock() - - if atomic.LoadInt32(&self.mining) == 0 { - return types.NewBlock( - self.current.header, - self.current.txs, - nil, - self.current.receipts, - ), self.current.state.Copy() +// pending returns the pending state and corresponding block. The returned +// values can be nil in case the pending block is not initialized. +func (w *worker) pending() (*types.Block, *state.StateDB) { + w.snapshotMu.RLock() + defer w.snapshotMu.RUnlock() + if w.snapshotState == nil { + return nil, nil } - return self.current.Block, self.current.state.Copy() + return w.snapshotBlock, w.snapshotState.Copy() } -func (self *worker) pendingBlock() *types.Block { - self.currentMu.Lock() - defer self.currentMu.Unlock() - - if atomic.LoadInt32(&self.mining) == 0 { - return types.NewBlock( - self.current.header, - self.current.txs, - nil, - self.current.receipts, - ) - } - return self.current.Block +// pendingBlock returns pending block. The returned block can be nil in case the +// pending block is not initialized. +func (w *worker) pendingBlock() *types.Block { + w.snapshotMu.RLock() + defer w.snapshotMu.RUnlock() + return w.snapshotBlock } // pendingBlockAndReceipts returns pending block and corresponding receipts. +// The returned values can be nil in case the pending block is not initialized. func (w *worker) pendingBlockAndReceipts() (*types.Block, types.Receipts) { - // return a snapshot to avoid contention on currentMu mutex w.snapshotMu.RLock() defer w.snapshotMu.RUnlock() return w.snapshotBlock, w.snapshotReceipts @@ -337,7 +327,15 @@ func (self *worker) update() { } feeCapacity := state.GetTRC21FeeCapacityFromState(self.current.state) txset, specialTxs := types.NewTransactionsByPriceAndNonce(self.current.signer, txs, nil, feeCapacity) + + tcount := self.current.tcount self.current.commitTransactions(self.mux, feeCapacity, txset, specialTxs, self.chain, self.coinbase, &self.pendingLogsFeed) + + // Only update the snapshot if any new transactions were added + // to the pending block + if tcount != self.current.tcount { + self.updateSnapshot() + } self.currentMu.Unlock() } else { // If we're mining, but nothing is being processed, wake on new transactions @@ -524,6 +522,22 @@ func (self *worker) makeCurrent(parent *types.Block, header *types.Header) error return nil } +// updateSnapshot updates pending snapshot block and state. +// Note this function assumes the current variable is thread safe. +func (w *worker) updateSnapshot() { + w.snapshotMu.Lock() + defer w.snapshotMu.Unlock() + + w.snapshotBlock = types.NewBlock( + w.current.header, + w.current.txs, + nil, + w.current.receipts, + ) + w.snapshotReceipts = w.current.receipts + w.snapshotState = w.current.state.Copy() +} + func abs(x int64) int64 { if x < 0 { return -x @@ -814,6 +828,7 @@ func (self *worker) commitNewWork() { self.lastParentBlockCommit = parent.Hash().Hex() } self.push(work) + self.updateSnapshot() } func (env *Work) commitTransactions(mux *event.TypeMux, balanceFee map[common.Address]*big.Int, txs *types.TransactionsByPriceAndNonce, specialTxs types.Transactions, bc *core.BlockChain, coinbase common.Address, pendingLogsFeed *event.Feed) {