The PR branch HEAD was 703d9257db at the time of this review club meeting.
Notes
Bitcoin Coreās RBF policy
enables unconfirmed transactions to be replaced by conflicting transactions (ādouble spendsā) under certain
conditions. If these conditions are met, nodes will replace the transaction
in their mempool and relay the replacement transaction to their peers.
The default policy requires opt-in BIP 125 signaling:
Only original transactions that signal
replaceability (using the nSequence field on one of its inputs) are subject to replacement.
If the original transaction didnāt signal replaceability, the replacement transaction
will be neither accepted nor relayed.
For L2 protocols, the necessity to opt-in to RBF poses DoS problems, see
this mailing list post
for a summary of research.
Therefore, it has been suggested to make full-RBF possible (removing the necessity to opt in).
As a first step, PR #25353 added an optional
-mempoolfullrbf parameter to Bitcoin Core, which is disabled by default.
If the node operator enables this, the node will ignore the signaling (but will still adhere to other RBF rules).
This PR goes one step further by implementing a preferential peering solution for peers that
have -mempoolfullrbf enabled. These peers would now advertise a full-RBF policy using service flags
and make additional automatic outbound connections to peers that also support full-RBF.
What network-level conditions must be fulfilled for full-RBF to āworkā, i.e.,
facilitate the propagation of transactions that replace others not signaling BIP 125?
Is it necessary that every node or the majority of nodes need to support it?
This PR currently suggests to make 4 additional connections to full-RBF peers (1 in an earlier version).
What should be considered when picking this number? What are the downsides of having
too few / too many connections?
What happens if service flags (such as NODE_REPLACE_BY_FEE) a peer tells us in
their version message are different from the service flags we had saved in AddrMan?
Is the logic different when we learn from an addr message instead from the peer
themselves? Does it matter if the updated entry has less or more service flags than the old one?
(Hint: Look at AddrMan::AddSingle
and AddrMan::SetServices_)
With this in mind, do you think that false signaling of a NODE_REPLACE_BY_FEE service flag
could be problem? Could it be detected and punished?
Which of the following ways to proceed do you prefer and why:
Preferential peering (this PR)
Changing the default to -mempoolfullrbf = 1
Status quo (leave it up to users to actively pick -mempoolfullrbf = 1)
<larryruane_> we already have fullrbf functionality; this PR lets us have a better chance to connect to other fullrbf peers (instead of it being just luck)
<theStack> concept ACK, given the assumption that full-rbf is important (didn't go over the mailing posts explaining the exact reasons for the need in detail...)
<lightlike> What network-level conditions must be fulfilled for full-RBF to āworkā, i.e., facilitate the propagation of transactions that replace others not signaling BIP 125? Is it necessary that every node or the majority of nodes need to support it?
<theStack> not sure if this was the intention of the question, but one of my initial thoughts was, that at the very least the miners have to support it, otherwise the replaced txs will never end up in blocks
<stickies-v> a sufficient amount of nodes in the network need to have at least 1 full-RBF-route to a sufficient amount of miners, so definitely no need to have majority of nodes required
<Kaizen_Kintsugi_> I think the majority, if you are surrounded by nodes that aren't doing RBF, your transaction wouldn't be propagated by them, correct? I believe this would open up a subtle eclipse attack vector with enough plausable deniability.
<larryruane_> did someone do some simulation? that would be helpful -- IF you have a realistic model of network topology (that's the hard part I would think)
<larryruane_> perhaps a subtle (or incorrect!) point: if the miners _always_ accept higher feerate replacements, always, then would they be setting themselves up to be DoSed?
<lightlike> yes, I'd say that from a network perspective, all full-RBF connecting nodes (including the miner's nodes) should form a cluster, so that there is some path from each node to a miner.
<glozow> i suppose this can also be achieved if people in the community running full RBF nodes connect to each other manually, and at least 1 of these nodes is a miner
<ariard> glozow: there is also a centralization effect of the full-rbf topology as you're likely to rely on a social communication channel like irc, reddit, a gist, ...
<lightlike> so in my simulations I got the result that without any preferential peering ~10-15% of supporting nodes would be necessary (which is not a lot, my intuition was expecting more like 30-40%).
<lightlike> It seems unrealistic to me that that many users would choose an optional flag (at least without some big social media campaign or something...)
<glozow> ariard: yeah for sure. but also, you can probably trust your buddy on irc to run a "true" full rbf node more than you can trust a peer on the p2p network advertising NODE_FULL_RBF
<Kaizen_Kintsugi_> Hey lightlike, do you have a link to your simulation code? I'm curious of how a sim is built in bitcoin. Do you just use the functional testing framework?
<instagibbs> Interesting to note that it doesn't necessarily preferentially "Activate" based on a node's economic footprint.... which means sybils may be tempting...
<sipa> i have a question: is the goal of this PR to (a) make "signal-less RBF" work for people who turn on the option, so they themselves can perform such transactions (b) to have the network "ease into" full-RBF relay if people turn it on, so it's easier to later argue that fullrbf can be made default, or something else?
<ariard> glozow: yeah depends how you construct the social communication channel, if the full-rbf peers listed are comming from web-of-trust (and there i agree with you) or it's super liberal in listing
<larryruane_> Kaizen_Kintsugi_: I *think* the reason it wasn't always default is that it makes unconfirmed transactions less reliable ... the receiver can't know if it will be replaced, so doesn't trust it as much ... without RBF, the receiver can have a little more confidence that the tx will get mined
<ariard> sipa: so yes for a) the goal is to make "signal-less RBF" work for node opeators, without the additional work to do manual discovery of other full-rbf peers
<ariard> about b) there is the idea of actually letting the network of nodes, and each individual operator, express a preferrence for full-rbf or not, without the project turning on a default
<instagibbs> imagine a coinjoin, Alice races all other joiners with a non-signaling tx double-spending said coinjoin, now you might get stuck without seeing why, and replacements don't seem to work(except sending coin "back to self" to cancel)
<_aj_> ariard, sipa: i think the scenario is that you post a pre-signed commitment tx A, with low or 0 fees, and then an attacker announces a non-RBF tx B that supplies some fees (enabling relay) but not enough to get mined; at which point you can't replace A (because you don't have a different version of it) and can't replace B (because it's not RBF-opt-in, and doesn't inherit A's RBF-ness)?
<lightlike> sipa: if only people who care set the flag, and that number is in the low % of nodes, their transactions probably won't get relayed to a miner.
<ariard> sipa: so since #25353, those who care about the ability to replace transactions can do it so, however for the replacement to be effective on the p2p network wise, I think you need propagation paths to the miners, and a subset of them turning on the option too
<michaelfolkson> This PR feels like a stepping stone to turning on the default. Is there a strong enough argument for needing this stepping stone? I'm not sure
<ariard> note, the propagation of non-RBF tx B should be anterior to the pre-signed commitment tx A, which I believe is achievable by an attacker by mass-connecting and bypassing the privacy-preserving relay timers
<lightlike> This PR currently suggests to make 4 additional connections to full-RBF peers (1 in an earlier version). What should be considered when picking this number? What are the downsides of having too few / too many connections?
<sipa> I'm not sure why that number is acceptable. If 12 outbound connections is acceptable, we should always make them. If they're not, we shouldn't make them with or without -mempoolfullrbf.
<ariard> michaelfolkson: sure, we might have a number of node operators wishing to stay on opt-in RBF as a default, the idea of having automatic preferential peering you let of community of nodes operators express their own prefs
<ariard> sipa: i think you have two questions, a) what should be the sufficient number of automatic outbound connections to have efficient propagation paths and b) is that sufficient number acceptable from a inbound slots resources consumptions viewpoint?
<lightlike> I think one problem with everyone making 12 connections is that we don't have enough inbound capacity for that. If just a few nodes (say <5%) have fullmempoolrbf enabled and do this, it might be less of a problem.
<sipa> I can see the rationale for āaddingā connections rather than just preferential peering, as this means you don't get reduced connectivity to the rest of the network... but I don't think it's acceptable to just increase load on the network because of this.
<sipa> ariard: I don't have a strong opinion on the number 4, or how this peering is done. But I don't think we should just increase the number of connections just because. If 4 extra connections (or whatever you pick, even 1) is acceptable, why not make them always?
<ariard> glozow: yeah it was suggested to me last year by harding, iirc it didn't fix the DoS issue as the replacement timeout is in fact the DoS delay offered to the attacker
<Kaizen_Kintsugi_> Is it reasonable to set a parameter that specifies a percentage of the operators connections to be of their preference, in this case full-rbf.
<ariard> _aj_: i think this is how it should work, as you only connect to service bit 26 peers, if the node operators are okay with this usage of their inbound slots
<sipa> There is no way a node can prove that it's a full RBF peer, so you can't disconnect them if they turn out to not be a full RBF node while you though they would be.
<lightlike> What happens if service flags (such as NODE_REPLACE_BY_FEE) a peer tells us in their version message are different from the service flags we had saved in AddrMan? Is the logic different when we learn from an addr message instead from the peer themselves?
<ariard> sipa: so if I understand correclty your point, the full-rbf peers should be deduce from the overall outbound connections budget we already have (the 8 outbound full-relay and the 2 outbound block-relay-only) ?
<glozow> yeah exactly, our outbound slots are precious, so I'm not sure how i feel about preferring a type of outbound connection that we can't verify is legit
<sipa> Hmm, yes, if it's the case that we disconnect when we attempt to connect to fullrbf, but the peer then tells us they're not fullrbf somehow, then _aj_'s devil's advocate argument works.
<_aj_> sipa: that said, saying "connect to 4 random peers, 2 blocks-only peers, and the remaing 4 outbound connections must be full-rbf" seems like a better policy?
<ariard> sipa: well you could have automated replacement probing logic with GETDATA(replacement_txid), though somehow are we already doing assumptions by "trusting" the version announced by our peers, and the service supported?
<larryruane_> lightlike: "Is the logic different ..." yes, If we receive a version message from a node directly, we simply set our cache of its service bits directly.... if we hear about the node indirectly (addrman), we OR in the service bits
<larryruane_> I think that makes sense because the addr message that we receive could be out of date, so treat it as if it MIGHT have the flag enabled; we'll find out for sure when we connect
<ariard> glozow: well as it doesn't remove the grief, the full-rbf node operators wouldn't have an incentive to turn it on, I think it make it harder to build economic majority
<glozow> ariard: but probing doesn't work either, what if they increased their incremental relay feerate and rejected the tx for a fee reason? we can't go around disconnecting peers for not having the same txns as us
<lightlike> Next q: With this in mind, do you think that false signaling of a NODE_REPLACE_BY_FEE service flag could be problem? Could it be detected and punished?
<sipa> ariard: tx relay policy being unenforcable is a reason to not bother with any of this and just making -mempoolfullrbf default at some point, IMHO. It's weird to have a service flag for just a relay policy. Using this approach as a stepping stone to appease politics "but look it's already deployed and works" doesn't mean much: *of course* it'll work for nodes that turn this on. Doing this just to create effectively a secondary P2P network with fullrbf
<sipa> Kaizen_Kintsugi_: Yes, BIP133. But that's the other way around: it is telling other nodes "don't bother sending me txn with fee below Y, because I'll just discard them anyway".
<ariard> _aj_: from petertodd exp, apparently there wasn't evil full-rbf back in the days of 2015/2016 when actually that change was far more contentious
<lightlike> I think there are different ways of false signaling: Nodes that don't want full-RBF to work should (game-theoretically) false signal full-RBF, so that others looking for preferential peers will connect to them.
<ariard> glozow: sure, i think we can never have absolute certainty of transaction acceptance at equivalent policy and resources setting (same mempool size) just becaouse you might have seen transactions, not seen on my side
<ariard> sipa: IMHO, this is where I'm differing in the sense that might have in the future controversial or not-clear-best-trade-off policy rules, adopting the release practice of offering options to node operators let us better accomodate an increasing variety of Bitcoin applications like L2, with different requirements
<_aj_> so if the idea is "have a service bit, so that we can see how many people turn this feature on" and then say "oh, it's reached x% of the network and miners are mining it, we'll make it the default" -- there's less incentive for opponents to false signal support
<lightlike> also, there is the possibility of someone spamming the node with existing legit addrs, but adding the FULLRBF service bit to the existing legitimate sevice flags (so other nodes would add it in therir addrman). If that happens, nodes might have problems to find legitimate full-RBF peers because everyone is full-RBF.
<larryruane_> davidjumberj: that's a great question, the only thing I can think of is in case there's some attack or DoS that no one anticipated, so may be better to go slowly?
<ariard> _aj_: yes this is the idea, being able to observe in Y time how many X% of the network have turn it on, without us enforcing a default on our users, not necessarily matching their application requirements
<instagibbs> If an opt-in system goes forward and double-spending because easy(we can measure this?), then to me that's a non-rejection of the idea, and can become standard
<lightlike> sipa: is it known if miners actually have an opinion on this? I'm afraids some might just lazily permit full-RBF as a reaction of bitcoin core making it the default?
<sipa> _aj_: Yes, that's what made me agree above with your devil's advocate argument. If the code does drop connections to intended fullrbf peers, which turn out to not be fullrbf peers (by their own claims), then my argument about increased resource usage goes away.
<ariard> _aj_: even if you enforce correspondence between version and addr service bits, the actual service offered by the service bits might be silently dropped or buggy by your peer
<_aj_> glozow: the problem is others might say "fullrbf means our business will effectively shut down, and there'll be less bitcoin tx volume, so you'll make less money"
<glozow> _aj_: I agree that's a concern, but think there are fewer and fewer businesses who absolutely cannot survive without relying on zeroconf. Or at least hope so š
<sipa> _aj_: It could be a separate message, or looking at the service bits they send in VERSION. I'm not sure if the latter is always reliable (do we always set them? even when we think we're not reachable etc)?
<ariard> instagibbs: "they would never know about protocol updates", well in the future miners might run multiple mempool, one for each RBF policy designable, as the economic efficiency of a RBF policy can be function of the transaction order of acceptance, i think