The PR branch HEAD was c27864f at the time of this review club meeting.
Notes
Background
Attendees should familiarize themselves with Bitcoin Coreâs Replace by Fee (RBF)
policy. These
notes will refer to Bitcoin Coreâs rules (not
BIP125âs
rules) by number.
A package is an ordered list of transactions, representable by a connected Directed Acyclic
Graph (a directed edge exists between a transaction that spends the output of another transaction).
Package CPFP describes a policy enabling a child transaction to pay for a parent transaction
when submitted together as a package, even if the parent does not meet all fee requirements on its
own. Package CPFP allows L2 protocols to sign transactions with a low (or zero) feerate, and then
add fees at broadcast time, even if the mempool minimum feerate rises above the presigned
transactionâs feerate. Package CPFP was discussed in a previous review club meeting.
Package RBF describes a policy enabling a child to pay for replacing transactions its parent
conflicts with when they are submitted as a package. (Package CPFP is a prerequisite for this). The
main use case of Package RBF is to allow LN commitment transactions (which conflict with each other
but whose fees cannot be changed) to replace each other in mempools using fees added at broadcast
time using children attached to anchor outputs.
A Pinning Attack is a type of transaction relay censorship in which the attacker takes advantage of mempool policy
to prevent a transaction from being mined or entering a mempool. An introduction to mempool policy and pinning attacks
is transcribed
here.
A âv3 transactionâ refers to a transaction that has its nVersion field set to 3. These types of
transactions are currently nonstandard in Bitcoin Core.
PR #25038 originally only implemented package RBF based on a simple
extension of Bitcoin Coreâs replacement policy. However, after the realization that the utility of package RBF would be
nullified by RBFâs pinning problems, development effort shifted to fixing RBF in general. As such, the scope of the PR
grew to include v3 as well.
The high-level goal is to make competition for block space a purely fee-based market. More
specifically, if two parties are trying to get their conflicting transactions confirmed, the one
who broadcasts the transactions that are most profitable to mine should win, not the one who
broadcasts first or adds some specially-crafted, low-fee garbage transactions. Here are some of the
worst RBF limitations today:
Pinning through absolute fee rules (aka âRule 3â
or âRule 4â Pinning): RBF rules require the replacement transaction pay a higher absolute fee than the aggregate fees paid
by all original transactions. This rule seems to be the most
headache-causing.
Suppose Alice and Mallory have presigned transactions A and M, respectively, which conflict with one another
(e.g. commitment transactions for an LN channel together). Mallory broadcasts M first and can increase the
fees required for Alice to replace M by:
(1) Attaching transaction(s) that descend from M and pay a feerate too low to fee-bump M through
CPFP. For example, assuming the default descendant size limit is 101KvB and M is 1KvB paying a
feerate of 2sat/vB, adding a 100KvB, 2sat/vB child increases the cost to replace M by 200Ksat.
(2) Adding a high-fee descendant of M that also spends from a large, low-feerate mempool transaction,
C. The child may pay a very large fee but not actually be fee-bumping M if its overall ancestor
feerate is still lower than Mâs individual feerate. For example, assuming the default ancestor size
limit is 101KvB, M is 1KvB paying 2sat/vB, and C is 99KvB paying 1sat/vB, adding a 1KvB child of
M and C increases the cost to replace M by 101Ksat.
Pinning through package limits: All transactions admitted to the mempool must stay within package limits; no ancestor
set or descendant set may exceed 25 transactions. Additionally, Rule 5 prohibits a replacement
that would cause the eviction of more than 100 entries.
When a candidate transaction would replace mempool transactions, it may also decrease the
descendant count of other mempool entries. Since ancestor/descendant limits are calculated
prior to removing the would-be-replaced transactions, they may be overestimated.
Also see Single-Conflict RBF Carve Out.
If a transaction conflicts with multiple mempool entries, even if each entry is within the 25-descendant
package limit, it is possible to reach the Rule 5 limit. For example, conflicting with 6
transactions with 20 descendants each.
No increase in incentive compatibility required: Theoretically, any replacement transaction should
confirm faster than the one it replaced; a rational user would not intentionally pay more fees to
have their transaction confirm later. However, there is currently no rule to enforce this. As a
result, all transactions signed with SIGHASH_ANYONECANPAY are vulnerable to being replaced by a transaction
that will confirm later than the original.
Rule 6
was originally enforcing this, as the âincentive compatibility scoreâ was previously just the
feerate of the transaction. However, with the current ancestor set-based selection algorithm and
possible package topologies, it isnât possible to implement a DoS-resistant way of calculating
these scores (it potentially requires using every entry in the mempool, see
this explanation
if you are interested in more details).
Ancestor BIP125 signaling transactions does not imply replaceability: Any descendant of an
in-mempool transaction which signals replaceability is also replaceable because
it will be evicted if its ancestor is replaced. However, if the descendant is not signaling BIP125
explicitly, it cannot be directly replaced. A transaction that only conflicts with the descendant,
and not the BIP125-signaling ancestor, will be rejected.
Transactions must meet RBF fee rules on their own: Package RBF (see definition
above) is not currently possible. Package RBF would enable, for example, conflicting LN commitment
transactions (which tend to have fees that are too similar to replace one another) to replace each
other utilizing fees from a fee-bumping child.
A larger list of RBF limitations was discussed last year on this mailing list
post and
gist. Various proposals to amend or rewrite RBF
policy were discussed on those threads. The discussions resulted in this v3 proposal to address most issues. Additional
RBF improvements (which do not conflict with v3) are also being considered.
V3 Policy
Package limits exist to limit the
worst-case computational complexity of mempool operations such as block template assembly and new transaction
validation. However, current limits still allow huge clusters of transactions to exist in the mempool.
For example, Xekyo has tweeted clusters of 219
and 881 transactions found in a default mempool:
One diagnosis of these RBF limitations is that current mempool policy is far too permissive in the
possible package topologies it accepts. The reason we cannot add an RBF rule comparing incentive
compatibility scores is that calculating them involves, at minimum, looking at its cluster (since
any transaction in the cluster may impact its incentive compatibility score), and there are no
limits on how large a cluster can be. In fact, the entire mempool could be one cluster.
Additionally, Rule 3 pinning is possible precisely because a counterparty has the freedom to attach
transactions to impact the incentive compatibility of the shared transaction.
The simplest mempool policy would be to never allow transactions spending unconfirmed UTXOs, i.e., a maximum package
size of 1. This doesnât work because L2 protocols require the ability to spend unconfirmed outputs, but a package of 1
parent and 1 child is enough: the presigned transaction plus a child attaching fees at broadcast time.
Why allow such crazy clusters of transactions into our mempool if we cannot properly track them or assess their
incentive compatibility afterward, especially if there is no use case beyond pinning attacks?
The philosophy behind v3 is to equalize what
transactions the mempool permits with what it can feasibly handle, while enabling L2 use cases. In a v3 world, cluster
size is limited to 2. This fact enables us to, for example, add an incentive compatibility rule to RBF without
potentially needing to iterate through more than 2 transactions.
A v3 transaction signals replaceability, even if it does not signal BIP125 replaceability.
Any descendant of an unconfirmed V3 transaction must also be V3.
A V3 transactionâs unconfirmed ancestors must all be V3.
A V3 transaction cannot have more than 1 unconfirmed descendant.
A V3 transaction that has an unconfirmed V3 ancestor cannot be larger than 1,000 virtual bytes.
A V3 transaction cannot have more than 1 unconfirmed ancestor.
Notice a few nice properties of v3 packages and transactions (from most obvious to least obvious):
A v3 transaction in mempool cannot have more than 1 descendant.
A v3 transaction in mempool cannot have more than 1 ancestor.
When a v3 transaction is being replaced, it has at most 1 descendant. That descendant adds no more than 1,000vB to what needs to be evicted.
When the descendant of a v3 transaction is being replaced, there must be exactly 1 replacement transaction and 1 to-be-replaced transaction.
When a v3 transaction is being replaced, it is the sponsor of either 0 or 1 0-fee parents.
There is no difference between a v3 transaction having âexplicitâ and âinheritedâ replaceability signaling.
The incentive compatibility score of a transaction is equal to the minimum between its ancestor feerate and individual feerate.
When the descendant of a parent v3 transaction is being replaced, the parentâs descendant count does not change, and its descendant size changes by the difference between the replacement and to-be-replaced transactions.
RBF carve out is not needed.
Given an unconfirmed v3 transaction of size s paying fees f, a maximum-size child paying the same feerate pays f/s * 1,000 in fees.
Further work that may enable more benefits:
The Ephemeral Outputs proposal builds on top of v3, offering an
alternative to SIGHASH_GROUP, with
most of the features and a policy-only changeset.
Ephemeral outputs may be used to enable Eltoo, which also
hinges on the resolution of these RBF limitations.
As v3 and package RBF would allow counterparties to replace each othersâ commitment transactions, just a single anchor
output per commitment transaction could be sufficient. This may eventually allow the removal of
CPFP carve out.
What is the difference between a transaction that âexplicitlyâ signals BIP125 and one that âinheritsâ BIP125
signaling? Why is it impossible for a v3 transaction to be one but not the other?
Why should there be a rule to check whether a replacement transation is more incentive compatible to mine?
Is min(package feerate, individual feerate) an accurate incentive compatibility score for v3 transactions? What
about in general? (See CheckMinerScores()implementation).
Imagine that there are two conflicting transactions, txA and txB, both 2,000vB. We really need one of them to confirm
immediately, but it doesnât matter which one. A malicious counterparty has already broadcast transaction txB which
pays 10,000sat in fees (5sat/vB). We also know that itâs guaranteed (just pretend, ok?) that anything above 20sat/vB
will be mined immediately, while anything below 20sat/vB will not.
Letâs say txA and txB are non-v3 transactions. What fee can we put on txA to guarantee that either txA or
txB will reach a package feerate of 20sat/vB? (Hint: txA needs to replace txB and any descendants it may have.
In the non-v3 world, txA can have up to 99KvB of descendants. What is the maximum fee the counterparty can
attach to descendants of txB without bumping it to 20sat/vB?)
Now imagine txA and txB are both v3 transactions. What fee can we put on txA to guarantee that either txA or txB will
reach a package feerate of 20sat/vB? (Hint: in the v3 world, txA cannot have more than 1,000vB of descendants).
If all mining nodes on the network are running with this v3 policy, while none of the non-mining nodes are, what happens?
If 10% of nodes on the network are running with this v3 policy, while we havenât upgraded our node yet, what happens?
What about 99% of nodes?
If we were running a business that accepted unconfirmed transactions as payments, what changes should we make so that our wallet correctly tracks v3 transactions?
Who might be interested in using v3 transactions? Who probably wouldnât be interested?
If there are some wallets/users/applications that use v3 while others donât, is there a privacy issue (i.e. people
can fingerprint which wallet likely created a transaction by looking at its version)?
After the addition of v3, all non-v3 transactions are still subject to the existing limitations and pinning attacks.
Wouldnât it be safer to enforce these rules for all transactions on the network?
V3 limits each transaction to 1 parent or 1 child (2 generations only), and perhaps that seems
restrictive. Letâs consider an alternative set of rules that allows each transaction to have 2
parents or 2 children (a transaction may have up to 2 children or up to 2 parents. They cannot have
both an unconfirmed parent and an unconfirmed child, so 2 generations only) - what would be the
maximum cluster size?
Why not limit the size of all v3 transactions to 1,000vB or something similarly small (Hint: what property of LN
channels depends on standard transaction
weight)?
Implementation
Why does ApplyV3Rulescheck whether the transaction conflicts with any of its ancestorsâ children? What happens if you remove this check?
V3 ancestor/descendant limits are stricter than the default mempool limits. Do we need to call both
ApplyV3Rules
(which enforces v3 ancestor/descendant limits) andCalculateMemPoolAncestors()
(which enforces ancestor/descendant limits)? Why or why not?
V3 rules are added to the filtering function passed to removeForReorg() in Chainstate::MaybeUpdateMempoolForReorg.
Why do we need to check v3 rules in a reorg?
Is CTxMemPool::removeForReorg() the appropriate place for this check? Can you think of an alternative place to add this check?
How does
CheckMinerScores determine whether one transaction or package is more incentive compatible to mine than another? Is this function 100% accurate for v3 transactions? What about for non-v3 transactions?
V3 restrictions suck! Why canât we just replace RBF Rules 3 and 4 with a better rule based on feerate? For example, âreplacement tx must have a feerate 2x higher than each of the transactions itâs replacing.â
Why not allow packages with multiple parents and 1 child in v3?
Theoretically, if the mempool is not full, the maximum number of transactions that may be removed in a replacement is 100 (due to Rule 5). After this commit, what is the new limit?
<glozow> I wrote up questions but it's highly unlikely we'll get through all of them. Also the goal here is to learn, so please feel free to ask your own questions whenever you like.
<codo> Using the notes as a guide I spent a lot of time catching up on background knowlegde (what are pinning attacks, watch old presentation, read doc/policy/* on master, what is nVersion, broaden git knowledge, ...). I will lurk and see how much of the conversation I understand.
<LarryRuane> Hey really quick meta github type question, if I may ... Does a PR being in "draft" status mean it's going to change a lot so hold off reviewing? Or does it tell the maintainers not to merge it yet (but what's there is good to review)? I've seen both interpretations
<glozow> larryruane: I think "draft" means "not mergeable" and sometimes "not reviewable." I put PRs in draft when the depend on other PRs, or if there's a bug in it I haven't fixed yet
<glozow> and yes, like stickies-v mentioned, I think usually reviewing it = concept and approach. I wouldn't leave a comment like "hey you should rename this variable" on a draft PR
<LarryRuane> at a very high level, I would say that without V3 (as things are currently), there are a lot of DoS potentials; V3 is trying to close them
<stickies-v> we're trying to make it easier for (mostly) off-chain protocols to ensure being able to quickly confirm on-chain if necessary, and v3 does that by reducing the complexity of allowed (unconfirmed) transaction clusters
<glozow> LarryRuane: d33r_gee: stickies-v: yep, I agree with these descriptions. The goal is to create a policy that's DoS-resistant and makes it more feasible to assess the incentive-compatibility of transactions. If adopted by most nodes, it should close pinning attacks which grief l2 protocols.
<pakaro> currently when LN-transactions settle on chain, the fee-rate is set when the anchor tx was first signed but unpublished. rbf is a solution, but currently vulnerable to tx-pinning attacks. v3's are non-standard txs that preclude tx-pinning [hopefully]
<glozow> abubakar: I think you're thinking of Full Rbf. V3 is another way of opting in to replaceability. It does not change the fact that RBF policy requires opt-in.
<LarryRuane> curious about one thing, I was initially surprised that we could even bump the version number! Are we doing that because we already used `nSequence` "hack" for BIP125 indication? Another way to ask, could RBF BIP125 have bumped the version number instead of using `nSequence`?
<glozow> LarryRuane: good question. I used nVersion instead of nSequence because I could use something that was currently non-standard. It's hard to ensure apps/protocols aren't already reserving nSequence numbers for things.
<glozow> abubakar's point, though, brings us to Question #1: What is the difference between a transaction that âexplicitlyâ signals BIP125 and one that âinheritsâ BIP125 signaling? Why is it impossible for a v3 transaction to be one but not the other?
<theStack> "explicit" signaling: one of the tx's inputs have an nSequence < 0xfffffffe (see `SignalsOptInRBF`); "inherited" signaling: one of the tx's ancestors txs shows "explicit" signaling; in v3 world we just always signal replacability
<LarryRuane> glozow: makes sense... and if old (pre- these PRs) see a v3 tx in a block, they consider it valid (probably don't even care about the version number?)
<glozow> theStack: correct! And yes, in v3, you can't spend from an unconfirmed v3 without also being v3. So there is no way to inherit but not explicitly signal.
<glozow> LarryRuane: yes, there is no change in consensus. But in policy we want to strictly loosen rules. Otherwise we could accidentally censor transaction relay for an application. So either we really really make sure nobody is using it currently, or just pick something that's nonstandard today. In a sense, we always want consensus changes to be soft forks, but policy changes to be "hard forks."
<LarryRuane> let's say someone submits a NON-v3 that spends an unconfirmed v3 ... it's not accepted into the mempool, but depending on timing, if its unconfirmed parent happens to get mined, then this non-v3 can be accepted -- that's interesting i think
<glozow> abubakar: yes, a non-v3 transaction opts in by setting one of is nSequence numbers to a BIP125-signaling number. A v3 transaction is free to do this too. Ancestors do not inherit anything.
<glozow> I'm going to throw out the next question but again feel free continue asking your own. Why should there be a rule to check whether a replacement transation is more incentive compatible to mine?
<LarryRuane> because if we don't do that, miners may run custom software that IS incentive compat, and then miners' mempools and the rest of the full nodes mempools would diverge?
<glozow> LarryRuane: yes, it's normal for mempool acceptance to depend on the chainstate. Similar to a transaction that spends 25 just-confirmed transactions. Or even a transaction that spends a 1-block relative timelocked output that just confirmed.
<d33r_gee> q2:Â it is important to ensure that the replacement transaction that replaces an existing unconfirmed transaction offers a higher fee so that it is more attractive to miners and has a higher chance of being included in the next block.
<LarryRuane> and in the scenarios both of us mentioned, if a tx is currently non-standard but MAY become standard soon, we don't hold onto it in an orphanage or something, do we? We just drop it immediately?
<glozow> stickies-v: yeah, it would be redundant to be both v3 and signal, but harmless. I imagine it would happen because wallets are automatically setting their nSequence to signal BIP125, and then they add support for v3 and there's no reason to change the former default
<glozow> d33r_gee: yes, that's part of the answer! but, rewording the question a bit, assuming the replacement tx always increases the overall fee and feerate of the mempool, would it be ok if the replacer would be selected later than the replacee?
<stickies-v> abubakar: in addition to pakaro 's answer - replacement rules require the new transaction to pay for all descendants too, so the more descendants allowed, the more expensive it can become to replace a transaction
<glozow> We can answer this question by asking "is there ever a scenario where you would want to pay *more* fees for a transaction to confirm *slower*?"
<pakaro> stickies-v how do descendants and unconfirmed parents relate? In my understanding, a v3 tx can only have 1 unconfirmed parents...To me that means that, inversely, a parent can only have 1 descendant..so how do we get multiple descendants? Is it that multiple-descendants exist in situations where the v3 was not included, and then the design is that v3 transactions come in later, and _those_ can only have 1 descendant?
<michaelfolkson> glozow: You mean like ensuring a child transaction was in a different block to its parent rather than in the same one? Probably but can't think of a scenario...
<stickies-v> pakaro: I was talking about "descendants" in terms of total size (vbytes) here, not count. sorry for the confusion. if we allow only a single descendant, but it can be a very large descendant, that can become costly again
<michaelfolkson> Maybe if you wanted to wait and see what other parties did and then depending on that RBFing the parent so the child was no longer valid...
<glozow> LarryRuane: bingo! Since we don't require the replacer to be more incentive compatible to mine than the replacee, attackers can pin transactions by replacing them and adding low-feerate ancestors. Of course, they have to be able to edit the transaction and bring in more inputs. But this is the case with SIGHASH_ANYONECANPAY transactions (of which there are thousands every day).
<d33r_gee> glozow hmmm... yes the replacer could be selected later than the replaccee if the replacee is time-sensitive (e.g. it is a transaction needed for a time-sensitive application), it may be important to prioritize the replacee over the replacer even if the replacer has a higher fee and feerate (still wrapping my head around those use cases)
<stickies-v> d33r_gee: the network can't have an understanding about what's time-sensitive or honest etc, so I think in practice we only really have the fees to look at
<michaelfolkson> d33r_gee: Depending on the protocol (Lightning, vaults etc) part of security model is you watch the chain for an attacker broadcasting a transaction they shouldn't and respond. Being pinned prevents your a speedy response
<theStack> no v3 txs would ever reach a miner, since all non-mining nodes reject those form the mempool. so i guess the answer to that question would be "nothing" :p
<glozow> theStack: correct! also, if a miner mines v3 transactions, everybody would still accept them. the point of this question is "it's policy, not consensus"
<codo> For LN to profit from this, a large part of the network should see V3 as standard, right? If so: won't it take some time (like a year) before LN channels based on V3 will be opened?
<glozow> Imagine that there are two conflicting transactions, txA and txB, both 2,000vB. We really need one of them to confirm immediately, but it doesnât matter which one. A malicious counterparty has already broadcast transaction txB which pays 10,000sat in fees (5sat/vB). We also know that itâs guaranteed (just pretend, ok?) that anything above 20sat/vB will be mined immediately, while anything below 20sat/vB will not.
<glozow> Letâs say txA and txB are non-v3 transactions. What fee can we put on txA to guarantee that either txA or txB will reach a package feerate of 20sat/vB?
<glozow> Now imagine txA and txB are both v3 transactions. What fee can we put on txA to guarantee that either txA or txB will reach a package feerate of 20sat/vB?
<glozow> So yes :) this addresses "Rule 3 pinning" by effectively setting a more reasonable upper bound on what you might need to pay if they try to pin you this way