Mempool Expiry eviction might remove txs that could be mined in the next block #33510

issue ismaelsadeeq openend this issue on September 30, 2025
  1. ismaelsadeeq commented at 4:15 pm on September 30, 2025: member

    LimitMempoolSize always try to remove transactions from the mempool whose age has passed the mempool expiry time limit, which is 336 hours (i.e., two weeks) by default.

    There might be a case where you evict something that might be mined next. For example, the mempool was cleared and some low feerate transaction that has been in the mempool and has not confirmed in a long time due to having a low feerate is now at the top of the mempool. However, when we want to limit the mempool size, we will evict such transactions.

    We can limit the harm of this by only expiring when the mempool is full now then post Cluster mempool, in addition to the transaction entry time, it would be possible to keep track of how many times you expect the transaction to confirm and it has not. If it has reached some threshold and the expiry time of the tx has been reached, then drop the transaction from the mempool because you know the transaction is likely deliberately ignored by miners (On the assumption that the node policy rules is sane and miners use tx fee as incentive for selection of transaction into their block template) hence no need to save it in the nodes mempool.

  2. polespinasa commented at 7:59 pm on September 30, 2025: contributor

    How about we make the expiration time dynamic based on the position (computer by fee rate) in the mempool?

    Txs more likely to be mined have a bigger expiry time. If the mempool clears a bit, txs with low feerate will be on top of the mempool and their expiry time can be re-calculated to increase and avoid evicting txs that will be mined.

    This way transactions more likely to be mined will not be evicted while the txs less likely to be mined will be evicted and only kept if the mempool clears a bit and they change their “likely grade”.

  3. sipa commented at 9:29 pm on September 30, 2025: member

    I don’t know if this is really a concern in practice, because it’s already compensated for by the fact that after a long time, transactions near the top of the mempool have had many chances of being mined already.

    We could just get rid of expiration entirely if a time-based limit wasn’t valuable, and just rely on eviction due to fullness. But if time-based expiration is valuable, then it’s inevitable that a chance exists that a soon-to-be mined transaction expires.

  4. polespinasa commented at 9:32 pm on September 30, 2025: contributor

    We could just get rid of expiration entirely if a time-based limit wasn’t valuable

    I might agree with this. @sipa do you know the reason why this was implemented in the first place?

  5. davidgumberg commented at 10:06 pm on September 30, 2025: contributor

    Archeology

    Time-based mempool expiry was added here: https://github.com/bitcoin/bitcoin/commit/49b6fd5663dfe081d127cd1eb11407c4d3eaf93d as part of #6722, from what I found, the most relevant discussion for time expiry was in #6455, e.g. this comment (https://github.com/bitcoin/bitcoin/pull/6455#issuecomment-122580009)):

    I do understand the worry about mempools becoming filled with high-fee but unconfirming transactions, leading to (ever) increasing fees until the mempool clears. I’ve thought about using fees actually in the mempool, or time-based experation.

    There are also two relevant irc discussions: here and here

     0flowchart TD
     1    A[#6331] --> D(#6421)
     2    B[#6410] --> D
     3    C[#6281] --> D
     4    D --> |time expiry added| G[#6455]
     5    E[#6452] --> G
     6    F[#6453] --> G
     7    G --> H[#6470]
     8    H --> I[#6557]
     9    I --> J[#6722]
    10    J --> |merged| K[master]
    11    
    12    click A "https://github.com/bitcoin/bitcoin/pull/6331" _blank
    13    click B "https://github.com/bitcoin/bitcoin/pull/6410" _blank
    14    click C "https://github.com/bitcoin/bitcoin/pull/6281" _blank
    15    click D "https://github.com/bitcoin/bitcoin/pull/6421" _blank
    16    click E "https://github.com/bitcoin/bitcoin/pull/6452" _blank
    17    click F "https://github.com/bitcoin/bitcoin/pull/6453" _blank
    18    click G "https://github.com/bitcoin/bitcoin/pull/6455" _blank
    19    click H "https://github.com/bitcoin/bitcoin/pull/6470" _blank
    20    click I "https://github.com/bitcoin/bitcoin/pull/6557" _blank
    21    click J "https://github.com/bitcoin/bitcoin/pull/6722" _blank
    22    click K "https://github.com/bitcoin/bitcoin/commit/49b6fd5663dfe081d127cd1eb11407c4d3eaf93d" _blank
    

    From this and my own assumptions, I gather that the time-based expiry is generally intended to evict transactions that a node believes are likely to be mined but empirical evidence has shown miners are not including for a long enough period of time that we think those transactions will never be included, maybe because miners:

    • Are censoring these transactions
    • Have a different estimation of their feerate
    • Have a soft-fork activated that your node doesn’t that makes the high feerate transactions consensus invalid

    How about we make the expiration time dynamic based on the position (computer by fee rate) in the mempool?

    Txs more likely to be mined have a bigger expiry time

    I think this should be the opposite, the transactions that are the best candidates for time-based expiry, are the ones that are at the top of our mempool, but block after block remain unconfirmed.

    We could just get rid of expiration entirely if a time-based limit wasn’t valuable, and just rely on eviction due to fullness.

    My gut reaction is that time-based expiry isn’t helpful, but without it, it seems like it would be easy to break the mempools of nodes that are missing a soft fork, since you could broadcast a mempool’s worth of post-soft-fork-invalid high-fee transactions for “free” to pre-soft-fork nodes, and they will never let go of them, but I suppose the current behavior where an attacker has to periodically rebroadcast is not that big of a barrier.

  6. polespinasa commented at 10:40 pm on September 30, 2025: contributor

    Thanks for the context @davidgumberg

    How about we make the expiration time dynamic based on the position (computer by fee rate) in the mempool? Txs more likely to be mined have a bigger expiry time

    I think this should be the opposite, the transactions that are the best candidates for time-based expiry, are the ones that are at the top of our mempool, but block after block remain unconfirmed.

    Yep, you are right, makes more sense in the opposite 😅

    but I suppose the current behavior where an attacker has to periodically rebroadcast is not that big of a barrier.

    It’s not a big barrier but still more uncomfortable; you have to be connected to the victim node and re-rebroadcast every default expiry_time, and eventually, if the attacker gets tired, the node will go run normal again. Without the expiry time, you can dos a mempool with 1 single attack.

  7. sipa commented at 1:01 pm on October 1, 2025: member

    @davidgumberg I like the idea of expiring based on how many times a transaction was expected to be mined, but wasn’t. E.g. every block, or every 10 minutes, or on a Poisson timer, run the block building code and increase a counter in the mempool for every transaction in the template. Whenever the counter reaches a certain configurable value, expire. Note that that may well mean that nothing ever expires, if everything gets mined once it’s spent enough time near the top of the mempool - but that may be ok, if it’s a sign there is no persistent policy difference between your mempool and miners'.

    One potential issue I see that whenever we expire, we also need to expire all descendants. What if you have a very old transaction that isn’t confirming (for whatever reason) but it has a very recent child? Should the child be permitted to keep its parent alive longer? This might matter in CPFP settings, if the child somehow helps the parent getting confirmed.

    Also thanks for digging up the history for expiration; I was wondering if it predated RBF, eviction, and CPFP, but it looks like all those things were added roughly around the same time. I can imagine one other reason for expiration, which probably didn’t exist at the time it was added: allowing transactions to be replaced for free (e.g. without the incremental relay fee, as a counter to the pinning that’s caused by that). But I’m guessing that the 2-week timeout currently doesn’t really help with that anyway.

  8. glozow commented at 7:19 pm on October 8, 2025: member

    Also thanks for digging up the history for expiration; I was wondering if it predated RBF, eviction, and CPFP, but it looks like all those things were added roughly around the same time. I can imagine one other reason for expiration, which probably didn’t exist at the time it was added: allowing transactions to be replaced for free (e.g. without the incremental relay fee, as a counter to the pinning that’s caused by that).

    I’ll add that, back in the day, expiry would have been the only way to “replace” (i.e. get rid of) a non-signaling transaction that wasn’t confirming.

  9. glozow added the label Mempool on Oct 8, 2025

github-metadata-mirror

This is a metadata mirror of the GitHub repository bitcoin/bitcoin. This site is not affiliated with GitHub. Content is generated from a GitHub metadata backup.
generated: 2025-10-10 15:13 UTC

This site is hosted by @0xB10C
More mirrored repositories can be found on mirror.b10c.me