Skip to content

Commit 137d497

Browse files
swift1337mattac21
authored andcommitted
fix(mempool): wait for reorg height (#900)
* fix waitForReorg + add metric * empty commit, trigger CI
1 parent 8856e13 commit 137d497

File tree

3 files changed

+58
-38
lines changed

3 files changed

+58
-38
lines changed

mempool/iterator.go

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,14 @@ type EVMMempoolIterator struct {
4545
// It combines iterators from both transaction pools and selects transactions based on fee priority.
4646
// Returns nil if both iterators are empty or nil. The bondDenom parameter specifies the native
4747
// token denomination for fee comparisons, and chainId is used for EVM transaction conversion.
48-
func NewEVMMempoolIterator(evmIterator *miner.TransactionsByPriceAndNonce, cosmosIterator mempool.Iterator, logger log.Logger, txConfig client.TxConfig, bondDenom string, chainID *big.Int, blockchain *Blockchain) mempool.Iterator {
48+
func NewEVMMempoolIterator(
49+
evmIterator *miner.TransactionsByPriceAndNonce,
50+
cosmosIterator mempool.Iterator,
51+
logger log.Logger,
52+
txConfig client.TxConfig,
53+
bondDenom string,
54+
blockchain *Blockchain,
55+
) mempool.Iterator {
4956
// Check if we have any transactions at all
5057
hasEVM := evmIterator != nil && !evmIterator.Empty()
5158
hasCosmos := cosmosIterator != nil && cosmosIterator.Tx() != nil
@@ -64,7 +71,7 @@ func NewEVMMempoolIterator(evmIterator *miner.TransactionsByPriceAndNonce, cosmo
6471
logger: logger,
6572
txConfig: txConfig,
6673
bondDenom: bondDenom,
67-
chainID: chainID,
74+
chainID: blockchain.Config().ChainID,
6875
blockchain: blockchain,
6976
}
7077
}

mempool/mempool.go

Lines changed: 41 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -404,17 +404,45 @@ func (m *ExperimentalEVMMempool) ReapNewValidTxs(maxBytes uint64, maxGas uint64)
404404
func (m *ExperimentalEVMMempool) Select(goCtx context.Context, i [][]byte) sdkmempool.Iterator {
405405
m.mtx.Lock()
406406
defer m.mtx.Unlock()
407-
ctx := sdk.UnwrapSDKContext(goCtx)
408407

409-
// Wait for the legacypool to Reset at >= blockHeight (this may have
410-
// already happened), to ensure all txs in pending pool are valid.
411-
m.legacyTxPool.WaitForReorgHeight(ctx, ctx.BlockHeight())
408+
return m.buildIterator(goCtx, i)
409+
}
412410

413-
evmIterator, cosmosIterator := m.getIterators(goCtx, i)
411+
// SelectBy iterates through transactions until the provided filter function returns false.
412+
// It uses the same unified iterator as Select but allows early termination based on
413+
// custom criteria defined by the filter function.
414+
func (m *ExperimentalEVMMempool) SelectBy(goCtx context.Context, txs [][]byte, filter func(sdk.Tx) bool) {
415+
m.mtx.Lock()
416+
defer m.mtx.Unlock()
414417

415-
combinedIterator := NewEVMMempoolIterator(evmIterator, cosmosIterator, m.logger, m.txConfig, m.vmKeeper.GetEvmCoinInfo(ctx).Denom, m.blockchain.Config().ChainID, m.blockchain)
418+
iter := m.buildIterator(goCtx, txs)
416419

417-
return combinedIterator
420+
for iter != nil && filter(iter.Tx()) {
421+
iter = iter.Next()
422+
}
423+
}
424+
425+
// buildIterator ensures that EVM mempool has checked txs for reorgs up to COMMITTED
426+
// block height and then returns a combined iterator over EVM & Cosmos txs.
427+
func (m *ExperimentalEVMMempool) buildIterator(ctx context.Context, txs [][]byte) sdkmempool.Iterator {
428+
sdkCtx := sdk.UnwrapSDKContext(ctx)
429+
430+
// context has a block height of the next PROPOSED block,
431+
// but we need to wait for the reorg to complete on the previous COMMITTED block.
432+
committedHeight := sdkCtx.BlockHeight() - 1
433+
434+
m.legacyTxPool.WaitForReorgHeight(ctx, committedHeight)
435+
436+
evmIterator, cosmosIterator := m.getIterators(ctx, txs)
437+
438+
return NewEVMMempoolIterator(
439+
evmIterator,
440+
cosmosIterator,
441+
m.logger,
442+
m.txConfig,
443+
m.vmKeeper.GetEvmCoinInfo(sdkCtx).Denom,
444+
m.blockchain,
445+
)
418446
}
419447

420448
// CountTx returns the total number of transactions in both EVM and Cosmos pools.
@@ -519,23 +547,6 @@ func (m *ExperimentalEVMMempool) shouldRemoveFromEVMPool(hash common.Hash, reaso
519547
return true
520548
}
521549

522-
// SelectBy iterates through transactions until the provided filter function returns false.
523-
// It uses the same unified iterator as Select but allows early termination based on
524-
// custom criteria defined by the filter function.
525-
func (m *ExperimentalEVMMempool) SelectBy(goCtx context.Context, i [][]byte, f func(sdk.Tx) bool) {
526-
m.mtx.Lock()
527-
defer m.mtx.Unlock()
528-
ctx := sdk.UnwrapSDKContext(goCtx)
529-
530-
evmIterator, cosmosIterator := m.getIterators(goCtx, i)
531-
532-
combinedIterator := NewEVMMempoolIterator(evmIterator, cosmosIterator, m.logger, m.txConfig, m.vmKeeper.GetEvmCoinInfo(ctx).Denom, m.blockchain.Config().ChainID, m.blockchain)
533-
534-
for combinedIterator != nil && f(combinedIterator.Tx()) {
535-
combinedIterator = combinedIterator.Next()
536-
}
537-
}
538-
539550
// SetEventBus sets CometBFT event bus to listen for new block header event.
540551
func (m *ExperimentalEVMMempool) SetEventBus(eventBus *cmttypes.EventBus) {
541552
if m.HasEventBus() {
@@ -594,30 +605,27 @@ func (m *ExperimentalEVMMempool) getEVMMessage(tx sdk.Tx) (*evmtypes.MsgEthereum
594605
// getIterators prepares iterators over pending EVM and Cosmos transactions.
595606
// It configures EVM transactions with proper base fee filtering and priority ordering,
596607
// while setting up the Cosmos iterator with the provided exclusion list.
597-
func (m *ExperimentalEVMMempool) getIterators(goCtx context.Context, i [][]byte) (*miner.TransactionsByPriceAndNonce, sdkmempool.Iterator) {
608+
func (m *ExperimentalEVMMempool) getIterators(goCtx context.Context, txs [][]byte) (*miner.TransactionsByPriceAndNonce, sdkmempool.Iterator) {
598609
ctx := sdk.UnwrapSDKContext(goCtx)
599610
baseFee := m.vmKeeper.GetBaseFee(ctx)
600611
var baseFeeUint *uint256.Int
601612
if baseFee != nil {
602613
baseFeeUint = uint256.MustFromBig(baseFee)
603614
}
604615

605-
m.logger.Debug("getting iterators")
606-
607-
pendingFilter := txpool.PendingFilter{
616+
evmPendingTxs := m.txPool.Pending(txpool.PendingFilter{
608617
MinTip: m.minTip,
609618
BaseFee: baseFeeUint,
610619
BlobFee: nil,
611620
OnlyPlainTxs: true,
612621
OnlyBlobTxs: false,
613622
MaxTxs: 2500,
614-
}
615-
evmPendingTxes := m.txPool.Pending(pendingFilter)
616-
orderedEVMPendingTxes := miner.NewTransactionsByPriceAndNonce(nil, evmPendingTxes, baseFee)
623+
})
617624

618-
cosmosPendingTxes := m.cosmosPool.Select(ctx, i)
625+
evmIterator := miner.NewTransactionsByPriceAndNonce(nil, evmPendingTxs, baseFee)
626+
cosmosIterator := m.cosmosPool.Select(ctx, txs)
619627

620-
return orderedEVMPendingTxes, cosmosPendingTxes
628+
return evmIterator, cosmosIterator
621629
}
622630

623631
func (m *ExperimentalEVMMempool) TrackTx(hash common.Hash) error {

mempool/txpool/legacypool/legacypool.go

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -162,10 +162,13 @@ var (
162162
// throttleTxMeter counts how many transactions are rejected due to too-many-changes between
163163
// txpool reorgs.
164164
throttleTxMeter = metrics.NewRegisteredMeter("txpool/throttle", nil)
165+
165166
// reorgDurationTimer measures how long time a txpool reorg takes.
166-
reorgDurationTimer = metrics.NewRegisteredTimer("txpool/reorgtime", nil)
167-
resetDurationTimer = metrics.NewRegisteredTimer("txpool/resettime", nil)
168-
demoteDurationTimer = metrics.NewRegisteredTimer("txpool/demote", nil)
167+
reorgDurationTimer = metrics.NewRegisteredTimer("txpool/reorgtime", nil)
168+
resetDurationTimer = metrics.NewRegisteredTimer("txpool/resettime", nil)
169+
demoteDurationTimer = metrics.NewRegisteredTimer("txpool/demote", nil)
170+
reorgWaitDurationTimer = metrics.NewRegisteredTimer("txpool/reorgwaittime", nil)
171+
169172
// dropBetweenReorgHistogram counts how many drops we experience between two reorg runs. It is expected
170173
// that this number is pretty low, since txpool reorgs happen very frequently.
171174
dropBetweenReorgHistogram = metrics.NewRegisteredHistogram("txpool/dropbetweenreorg", nil, metrics.NewExpDecaySample(1028, 0.015))
@@ -2131,6 +2134,8 @@ func (pool *LegacyPool) Clear() {
21312134
// height >= height. If the context is cancelled or the pool is shutting down,
21322135
// this will also return.
21332136
func (pool *LegacyPool) WaitForReorgHeight(ctx context.Context, height int64) {
2137+
defer func(start time.Time) { reorgWaitDurationTimer.UpdateSince(start) }(time.Now())
2138+
21342139
for pool.latestReorgHeight.Load() < height {
21352140
// reorg loop has not run at the target height, subscribe to the
21362141
// outcome of the next reorg loop iteration to know when to check again

0 commit comments

Comments
 (0)