交易进入区块之前,会先存放在 mempool 中;它负责处理交易排序、nonce 间隙排队,以及对 EVM 与 Cosmos 交易统一进行基于费用的优先级选择。EVM mempool 在 evmd 中默认启用。关于 mempool 设计与架构的概念性说明,请参阅 Mempool Concepts 页面。 mempool 的设置分布在两个位置:
  • evmd/mempool.go — 你必须在 app.go 中、setAnteHandler 之后调用 configureEVMMempool
  • mempool/ — mempool 的实现(EVMMempool、TxPool、Rechecker、ReapList、RecheckPool 等)
最常用的 EVM Mempool 旧版池参数 MinTip 已通过 app.toml 暴露,无需修改代码。旧版池 (legacypool.LegacyPool)是对 go-ethereum transaction pool 的移植, 负责所有 EVM 交易排序与费用约束。某些高级设置无法通过 app.toml 配置,需要修改 evmd/mempool.go 中的 createMempoolConfig。BlockGasLimit 会从 genesis.json 中的 consensus_params.block.max_gas 读取。

配置选项

Config 结构体用于控制 mempool 行为:
mempool/mempool.go
type Config struct {
    LegacyPoolConfig *legacypool.Config                                // Optional: port of Geth's txpool — see Custom Legacy Pool below
    CosmosPoolConfig *sdkmempool.PriorityNonceMempoolConfig[math.Int]  // Optional: Cosmos pool tuning — see Custom Cosmos Mempool below
    AnteHandler      sdk.AnteHandler                                   // Required: transaction validation

    BlockGasLimit    uint64                                            // Required: gas limit for block selection
    MinTip           *uint256.Int                                      // Optional: minimum tip for EVM txs

	PendingTxProposalTimeout time.Duration                             // Optional but recommended: max amount of time to allocate to fetching pending execution txs
	InsertQueueSize int                                                // Optional: how many txs can be pending insertion at once
	EnableTxTracker bool                                               // Optional: if tracking transaction inclusion metrics is enabled
}

默认值与回退行为

  • 如果 BlockGasLimit 为 0,mempool 会使用 100_000_000 gas 作为回退值。
  • 如果未提供 LegacyPoolConfig,将使用 legacypool.DefaultConfig 的默认值。
  • 如果未提供 CosmosPoolConfig,会创建一个默认的 PriorityNonceMempool,其配置如下:
    • Priority = EVM coin denom 中的 (fee_amount / gas_limit)
    • Comparator = 大整数比较(值越大越优先)
    • MinValue = 0
  • MinTip 为可选项。如果未设置,选择逻辑会使用每笔交易的有效 tip(min(gas_tip_cap, gas_fee_cap - base_fee))。
  • 如果未提供 PendingTxProposalTimeout,则使用 0。这表示 超时不受限制,并且在创建 proposal 之前始终等待所有交易 recheck 完成。
  • 如果 InsertQueueSize 为 0,mempool 会使用 5000 作为回退值。
  • 如果未提供 EnableTxTracker,则保持为 false。

自定义旧版池配置

自定义 EVM transaction pool 参数:
evmd/mempool.go
// EVM legacy txpool tuning
legacyCfg := legacypool.DefaultConfig
legacyCfg.PriceLimit = 2                // Minimum gas price (wei)
legacyCfg.PriceBump = 15                // 15% price bump to replace
legacyCfg.AccountSlots = 32             // Slots per account
legacyCfg.GlobalSlots = 10240           // Total executable slots
legacyCfg.AccountQueue = 128            // Non-executable per account
legacyCfg.GlobalQueue = 2048            // Total non-executable
legacyCfg.Lifetime = 6 * time.Hour      // Max queue time
legacyCfg.IncludedNonceCacheSize = 5000 // Max cache size for tracking account nonces

mempoolConfig.LegacyPoolConfig = &legacyCfg

自定义 Cosmos Mempool 配置

mempool 默认对 Cosmos 交易使用 PriorityNonceMempool。你可以自定义优先级计算方式:
evmd/mempool.go
// Define custom priority calculation for Cosmos transactions
cosmosCfg := sdkmempool.PriorityNonceMempoolConfig[math.Int]{}
cosmosCfg.TxPriority = sdkmempool.TxPriority[math.Int]{
    GetTxPriority: func(goCtx context.Context, tx sdk.Tx) math.Int {
        feeTx, ok := tx.(sdk.FeeTx)
        if !ok {
            return math.ZeroInt()
        }

        // Get fee in bond denomination
        bondDenom := "uatom" // or your chain's bond denom
        fee := feeTx.GetFee()
        found, coin := fee.Find(bondDenom)
        if !found {
            return math.ZeroInt()
        }

        // Calculate gas price: fee_amount / gas_limit
        gasPrice := coin.Amount.Quo(math.NewIntFromUint64(feeTx.GetGas()))
        return gasPrice
    },
    Compare: func(a, b math.Int) int {
        return a.BigInt().Cmp(b.BigInt()) // Higher values have priority
    },
    MinValue: math.ZeroInt(),
}

mempoolConfig.CosmosPoolConfig = &cosmosCfg

自定义区块 Gas 上限

BlockGasLimit 会自动从 genesis.json 中的 consensus_params.block.max_gas 读取,它不是 app.toml 配置项。要修改它,需要在链启动前更新 genesis 文件。该值也可以在代码中覆盖:
evmd/mempool.go
// Example: 50M gas limit for lower capacity chains
mempoolConfig := &evmmempool.Config{
    BlockGasLimit: 50_000_000,
}

Event Bus 集成

用户必须将 mempool 连接到 CometBFT 的 EventBus,这样它才能对已最终确认的区块作出响应:
evmd/app.go
// After starting the CometBFT node
if m, ok := app.GetMempool().(*evmmempool.EVMMempool); ok {
    m.SetEventBus(bftNode.EventBus())
}
这样会启用链头通知,使 mempool 能在区块提交后及时提升或驱逐交易。

app.toml 配置

以下设置可以在 app.toml 中配置,并在节点启动时生效,无需修改代码:
键默认值说明
evm.min-tip0以 wei 表示的最小 tip(优先费);低于该值的交易不会被纳入区块选择
evm.mempool.price-limit1接受交易进入池所需的最小 gas price(单位 wei)
evm.mempool.price-bump10用于替换相同 nonce 的待处理交易所需的最小涨幅百分比
evm.mempool.account-slots16每个账户可执行交易的最大数量
evm.mempool.global-slots5120所有账户合计可执行交易的最大数量
evm.mempool.account-queue64每个账户排队中(不可执行)交易的最大数量
evm.mempool.global-queue1024所有账户合计排队交易的最大数量
evm.mempool.lifetime3h交易在被驱逐前可在队列中保留的最长时间
evm.mempool.included-nonce-cache-size4096用于驱逐判断时跟踪 nonce 的最大数量。该值应设置为在当前链的区块 gas 上限下,单个区块中预期会出现的最大账户数。
evm.mempool.pending-tx-proposal-timeout0ms创建 proposal 时,等待获取待执行交易的最长时间。0 表示在创建 proposal 前等待所有交易校验完成。注意,在高负载下这可能耗时较长并降低性能。实践中发现,将其设置为约 250ms,通常能在性能与每个区块 recheck 足够数量交易之间取得较好平衡。
evm.mempool.check-tx-timeout5s插入 Cosmos 交易时等待 CheckTx 完成的超时时间。
evm.mempool.insert-queue-size5000返回错误之前允许处于待插入状态的最大交易数。注意,EVM 与 Cosmos 交易使用各自独立的队列。因此,你可以同时有 insert-queue-size 个 EVM 交易和 insert-queue-size 个 Cosmos 交易处于待插入状态。
evm.mempool.enable-tx-trackerfalse是否启用用于跟踪 EVM 交易纳入延迟的指标。

监控与调试

使用 txpool RPC methods 监控 mempool 状态:
  • txpool_status:获取待处理和排队交易数量
  • txpool_content:查看池中的全部交易
  • txpool_inspect:获取可读性更高的交易摘要
  • txpool_contentFrom:查看特定地址的交易

相关文档


The mempool holds submitted transactions before they are included in a block, handling ordering, nonce gap queuing, and fee-based prioritization across both EVM and Cosmos transactions. The EVM mempool is enabled by default in evmd. For conceptual information about mempool design and architecture, see the Mempool Concepts page. The mempool setup is split across two locations:
  • evmd/mempool.go — configureEVMMempool must be called from your app.go after setAnteHandler
  • mempool/ — the mempool implementation (EVMMempool,TxPool, Rechecker, ReapList, RecheckPool, etc)
The most common EVM Mempool, Legacy pool parameters, MinTip are exposed via app.toml and require no code changes. The legacy pool (legacypool.LegacyPool) is a port of go-ethereum’s transaction pool and handles all EVM transaction ordering and fee enforcement. Some advanced settings are not covered by app.toml, and require modifying createMempoolConfig in evmd/mempool.go. BlockGasLimit is read from consensus_params.block.max_gas in genesis.json.

Configuration Options

The Config struct controls mempool behavior:
mempool/mempool.go
type Config struct {
    LegacyPoolConfig *legacypool.Config                                // Optional: port of Geth's txpool — see Custom Legacy Pool below
    CosmosPoolConfig *sdkmempool.PriorityNonceMempoolConfig[math.Int]  // Optional: Cosmos pool tuning — see Custom Cosmos Mempool below
    AnteHandler      sdk.AnteHandler                                   // Required: transaction validation

    BlockGasLimit    uint64                                            // Required: gas limit for block selection
    MinTip           *uint256.Int                                      // Optional: minimum tip for EVM txs

	PendingTxProposalTimeout time.Duration                             // Optional but recommended: max amount of time to allocate to fetching pending execution txs
	InsertQueueSize int                                                // Optional: how many txs can be pending insertion at once
	EnableTxTracker bool                                               // Optional: if tracking transaction inclusion metrics is enabled
}

Defaults and Fallbacks

  • If BlockGasLimit is 0, the mempool uses a fallback of 100_000_000 gas.
  • If LegacyPoolConfig is not provided, defaults from legacypool.DefaultConfig are used.
  • If CosmosPoolConfig is not provided, a default PriorityNonceMempool is created with:
    • Priority = (fee_amount / gas_limit) in the EVM coin denom
    • Comparator = big-int comparison (higher is selected first)
    • MinValue = 0
  • MinTip is optional. If unset, selection uses the effective tip from each tx (min(gas_tip_cap, gas_fee_cap - base_fee)).
  • If PendingTxProposalTimeout is not provided, 0 is used. This means unlimited timeout and always wait for all tx rechecking to finish before creating a proposal.
  • If InsertQueueSize is 0, the mempool uses a fallback of 5000.
  • If EnableTxTracker is not provided, it is kept false.

Custom Legacy Pool Configuration

Customize EVM transaction pool parameters:
evmd/mempool.go
// EVM legacy txpool tuning
legacyCfg := legacypool.DefaultConfig
legacyCfg.PriceLimit = 2                // Minimum gas price (wei)
legacyCfg.PriceBump = 15                // 15% price bump to replace
legacyCfg.AccountSlots = 32             // Slots per account
legacyCfg.GlobalSlots = 10240           // Total executable slots
legacyCfg.AccountQueue = 128            // Non-executable per account
legacyCfg.GlobalQueue = 2048            // Total non-executable
legacyCfg.Lifetime = 6 * time.Hour      // Max queue time
legacyCfg.IncludedNonceCacheSize = 5000 // Max cache size for tracking account nonces

mempoolConfig.LegacyPoolConfig = &legacyCfg

Custom Cosmos Mempool Configuration

The mempool uses a PriorityNonceMempool for Cosmos transactions by default. You can customize the priority calculation:
evmd/mempool.go
// Define custom priority calculation for Cosmos transactions
cosmosCfg := sdkmempool.PriorityNonceMempoolConfig[math.Int]{}
cosmosCfg.TxPriority = sdkmempool.TxPriority[math.Int]{
    GetTxPriority: func(goCtx context.Context, tx sdk.Tx) math.Int {
        feeTx, ok := tx.(sdk.FeeTx)
        if !ok {
            return math.ZeroInt()
        }

        // Get fee in bond denomination
        bondDenom := "uatom" // or your chain's bond denom
        fee := feeTx.GetFee()
        found, coin := fee.Find(bondDenom)
        if !found {
            return math.ZeroInt()
        }

        // Calculate gas price: fee_amount / gas_limit
        gasPrice := coin.Amount.Quo(math.NewIntFromUint64(feeTx.GetGas()))
        return gasPrice
    },
    Compare: func(a, b math.Int) int {
        return a.BigInt().Cmp(b.BigInt()) // Higher values have priority
    },
    MinValue: math.ZeroInt(),
}

mempoolConfig.CosmosPoolConfig = &cosmosCfg

Custom Block Gas Limit

BlockGasLimit is read automatically from consensus_params.block.max_gas in genesis.json — it is not an app.toml setting. To change it, update the genesis file before chain start. The value can also be overridden in code:
evmd/mempool.go
// Example: 50M gas limit for lower capacity chains
mempoolConfig := &evmmempool.Config{
    BlockGasLimit: 50_000_000,
}

Event Bus Integration

Users must connect the mempool to CometBFT’s EventBus so it can react to finalized blocks:
evmd/app.go
// After starting the CometBFT node
if m, ok := app.GetMempool().(*evmmempool.EVMMempool); ok {
    m.SetEventBus(bftNode.EventBus())
}
This enables chain-head notifications so the mempool can promptly promote/evict transactions when blocks are committed.

app.toml Configuration

The following settings can be configured in app.toml and take effect at node startup without code changes:
KeyDefaultDescription
evm.min-tip0Minimum tip (priority fee) in wei; transactions below this are excluded from block selection
evm.mempool.price-limit1Minimum gas price in wei to accept a transaction into the pool
evm.mempool.price-bump10Minimum % increase required to replace a pending transaction with the same nonce
evm.mempool.account-slots16Max executable transactions per account
evm.mempool.global-slots5120Max total executable transactions across all accounts
evm.mempool.account-queue64Max queued (non-executable) transactions per account
evm.mempool.global-queue1024Max total queued transactions across all accounts
evm.mempool.lifetime3hMax time a transaction can remain queued before eviction
evm.mempool.included-nonce-cache-size4096Max amount of nonces to track for eviction. Should be set to the maximum number of accounts you expect to see in a single block, given your chains block gas limit.
evm.mempool.pending-tx-proposal-timeout0msMax time to wait for fetching pending execution transaction when creating a proposal. 0 means wait for all transactions to be validated before creating a proposal. Note that this may take a significant amount of time under high load and can degrade performance. We’ve found setting this to ~250ms strikes the right balance between performance and rechecking a sufficient amount of transactions per block.
evm.mempool.check-tx-timeout5sTimeout to wait for CheckTx on Cosmos txs insertion.
evm.mempool.insert-queue-size5000Max amount of transactions that can be pending insertion before returning an error. Note that EVM & Cosmos transaction use separate queues. So you may have insert-queue-size EVM transactions pending insertion, and insert-queue-size Cosmos transactions pending insertion.
evm.mempool.enable-tx-trackerfalseIf metrics for tracking EVM transaction inclusion latencies should be enabled.

Monitoring and Debugging

Use the txpool RPC methods to monitor mempool state:
  • txpool_status: Get pending and queued transaction counts
  • txpool_content: View all transactions in the pool
  • txpool_inspect: Get human-readable transaction summaries
  • txpool_contentFrom: View transactions from specific addresses