When a node receives a transaction that conflicts with, or spends the same prevout
as, one or more of the transactions in its mempool, it decides which transaction(s) to keep based
on a set of rules. Bitcoin Core’s Replace by Fee
requires that no transaction replace more than 100 mempool transactions (“Rule 5”).
Many people conclude that the descendant limit makes Rule 5 redundant; it seems that a transaction
cannot replace more than 100 transactions a conflicting mempool transaction cannot have more than
25 descendants. This is a very common misconception. A transaction can spend multiple prevouts, and
thus conflict with multiple unrelated transactions.
What does it mean for a transaction to “conflict with” transactions in the mempool? What is the
difference between a “directly” and “indirectly conflicting” transaction?
Based on the default RBF policy, how many “direct” conflicts is a transaction allowed to have?
How many transactions is it allowed to replace?
Why should the node limit the number of transactions that can be replaced at a time? Can you
think of any potential attacks
How is it possible for a transaction to conflict with 100 transactions if the descendant limit is
25? Can you come up with an example that isn’t the one tested in this PR?
What’s wrong with configuring -acceptnonstdtxn=1, -limitancestorcount, -limitancestorsize,
-limitdescendantcount, and -limitdescendantsize, to test mempool policy?
Why is it necessary to pass a different sequence to create_self_transfer_multi?
What does annotating get_utxo with the -> dict return type annotation do?
Rule 5 only restricts the number of transactions that can be replaced, not the size. However, an
effective maximum exists; what is the effective maximum virtual size of transactions that can be
replaced in a default mempool? (Hint: default maximum transaction
and maximum ancestor/descendant
(Hint Hint: not all of these numbers are relevant)).
Hypothetically, if we increased the default ancestor/descendant limits to 120, would we also need
to change the limit on replaced transactions? (Hint: how can a transaction recipient prevent its
In what scenarios will the
for calculating the number of to-be-replaced transactions overestimate? If we call
pool.CalculateDescendants() with a set of 99 mempool entries, what is the maximum number of
mempool transactions we might traverse before the function returns?
<danielabrozzoni> I read the code, I tried to understand the difference between the new `test_too_many_replacements_with_default_mempool_params` and the old `test_too_many_replacements` to understand why the old one wasn't testing the rule 5 use case
<glozow> larryruane: danielabrozzoni: Great summaries, thank you! Let's move onto the questions. What does it mean for a transaction to “conflict with” transactions in the mempool? What is the difference between a “directly” and “indirectly conflicting” transaction?
<danielabrozzoni> TxA is directly conflicting with TxB if A double spends B's inputs. TxA is indirectly conflicting with TxB if A is directly conflicting with one of B's ancestors (so if B's ancestor is replaced with A, B has to be evicted as well).
<glozow> danielabrozzoni: larryruane: yes! if you evict a transaction, you must also evict its descendants. so we also care if there are "indirect" conflicts, i.e. the transaction conflicts with the ancestor of a mempool tx
<larryruane> they could submit (let's just say) 500 independent transactions all with low fee (but enough to make it into the mempool), and then attacker could submit a single transaction that conflicts with all 500
<glozow> Fun! I have a bonus question that's pretty relevant here. Rule 5 only restricts the number of transactions that can be replaced, not the size. However, an effective maximum exists; what is the effective maximum virtual size of transactions that can be replaced in a default mempool?
<sipa> michaelfolkson: It helps to realize that transactions are abstract data structures with a lot of complex structure in them (inputs, outputs, witnesses, stack items, ...). The traditional "network protocol raw serialized" view of a transaction is just one way of representing it, and isn't actually used internally except for storing on disk and transmitting over the network.