diff --git a/core/blockchain.go b/core/blockchain.go index 6f68a261e4..2e2e380c35 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -715,7 +715,7 @@ func (bc *BlockChain) GetJustifiedNumber(header *types.Header) uint64 { } // getFinalizedNumber returns the highest finalized number before the specific block. -func (bc *BlockChain) getFinalizedNumber(header *types.Header) uint64 { +func (bc *BlockChain) GetFinalizedNumber(header *types.Header) uint64 { if p, ok := bc.engine.(consensus.PoSA); ok { if finalizedHeader := p.GetFinalizedHeader(bc, header); finalizedHeader != nil { return finalizedHeader.Number.Uint64() @@ -747,7 +747,7 @@ func (bc *BlockChain) loadLastState() error { bc.currentBlock.Store(headBlock.Header()) headBlockGauge.Update(int64(headBlock.NumberU64())) justifiedBlockGauge.Update(int64(bc.GetJustifiedNumber(headBlock.Header()))) - finalizedBlockGauge.Update(int64(bc.getFinalizedNumber(headBlock.Header()))) + finalizedBlockGauge.Update(int64(bc.GetFinalizedNumber(headBlock.Header()))) // Restore the last known head header headHeader := headBlock.Header() @@ -1196,7 +1196,7 @@ func (bc *BlockChain) SnapSyncCommitHead(hash common.Hash) error { bc.currentBlock.Store(block.Header()) headBlockGauge.Update(int64(block.NumberU64())) justifiedBlockGauge.Update(int64(bc.GetJustifiedNumber(block.Header()))) - finalizedBlockGauge.Update(int64(bc.getFinalizedNumber(block.Header()))) + finalizedBlockGauge.Update(int64(bc.GetFinalizedNumber(block.Header()))) bc.chainmu.Unlock() // Destroy any existing state snapshot and regenerate it in the background, @@ -1337,7 +1337,7 @@ func (bc *BlockChain) writeHeadBlock(block *types.Block) { bc.currentBlock.Store(block.Header()) headBlockGauge.Update(int64(block.NumberU64())) justifiedBlockGauge.Update(int64(bc.GetJustifiedNumber(block.Header()))) - finalizedBlockGauge.Update(int64(bc.getFinalizedNumber(block.Header()))) + finalizedBlockGauge.Update(int64(bc.GetFinalizedNumber(block.Header()))) } // stopWithoutSaving stops the blockchain service. If any imports are currently in progress diff --git a/core/headerchain.go b/core/headerchain.go index 310dc57501..bf88e770cd 100644 --- a/core/headerchain.go +++ b/core/headerchain.go @@ -97,7 +97,7 @@ func NewHeaderChain(chainDb ethdb.Database, config *params.ChainConfig, engine c hc.currentHeaderHash = hc.CurrentHeader().Hash() headHeaderGauge.Update(hc.CurrentHeader().Number.Int64()) justifiedBlockGauge.Update(int64(hc.GetJustifiedNumber(hc.CurrentHeader()))) - finalizedBlockGauge.Update(int64(hc.getFinalizedNumber(hc.CurrentHeader()))) + finalizedBlockGauge.Update(int64(hc.GetFinalizedNumber(hc.CurrentHeader()))) return hc, nil } @@ -116,7 +116,7 @@ func (hc *HeaderChain) GetJustifiedNumber(header *types.Header) uint64 { } // getFinalizedNumber returns the highest finalized number before the specific block. -func (hc *HeaderChain) getFinalizedNumber(header *types.Header) uint64 { +func (hc *HeaderChain) GetFinalizedNumber(header *types.Header) uint64 { if p, ok := hc.engine.(consensus.PoSA); ok { if finalizedHeader := p.GetFinalizedHeader(hc, header); finalizedHeader != nil { return finalizedHeader.Number.Uint64() @@ -585,7 +585,7 @@ func (hc *HeaderChain) SetCurrentHeader(head *types.Header) { hc.currentHeaderHash = head.Hash() headHeaderGauge.Update(head.Number.Int64()) justifiedBlockGauge.Update(int64(hc.GetJustifiedNumber(head))) - finalizedBlockGauge.Update(int64(hc.getFinalizedNumber(head))) + finalizedBlockGauge.Update(int64(hc.GetFinalizedNumber(head))) } type ( @@ -673,7 +673,7 @@ func (hc *HeaderChain) setHead(headBlock uint64, headTime uint64, updateFn Updat hc.currentHeaderHash = parentHash headHeaderGauge.Update(parent.Number.Int64()) justifiedBlockGauge.Update(int64(hc.GetJustifiedNumber(parent))) - finalizedBlockGauge.Update(int64(hc.getFinalizedNumber(parent))) + finalizedBlockGauge.Update(int64(hc.GetFinalizedNumber(parent))) // If this is the first iteration, wipe any leftover data upwards too so // we don't end up with dangling daps in the database diff --git a/miner/bid_simulator.go b/miner/bid_simulator.go index da5be60841..291edcc59a 100644 --- a/miner/bid_simulator.go +++ b/miner/bid_simulator.go @@ -113,6 +113,7 @@ type bidSimulator struct { simBidMu sync.RWMutex simulatingBid map[common.Hash]*BidRuntime // prevBlockHash -> bidRuntime, in the process of simulation + bidsToSim map[uint64][]*BidRuntime // blockNumber --> bidRuntime list, used to discard envs maxBidsPerBuilder uint32 // Maximum number of bids allowed per builder per block } @@ -143,6 +144,7 @@ func newBidSimulator( bestBid: make(map[common.Hash]*BidRuntime), bestBidToRun: make(map[common.Hash]*types.Bid), simulatingBid: make(map[common.Hash]*BidRuntime), + bidsToSim: make(map[uint64][]*BidRuntime), } if delayLeftOver != nil { b.delayLeftOver = *delayLeftOver @@ -265,12 +267,6 @@ func (b *bidSimulator) SetBestBid(prevBlockHash common.Hash, bid *BidRuntime) { b.bestBidMu.Lock() defer b.bestBidMu.Unlock() - // must discard the environment of the last best bid, otherwise it will cause memory leak - last := b.bestBid[prevBlockHash] - if last != nil && last.env != nil { - last.env.discard() - } - b.bestBid[prevBlockHash] = bid } @@ -330,6 +326,21 @@ func (b *bidSimulator) RemoveSimulatingBid(prevBlockHash common.Hash) { delete(b.simulatingBid, prevBlockHash) } +func (b *bidSimulator) AddBidToSim(bidRuntime *BidRuntime) { + b.simBidMu.Lock() + defer b.simBidMu.Unlock() + + if bidRuntime == nil || bidRuntime.bid == nil { + return + } + + blockNumber := bidRuntime.bid.BlockNumber + if _, ok := b.bidsToSim[blockNumber]; !ok { + b.bidsToSim[blockNumber] = make([]*BidRuntime, 3) + } + b.bidsToSim[blockNumber] = append(b.bidsToSim[blockNumber], bidRuntime) +} + func (b *bidSimulator) mainLoop() { defer b.chainHeadSub.Unsubscribe() @@ -501,20 +512,20 @@ func (b *bidSimulator) clearLoop() { delete(b.pending, blockNumber) b.pendingMu.Unlock() - b.bestBidMu.Lock() - if bid, ok := b.bestBid[parentHash]; ok { - bid.env.discard() + clearThreshold := b.chain.GetFinalizedNumber(b.chain.GetHeaderByHash(parentHash)) + if blockNumber > b.chain.TriesInMemory() { + clearThreshold = max(clearThreshold, blockNumber-b.chain.TriesInMemory()) } - delete(b.bestBid, parentHash) + + b.bestBidMu.Lock() for k, v := range b.bestBid { - if v.bid.BlockNumber <= blockNumber-b.chain.TriesInMemory() { - v.env.discard() + if v.bid.BlockNumber <= clearThreshold { delete(b.bestBid, k) } } delete(b.bestBidToRun, parentHash) for k, v := range b.bestBidToRun { - if v.BlockNumber <= blockNumber-b.chain.TriesInMemory() { + if v.BlockNumber <= clearThreshold { delete(b.bestBidToRun, k) } } @@ -522,11 +533,21 @@ func (b *bidSimulator) clearLoop() { b.simBidMu.Lock() for k, v := range b.simulatingBid { - if v.bid.BlockNumber <= blockNumber-b.chain.TriesInMemory() { - v.env.discard() + if v.bid.BlockNumber <= clearThreshold { delete(b.simulatingBid, k) } } + for blockNumber, bidList := range b.bidsToSim { + if blockNumber <= clearThreshold { + for _, bid := range bidList { + if bid.env != nil { + // envs for simulating only discard here + bid.env.discard() + } + } + } + delete(b.bidsToSim, blockNumber) + } b.simBidMu.Unlock() } @@ -631,10 +652,6 @@ func (b *bidSimulator) simBid(interruptCh chan int32, bidRuntime *BidRuntime) { if bidRuntime.env != nil { logCtx = append(logCtx, "gasLimit", bidRuntime.env.header.GasLimit) - - if err != nil || !success { - bidRuntime.env.discard() - } } if err != nil { @@ -675,6 +692,7 @@ func (b *bidSimulator) simBid(interruptCh chan int32, bidRuntime *BidRuntime) { }, false); err != nil { return } + b.AddBidToSim(bidRuntime) // if the left time is not enough to do simulation, return delay := b.engine.Delay(b.chain, bidRuntime.env.header, &b.delayLeftOver)