Peter Todd https://petertodd.org/ Tue, 04 Nov 2025 11:29:18 +0000 Tue, 04 Nov 2025 11:29:18 +0000 Jekyll v3.9.0 OpenTimestamps and Knots/OCEAN <p>Is <a href="https://opentimestamps.org">OpenTimestamps</a> incompatible with or threatened by the <a href="https://bitcoinknots.org/">Bitcoin Knots</a> fork of <a href="https://bitcoincore.org/">Bitcoin Core</a> and/or the <a href="https://www.ocean.xyz/">OCEAN</a> mining pool?</p> <p>I’m told this question has come up a few times from investors and potential users of OpenTimestamps, so I thought it would be worth answering in a blog post. This post isn’t going to get into the politics of Bitcoin Knot’s transaction relaying policy, or OCEAN’s transaction mining policies. We’re going to stick to the facts of how OpenTimestamps uses the Bitcoin blockchain, what policies Knots and OCEAN currently have, and finally, hypothetical changes to those policies.</p> <p>tl;dr: there is no incompatibility between OpenTimestamps and Knots/OCEAN. Nor is there any way that Bitcoin node operators or miners could prevent OpenTimestamps from functioning, short of extreme levels of censorship. Users of OpenTimestamps have nothing to worry about.</p> <div class="post-toc"> <h1 class="no_toc" id="contents">Contents</h1> <ol id="markdown-toc"> <li><a href="#how-opentimestamps-currently-uses-the-bitcoin-blockchain" id="markdown-toc-how-opentimestamps-currently-uses-the-bitcoin-blockchain">How OpenTimestamps Currently Uses The Bitcoin Blockchain</a></li> <li><a href="#the-mistaken-controversy" id="markdown-toc-the-mistaken-controversy">The (Mistaken) Controversy</a> <ol> <li><a href="#hypothetical-knots-no-longer-relays-op_return-transactions" id="markdown-toc-hypothetical-knots-no-longer-relays-op_return-transactions">Hypothetical: Knots No Longer Relays OP_Return Transactions</a></li> <li><a href="#hypothetical-a-group-actively-attacks-nodes-that-relay-op_return-transactions" id="markdown-toc-hypothetical-a-group-actively-attacks-nodes-that-relay-op_return-transactions">Hypothetical: A Group Actively Attacks Nodes That Relay OP_Return Transactions</a></li> <li><a href="#hypothetical-miners-stop-mining-op_return-transactions" id="markdown-toc-hypothetical-miners-stop-mining-op_return-transactions">Hypothetical: Miners Stop Mining OP_Return Transactions</a></li> <li><a href="#hypothetical-whitelisting" id="markdown-toc-hypothetical-whitelisting">Hypothetical: Whitelisting</a></li> <li><a href="#hypothetical-whitelisting-and-blacklisting" id="markdown-toc-hypothetical-whitelisting-and-blacklisting">Hypothetical: Whitelisting <em>and</em> Blacklisting</a></li> </ol> </li> <li><a href="#summary" id="markdown-toc-summary">Summary</a></li> <li><a href="#footnotes" id="markdown-toc-footnotes">Footnotes</a></li> </ol> </div> <h2 id="how-opentimestamps-currently-uses-the-bitcoin-blockchain">How OpenTimestamps Currently Uses The Bitcoin Blockchain</h2> <p>OpenTimestamps is an efficient, scalable, timestamping protocol. I’ve explained <a href="/2016/opentimestamps-announcement#how-opentimestamps-works">how OpenTimestamps works</a> in detail before on this blog. But in short, it uses merkle trees and commitment operations to timestamp an unlimited amount of data with a single Bitcoin transaction. To succeed in this goal, an OpenTimestamps calendar needs to create a Bitcoin transaction that either contains or cryptographically commits to a single 32-byte hash digest.</p> <p>The <a href="https://github.com/opentimestamps/opentimestamps-server">OpenTimestamps Calendar Servers</a> currently embed these digests directly in an OP_Return output:</p> <p><a href="https://mempool.space/tx/f31dd1b3f64e5f0ea96b4efdd563bd8660aa0f66e3a8e6f5804ae1b4e145f146"><img src="/assets/2025-08-21/mempool-space-tx-f31dd1b3f64e5f0ea96b4efdd563bd8660aa0f66e3a8e6f5804ae1b4e145f146.png" alt="tx f31dd1b3f64e5f0ea96b4efdd563bd8660aa0f66e3a8e6f5804ae1b4e145f146" /></a></p> <p>Since an infinite number of timestamp requests can be aggregated into a single transaction, the absolute maximum number of transactions a single calendar would ever produce is one per block, 144txs/day. In practice they produce significantly less than that due to funding limitations, and the fact that it’s <a href="https://lists.w3.org/Archives/Public/public-blockchain/2016Sep/0076.html">dubious to trust the time fields in block headers to ~10 minute resolution</a> anyway.</p> <p>Since a single Bitcoin block could potentially contain over <em>six thousand</em> timestamp transactions<sup id="fnref:timestamp-tx-capacity" role="doc-noteref"><a href="#fn:timestamp-tx-capacity" class="footnote">1</a></sup>, and there are just four public calendars, OpenTimestamps uses an extremely small percentage of the total Bitcoin blockchain capacity.</p> <h2 id="the-mistaken-controversy">The (Mistaken) Controversy</h2> <p>By default, Bitcoin Knots nodes do not relay transactions containing OP_Return outputs with more than 40 bytes of data. Since OCEAN uses Bitcoin Knots, most blocks created by OCEAN<sup id="fnref:ocean-mempool-policies" role="doc-noteref"><a href="#fn:ocean-mempool-policies" class="footnote">2</a></sup> are similarly limited.</p> <p><strong><em>40 bytes of OP_Return data is more than enough for OpenTimestamps!</em></strong></p> <p>At the moment, there simply is no issue: both Knots and OCEAN will relay and mine the transactions produced by the OpenTimestamps calendars with no issue.</p> <p>Most of this controversy is simply mistaken, caused by a misunderstanding of what Knots/OCEAN actually does. But, it is hypothetically possible that a future version of Knots will further tighten relay policy in such a way as to not relay these transactions. What then?</p> <h3 id="hypothetical-knots-no-longer-relays-op_return-transactions">Hypothetical: Knots No Longer Relays OP_Return Transactions</h3> <p>Suppose that a future version of Bitcoin Knots makes the choice to no longer relay transactions containing OP_Return outputs at all. We’ll also assume that OCEAN no longer mines those transactions. And, for sake of argument, we’ll assume that nearly 100% of nodes choose to run Knots.</p> <p>Does this affect OpenTimestamps? No.</p> <p>At the moment, no released version of Bitcoin Core or any known fork of Bitcoin Core (Knots and Libre Relay) propagates transactions paying a fee-rate less than 1 sat/vB. Yet, at the moment, both of my <a href="https://alice.btc.calendar.opentimestamps.org">Alice</a> and <a href="https://bob.btc.calendar.opentimestamps.org">Bob</a> calendars are producing transactions with sub-1-sat/vB fee-rates. Even though something like 99% of Bitcoin nodes reject these transactions, <a href="https://web.archive.org/web/20250821185756/https://bob.btc.calendar.opentimestamps.org/">they get to miners just fine</a>.</p> <p>As Satoshi said in the initial announcement, <a href="https://satoshi.nakamotoinstitute.org/posts/p2pfoundation/1/">“[Bitcoin] takes advantage of the nature of information being easy to spread but hard to stifle”</a>.</p> <p>Since it only takes a single path to get a transaction — information — to a miner willing to mine it, for an actively maintained operation like the OpenTimestamps calendars, it is exceptionally difficult to prevent transactions from getting to miners by simply running nodes that reject those transactions.</p> <h3 id="hypothetical-a-group-actively-attacks-nodes-that-relay-op_return-transactions">Hypothetical: A Group Actively Attacks Nodes That Relay OP_Return Transactions</h3> <p>Suppose that a group was trying to attack nodes that relayed OP_Return transactions, e.g. by detecting them somehow<sup id="fnref:garbageman" role="doc-noteref"><a href="#fn:garbageman" class="footnote">3</a></sup> and launching DoS attacks against them to flood their internet connections with enough data that the nodes are forced offline. Again, against an actively maintained project like the OpenTimestamps calendars this attack will fail because we can easily mitigate the attack by doing things like submitting timestamp transactions to miners directly, as well as running undetectable, non-public nodes.</p> <h3 id="hypothetical-miners-stop-mining-op_return-transactions">Hypothetical: Miners Stop Mining OP_Return Transactions</h3> <p>What if you just can’t get an OP_Return containing transaction mined?</p> <p>The OpenTimestamps proof format is designed to be flexible. It doesn’t make any assumptions about how exactly a timestamp proof is created; there is no concept of transactions in OpenTimestamps proofs. Rather, a proof is a series of mathematical operations that lead to a Bitcoin <em>block header</em>.</p> <p>That means that the OpenTimestamps calendars can easily switch to other ways of embedding data in Bitcoin transactions. For example, in the past, prior to the creation of the OP_Return mechanism, very early versions of the OpenTimestamps calendar software used <a href="https://github.com/opentimestamps/opentimestamps-server/blob/348ca0b0ee3f9931a5d9ddd7951214aab52a383e/otsserver/bitcoin.py#L71">bare multisig</a> outputs. Even though the transaction format is totally different, those ancient timestamps can be verified by modern versions of the OpenTimestamps software with no issues<sup id="fnref:ots-proof-conversion" role="doc-noteref"><a href="#fn:ots-proof-conversion" class="footnote">4</a></sup>.</p> <p>In this hypothetical circumstance, one of <em>many</em> ways that the OpenTimestamps calendars could create timestamp transactions would be to use the Pay-2-Witness-Script-Hash (P2WSH) address format. Specifically, each timestamp transaction would create a new P2WSH output whose address committed to a multisig script of the form:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>1 &lt;real pubkey&gt; &lt;fake pubkey&gt; 2 CheckMultiSig </code></pre></div></div> <p>The “fake” pubkey is just a 32-byte digest computed by hashing a byte and the actual 32-byte digest that needs to be timestamped, plus the even/odd byte. Being a 1-of-2 multisig, we can still spend the funds later with the real pubkey. An arbitrary 32-byte string has an approximately 50% chance of being a valid secp256k1 pubkey. So with a single extra byte we can just keep trying until we find a valid one. The probability of failing is on the order of \(\frac{1}{2^{256}}\) — much less likely than finding a SHA256 hash collision by accident.</p> <p>Miners can’t block transactions committing to data in this form without making it impossible for many Bitcoin users to spend their funds without prior permission.</p> <h3 id="hypothetical-whitelisting">Hypothetical: Whitelisting</h3> <p>Suppose that all Bitcoin miners go a step further and refuse to mine transactions without prior approval, AKA whitelisting. Can OpenTimestamps survive?</p> <p>Of course, this scenario is getting quite ridiculous: Bitcoin as we know it would simply not exist anymore, as we are discussing a permissioned system that ultimately is no different than conventional banking, or most Central Bank Digital Currency (CBDC) proposals.</p> <p>But yes, <em>even</em> in this scenario OpenTimestamps has a chance: via fancy Elliptic Curve Cryptography tricks, <em>any</em> pubkey or signature can <em>secretly</em> commit to a digest. That means that <em>any</em> transaction could in fact be a timestamp transaction! Anyone approved to create Bitcoin transactions could volunteer to timestamp data for the public calendars, and miners could have absolutely no way of detecting this in advance.</p> <p>While the OpenTimestamps protocol does not currently support this type of commitment operation, a <a href="https://github.com/opentimestamps/python-opentimestamps/pull/14">pull-req by Andrew Poelstra</a> implementing this has been available since 2017 and could easily be added to the protocol if necessary. The actual reason this might be merged would be to save on fees; actually needing this level of censorship resistance is I hope very unlikely.</p> <h3 id="hypothetical-whitelisting-and-blacklisting">Hypothetical: Whitelisting <em>and</em> Blacklisting</h3> <p>What if in addition to all Bitcoin usage being limited to approved, whitelisted, entities miners also revoke (blacklist) the licenses and coins of anyone who is detected making timestamps. Since the public calendar infrastructure is, well, public, it would be hypothetically possible for the organization in charge of approving the use of the Bitcoin blockchain to actively detect and punish all timestamping activity.</p> <p>While I’m sure there is a cryptographic solution to even this scenario — maybe involving zero-knowledge-proofs<sup id="fnref:zk-proof-of-assets" role="doc-noteref"><a href="#fn:zk-proof-of-assets" class="footnote">5</a></sup> or something — at this point I gotta ask, what kind of absurd world are you living in? Why have you allowed authorities to be so draconian as to prevent timestamping, a technology that merely proves things are true?</p> <h2 id="summary">Summary</h2> <p>As long as people continue to maintain OpenTimestamps and the OpenTimestamps public calendar infrastructure, OpenTimestamps is unstoppable.</p> <h2 id="footnotes">Footnotes</h2> <div class="footnotes" role="doc-endnotes"> <ol> <li id="fn:timestamp-tx-capacity" role="doc-endnote"> \[\frac{1000000\frac{\text{vB}}{\text{block}}}{152.25 \frac{\text{vB}}{\text{tx}}} \approx 6568 \frac{\text{tx}}{\text{block}}\] <p><a href="#fnref:timestamp-tx-capacity" class="reversefootnote" role="doc-backlink">&#8617;</a></p> </li> <li id="fn:ocean-mempool-policies" role="doc-endnote"> <p>I say most blocks, because as of writing, OCEAN offers <a href="https://web.archive.org/web/20250821165627/https://www.ocean.xyz/docs/templateselection">four different choices of block template</a>, including Bitcoin Core’s default. Additionally, OCEAN offers <a href="https://ocean.xyz/docs/datum">DATUM</a>, which allows hashpower pointed at OCEAN to do their own block template generation. <a href="#fnref:ocean-mempool-policies" class="reversefootnote" role="doc-backlink">&#8617;</a></p> </li> <li id="fn:garbageman" role="doc-endnote"> <p>See also the <a href="https://gnusha.org/pi/bitcoindev/[email protected]/">Garbageman attack</a> on Libre Relay nodes. <a href="#fnref:garbageman" class="reversefootnote" role="doc-backlink">&#8617;</a></p> </li> <li id="fn:ots-proof-conversion" role="doc-endnote"> <p>That is, after those proof files are converted from the JSON serialization used in my early prototype to the modern binary serialization. <a href="#fnref:ots-proof-conversion" class="reversefootnote" role="doc-backlink">&#8617;</a></p> </li> <li id="fn:zk-proof-of-assets" role="doc-endnote"> <p>An interesting project for a student could be to adapt Adam Gibson’s work on <a href="https://github.com/AdamISZ/aut-ct/blob/master/auditor-docs/privacy-preserving-proof-of-assets.pdf">privacy-preserving proof-of-assets</a> to this problem. <a href="#fnref:zk-proof-of-assets" class="reversefootnote" role="doc-backlink">&#8617;</a></p> </li> </ol> </div> Thu, 21 Aug 2025 00:00:00 +0000 https://petertodd.org/2025/opentimestamps-and-knots-ocean https://petertodd.org/2025/opentimestamps-and-knots-ocean bitcoin opentimestamps knots ocean How Good Are The Widely Used Coinjoin Implementations? <p>I was asked by <a href="https://kruw.io">Kruw</a> to analyze and respond to Yuval “nothingmuch” Kogman’s post<sup id="fnref:kogman-post" role="doc-noteref"><a href="#fn:kogman-post" class="footnote">1</a></sup> on centralized, coordinator-based, deanonymization attacks. In particular<sup id="fnref:samourai-status" role="doc-noteref"><a href="#fn:samourai-status" class="footnote">2</a></sup>, attacks on the WabiSabi protocol used by Wasabi wallet; Kogman was involved in the design of WabiSabi, but “left in protest before its release”<sup id="fnref:kogman-post:1" role="doc-noteref"><a href="#fn:kogman-post" class="footnote">1</a></sup>.</p> <p>Kogman claims that the “this software is not fit for purpose and should not be used unless users trust the coordinators with their privacy”. However, Kogman hasn’t articulated a clear engineering basis for this statement. So I thought it would be worthwhile to do a proper security analysis of what coinjoin is, what kinds of attacks it prevents, and how well the two leading coinjoin implementations — Joinmarket and Wasabi — prevent real world deanonymization attacks.</p> <p>Disclaimer: Kruw is paying me for my time at my usual open-source consulting rate; he runs the <a href="https://coinjoin.kruw.io">most popular Wasabi coordinator</a>. I personally use Wasabi, and indeed, received my payment for this article from Kruw’s Wasabi wallet, to mine.</p> <div class="post-toc"> <h1 class="no_toc" id="contents">Contents</h1> <ol id="markdown-toc"> <li><a href="#background" id="markdown-toc-background">Background</a> <ol> <li><a href="#k-anonymity-sets" id="markdown-toc-k-anonymity-sets">K-Anonymity Sets</a></li> <li><a href="#tor" id="markdown-toc-tor">Tor</a></li> </ol> </li> <li><a href="#notable-coinjoin-schemes" id="markdown-toc-notable-coinjoin-schemes">Notable Coinjoin Schemes</a> <ol> <li><a href="#payjoin" id="markdown-toc-payjoin">Payjoin</a></li> <li><a href="#joinmarket" id="markdown-toc-joinmarket">JoinMarket</a></li> <li><a href="#wabisabi-and-wasabi-wallet" id="markdown-toc-wabisabi-and-wasabi-wallet">WabiSabi and Wasabi Wallet</a> <ol> <li><a href="#round-structure-and-cryptography" id="markdown-toc-round-structure-and-cryptography">Round Structure and Cryptography</a></li> </ol> </li> </ol> </li> <li><a href="#attacks-on-multi-party-coinjoins" id="markdown-toc-attacks-on-multi-party-coinjoins">Attacks On Multi-Party Coinjoins</a> <ol> <li><a href="#sybil-attack" id="markdown-toc-sybil-attack">Sybil Attack</a></li> <li><a href="#targeted-sybil-attack" id="markdown-toc-targeted-sybil-attack">Targeted Sybil Attack</a></li> <li><a href="#address-reuse-after-failed-coinjoins" id="markdown-toc-address-reuse-after-failed-coinjoins">Address Reuse After Failed Coinjoins</a> <ol> <li><a href="#leaking-commonly-owned-input-sets" id="markdown-toc-leaking-commonly-owned-input-sets">Leaking Commonly Owned Input Sets</a></li> <li><a href="#information-extraction-via-invalid-rounds" id="markdown-toc-information-extraction-via-invalid-rounds">Information Extraction via Invalid Rounds</a></li> </ol> </li> <li><a href="#attacking-round-consistency" id="markdown-toc-attacking-round-consistency">Attacking Round Consistency</a></li> <li><a href="#the-k-anonymity-set-of-communication-characteristics" id="markdown-toc-the-k-anonymity-set-of-communication-characteristics">The K-Anonymity Set of Communication Characteristics</a></li> </ol> </li> <li><a href="#final-thoughts" id="markdown-toc-final-thoughts">Final Thoughts</a></li> <li><a href="#footnotes" id="markdown-toc-footnotes">Footnotes</a></li> </ol> </div> <h2 id="background">Background</h2> <p>Coinjoin was first popularized<sup id="fnref:coinjoin-credit" role="doc-noteref"><a href="#fn:coinjoin-credit" class="footnote">3</a></sup> by Gregory Maxwell in 2013. The basic principle is simple: if two or more parties collaboratively create a Bitcoin transaction, the <a href="https://en.bitcoin.it/wiki/Common-input-ownership_heuristic">common input ownership heuristic</a> can be defeated, by the fact that not all inputs to the transaction are owned by the same entity. The simplest possible way to coinjoin is for two or more parties who were already intending to do a transaction to simply concatenate the inputs and outputs of their respective transactions together. Even this simple technique has a small cost savings: the multiple parties get to share the bytes in the transaction header, resulting in a smaller overall transaction.</p> <p>However, this simplicity is lacking in privacy for two main reasons:</p> <ol> <li>An external observer can usually link inputs and outputs based on unique values.</li> <li>Parties within the coinjoin know which inputs and outputs belong to other coinjoin members.</li> </ol> <p>For example, consider the following transaction:</p> <table align="center"> <thead align="right"> <tr class="header"> <th> Inputs </th> <th> Outputs </th> </tr> </thead> <tbody align="right"> <tr><td> 61,836 </td><td> 53,467 </td></tr> <tr><td> 98,902 </td><td> 61,736 </td></tr> <tr><td> </td><td> 45,235 </td></tr> </tbody> </table> <p>If you suspect this were a very simple two party coinjoin, it’s a reasonable guess that the first input and second output are owned by the same person, with the second input going to the first and third.</p> <p>That leads us to our two main threat models:</p> <ol> <li>Passive chainalysis<sup id="fnref:chainalysis-term" role="doc-noteref"><a href="#fn:chainalysis-term" class="footnote">4</a></sup>: An attacker who uses publicly available blockchain data, possibly in conjunction with other data, to attempt to deanonymize transactions through passive analysis.</li> <li>Active (sybil) attack: An attacker who actively participates in coinjoins to gather data that is not publicly available. We can assume active attackers also use passive chainalysis.</li> </ol> <p>Interestingly, based on my off-the-record discussions with current and former employees of Chainalysis and competing companies, real world chainalysis adversaries don’t actually bother to do the proper statistical analysis required to actually deanonymize even the simplest of coinjoins. Indeed, they don’t bother to do proper statistical analysis of anything at all: their products are highly unscientific, and based on “labeling” outputs on what is essentially hunches and primitive heuristics rather than actually figuring out the probability that a given output is associated with a given activity.<sup id="fnref:meiklejohn-methodology" role="doc-noteref"><a href="#fn:meiklejohn-methodology" class="footnote">5</a></sup> I’ve even had a founder of a Chainalysis competitor drunkenly brag to me over dinner that his product was a total scam that didn’t do any real chainalysis at all: the real purpose of his product was to give police cover to throw people in jail, as well as allow exchanges to meet “AML/KYC” checkbox requirements. Chainalysis themselves has gone to great lengths to hide how their product actually works, e.g. in court cases; it’s highly likely that Chainalysis’s product does not in fact work reliably.</p> <p>Conversely, <a href="https://x.com/theragetech/status/1948793372787048928">recent court documents</a> have revealed that Chainalysis ran a Tornado Cash Relayer, presumably in an attempt to gather data on Tornado Cash users. While Tornado Cash is a very different type of technology than coinjoin, if Chainalysis is taking active measures to deanonymize Tornado Cash usage they may also be taking active measures to deanonymize coinjoin implementations.</p> <p>Regardless, whether or not our adversaries are presently scams or not, we should assume competence.</p> <h3 id="k-anonymity-sets">K-Anonymity Sets</h3> <p>Privacy tools are typically analyzed in terms of k-anonymity sets: the set of \(k\) individuals from which an anonymized individual can’t be distinguished from. Monetary applications like coinjoin add an additional element: the amount of value that your value could have come from. This is especially relevant if you are trying to coinjoin larger amounts: the k-anonymity set for larger amounts is smaller, because fewer other k’s had sufficient funds to be a potential source of the funds.</p> <h3 id="tor"><a href="https://www.torproject.org/">Tor</a></h3> <p>The Tor network is an <a href="https://en.wikipedia.org/wiki/Onion_routing">onion routing</a> network. Coinjoin schemes make use of Tor for its anonymity: if Tor nodes fulfil their promise not to keep logs, in most threat models Tor allows coinjoin clients to communicate anonymously. Which is important to the security model of JoinMarket, and critical to the security model of Wasabi.</p> <p>Tor is <em>not</em> decentralized. While a large number of volunteers run individual Tor nodes, the Tor consensus itself — the list of Tor nodes — is run by a centralized set <a href="https://community.torproject.org/relay/governance/policies-and-proposals/directory-authority/">directory authorities</a>, who solely decide who is and is not a Tor node.</p> <h2 id="notable-coinjoin-schemes">Notable Coinjoin Schemes</h2> <p>There’s only three notable, coinjoin schemes that have actually been implemented, and are currently in operation. Each of these schemes uses a fundamentally different approach, with advantages and disadvantages.</p> <h3 id="payjoin"><a href="https://payjoin.org/">Payjoin</a></h3> <p>This is a two party <em>protocol</em>, allowing a payor (sender) to create a coinjoin transaction with the payee (recipient) that they were already intending to pay. This transaction defeats the common input ownership heuristic by combining the coins of payee and payor. Since Payjoin is a protocol, many wallets already support it, including our other two coinjoin implementations, JoinMarket and Wasabi.</p> <p>The <a href="https://github.com/SatoshiPortal/bullbitcoin-mobile">Bull Bitcoin Mobile Wallet</a> (<a href="https://play.google.com/store/apps/details?id=com.bullbitcoin.mobile&amp;hl=en">Play Store</a>) is a good example of when and why Payjoin is advantageous. Developed by the <a href="https://www.bullbitcoin.com/">Bull Bitcoin Exchange</a>, it aims to solve two key problems:</p> <ol> <li>When buying Bitcoin, exchange customers tend to accumulate one UTXO per purchase. Payjoin allows previously purchased UTXOs to be combined with the BTC purchased right now, resulting in less fees spent consolidating UTXOs, without impacting privacy.</li> <li>When selling Bitcoin, the coinjoin transaction saves the exchange fees by combining one or more existing UTXOs with the amount sold. Additionally, in the future payjoin will make it possible to implement <a href="https://bitcointalk.org/index.php?topic=281848.0">cut-through payments</a>, further saving money on fees. And obviously, both parties potentially benefit from an improved k-anonymity set.</li> </ol> <p>Since payjoin is a two party protocol, active attacks are irrelevant: the other party you are payjoining with inherently knows what inputs and outputs are yours. Furthermore, sybil attacks are not relevant: you are payjoining with a known entity you were already planning on transacting with anyway.</p> <p>In practice, payjoins are often distinguishable by the <a href="https://eprint.iacr.org/2022/589.pdf">Unnecessary Input Heuristic</a>, allowing sender and receiver to be guessed based on the assumption that wallets only add the bare minimum number of inputs necessary to perform a payment. This assumption is <em>not</em> always correct, as some wallets do in fact add unnecessary inputs for UTXO management and privacy reasons. Secondly, not all payjoins meet this heuristic. Differences in transaction patterns, e.g. between a Bitcoin exchange and a typical Bitcoin holder, may also be different enough to distinguish the inputs and outputs of both parties. Regardless, the fee savings of payjoin are reason enough to implement it in any on-chain wallet.</p> <p>We won’t discuss payjoin further, as it provides a clear fee-reduction benefit to any on-chain wallet — including coinjoin wallets — with no significant downsides other than implementation complexity. If the entity you are intending to pay on-chain offers payjoin, there is no reason <em>not</em> to use payjoin to pay them.</p> <h3 id="joinmarket"><a href="https://github.com/JoinMarket-Org/joinmarket-clientserver">JoinMarket</a></h3> <p>This is meant to be a taker-maker protocol, in which the <em>taker</em> pays one or more <em>makers</em> to improve the privacy of their transaction by paying the makers to also contribute their inputs and outputs to the transaction; the taker also pays the transaction fees.</p> <p>If makers contributed arbitrary inputs and outputs, of arbitrary value, this wouldn’t usually provide any privacy improvement as maker and taker inputs could usually be distinguished by simply matching them by value. So instead, makers contribute outputs <em>equal</em> in value to the taker’s payment output. The idea is that by having multiple payment outputs of the same value, we’ve achieved a k-anonymity set comprising these multiple outputs.</p> <p>Here’s a very simple example of a JoinMarket transaction that I made for this article, with one taker, and one maker, txid <a href="https://mempool.space/tx/4f112abd2eefe3484a7bbf7c1731f784cba19de677468835145e9c448fb18b7d">4f11…8b7d</a>:</p> <table align="center"> <thead align="right"> <tr class="header"> <th> Inputs </th> <th> Outputs </th> </tr> </thead> <tbody align="right"> <tr><td> 148,798 </td><td> 46,981 </td></tr> <tr><td> 1,448,113 </td><td> 100,420 </td></tr> <tr><td> </td><td> 1,347,800 </td></tr> <tr><td> </td><td> 100,420 </td></tr> </tbody> </table> <p>At first glance, the 100,420 sat outputs appear to have a \(k=2\) anonymity set: there are two of them. But suppose you were the <em>recipient</em> of the first 100,420 sat output. The question for <em>you</em> is where did the money come from? Due to how JoinMarket works, it’s reasonable to assume that I paid you as a taker, and the other party in the transaction is the maker. Since I must be a taker, I must have paid for the transaction, as well as the maker fee.</p> <p>With that assumption, you can easily deanonymize my input by making a reasonable guess at what inputs map to what change outputs, and doing some arithmetic:</p> \[\begin{align} 148798 - 100420 - 46981 &amp;= 1397 \\ 1448113 - 100420 - 1347800 &amp;= -107 \end{align}\] <p>Obviously, the first input is from the taker, as it contributed a net 1397 sats to the transaction, while the second input received a 107 sats maker fee. Which, having made the transaction myself, I can confirm is correct.</p> <p>Even though I paid a 107 sat maker fee, and an extra 698 sats in transaction fees, I got no additional privacy!</p> <p>This issue isn’t limited to simple test transactions either. In most cases, even when multiple makers are used, the taker can be identified by this analysis. The root cause of the problem is that JoinMarket is a market: takers and makers have fundamentally different roles, and thus their inputs and outputs can be distinguished by the fact that the taker is paying the makers.</p> <p>In a sense, the economics of JoinMarket are entirely backwards: in a typical case — where the taker is paying multiple makers — the makers probably receive a privacy improvement by the fact that the decoy outputs have a k-anonymity set of all makers<sup id="fnref:jm-maker-k-anon-set" role="doc-noteref"><a href="#fn:jm-maker-k-anon-set" class="footnote">6</a></sup>. Yet the taker — who paid a non-trivial amount of money for this service — usually doesn’t receive the benefit of improved privacy.</p> <p>I personally was unaware of this issue when I started writing this article. As it turns out, it was first concretely discussed <a href="https://bitcointalk.org/index.php?topic=1609980.00">on bitcointalk</a> almost a decade ago, soon after JoinMarket was first released. However, the significance doesn’t seem to have been fully appreciated.</p> <p>While there could be interesting things to say about other aspects of JoinMarket — like its use of fidelity bonds for sybil protection – it’s main functionality doesn’t work as intended. So we won’t cover it further in this article; I do not recommend using JoinMarket until it is redesigned.</p> <h3 id="wabisabi-and-wasabi-wallet">WabiSabi and Wasabi Wallet</h3> <p>The <a href="https://github.com/WalletWasabi/WabiSabi/blob/1e6deb989f58bc6edce91bc300252d2bed18db30/protocol.md">WabiSabi protocol</a> is a multi-step coinjoin protocol, implemented by the <a href="https://wasabiwallet.io/">Wasabi Wallet</a><sup id="fnref:ginger-wallet" role="doc-noteref"><a href="#fn:ginger-wallet" class="footnote">7</a></sup>. There was also a <a href="https://docs.btcpayserver.org/Wabisabi/">BTCPay Server Plugin</a> that used the WabiSabi protocol. But it is no longer maintained. I’m unaware of any WabiSabi implementation other than Wasabi Wallet. So for this article I’ll refer to “Wasabi” for both the protocol and Wasabi Wallet implementation. Finally, while there existed a previous 1.x version of the Wasabi wallet, as it is now obsolete we will be solely referring to the current 2.x release.</p> <p>Wasabi relies on amount decomposition to achieve a k-anonymity set across multiple users. The privacy of funds deposited into Wasabi is protected by one or more coinjoin <em>rounds</em>, where a (user-configurable) central coordinator brings multiple users together to coinjoin their funds.</p> <p>For this article I created a fresh Wasabi wallet and deposited 516,237sats into it. I then allowed Wasabi to coinjoin those funds using the <a href="https://coinjoin.kruw.io/">https://coinjoin.kruw.io/</a> coordinator using the “Maximize Speed” coinjoin strategy. Here’s my input and outputs from the first coinjoin round, txid <a href="https://mempool.space/tx/7a27c793440396fd0090792e40bf0f9c981900697367391bb566725c179647ad">7a27…47ad</a>:</p> <p><img src="/assets/2025-07-31/wasabi-ins-outs-txid-7a27c7.png" alt="My Inputs and Outputs for txid 7a27c793440396fd0090792e40bf0f9c981900697367391bb566725c179647ad" /></p> <p>To achieve a k-anonymity set, my Wasabi wallet has <em>decomposed</em> that deposit amount into multiple UTXOs of standard denominations<sup id="fnref:wasabi-standard-denominations" role="doc-noteref"><a href="#fn:wasabi-standard-denominations" class="footnote">8</a></sup>, shared by other participants in that coinjoin round. For example, my 59,049sat output was one of 5 different 59,059sat outputs in that transaction, a k-anonymity set of approximately 5; my 100,000sat output was one of 14 different 100,000sat outputs, a k-anonymity set of approximately 14.</p> <p>You’ve probably noticed the numbers next to the shield icon. Wasabi keeps track of the <a href="https://docs.wasabiwallet.io/FAQ/FAQ-UseWasabi.html#what-is-the-anonymity-score">anonymity score</a> of each UTXO. This measurement is approximately — but not exactly — the k-anonymity set that Wasabi believes each coinjoin round provided. You can configure Wasabi with the desired anonymity score target for your coins, and Wasabi will continue to do coinjoin rounds until all (economically spendable) coins have reached your desired target. In the case of this test wallet, Wasabi did three coinjoin rounds in total before all outputs reached the desired target:</p> <p><img src="/assets/2025-07-31/wasabi-coinjoins.png" alt="Wasabi Coinjoins" /></p> <p>Importantly, the anonymity score tries to take into account the total value and composition of the outputs of other participants. For example, for txid <a href="https://mempool.space/tx/ef4a4964f9e1e2cdc5f5daae90c1a08b31247094f69fb774684c8dade5ee62d3">ef4a…62d3</a>, I intentionally used an unpopular coordinator with very few participants. Wasabi has calculated an anonymity score of 1 for my outputs due to the lack of other participants:</p> <p><img src="/assets/2025-07-31/wasabi-ins-outs-txid-ef4a49.png" alt="My Inputs and Outputs for txid ef4a4964f9e1e2cdc5f5daae90c1a08b31247094f69fb774684c8dade5ee62d3" /></p> <p>Since Wasabi uses a central coordinator, as long as you’re using a popular coordinator it is relatively straightforward to achieve very large coinjoin transactions with hundreds of inputs and outputs, with most standard values having a dozen identical outputs. In this circumstance, it takes relatively little fees to achieve relatively large anonymity sets, making Wasabi fairly cost effective. Unlike JoinMarket, since all participants (modulo the coordinator themselves) are participating in an equal way, there is no (known) way for a passive chainalysis attacker to map outputs to inputs better than the probabilities inherent to the k-anonymity set.</p> <h4 id="round-structure-and-cryptography">Round Structure and Cryptography</h4> <p>With a central coordinator, one way to implement all this would be to simply have each participant tell the coordinator what inputs and outputs they wanted to use in the coinjoin, and the coordinator could construct a transaction containing all the requested inputs and outputs for participants to sign. If Wasabi worked this way, the resulting coinjoins would be resistant to passive chainalysis. Secondly — assuming that a large number of participants were present in each round — it would be difficult for participants to learn what inputs and outputs belonged to <em>other</em> participants by process of elimination.</p> <p>But you would have to trust the coordinator to keep the link between inputs and outputs a secret. That’s a problem. Both for the obvious reason that we’d rather the coordinator not know that. But also, because honest coordinators would rather not have that information themselves.</p> <p>Wasabi mitigates this problem with a multi-phase protocol, with participants using multiple identities via an anonymous communication mechanism such as Tor. For a full description, you should <a href="https://docs.wasabiwallet.io/using-wasabi/CoinJoin.html#wabisabi-protocol-step-by-step">read the docs</a>. But in summary, the protocol consists of the following phases:</p> <ol> <li>Input Registration: Participants tell the coordinator which <em>inputs</em> they want to use, and receive what is essentially a per-round <a href="https://en.wikipedia.org/wiki/Ecash"><em>chaumian e-cash</em></a> token for each input. The identities the participants use in this phase are known as the “Alices”; typically Tor is used here for anonymity.</li> <li>Output Registration: Using a new identity, e.g. via a new Tor connection, participants spend their input tokens to register <em>outputs</em> they want to exist in the coinjoin round.</li> <li>Signing: Now that the full transaction is built by the coordinator, every participant signs the transaction, re-using their Alice identities from the Input Registration phase.</li> <li>Blame Round: If not all participants signed, the coinjoin is attempted again with the successful participants. Coins from unsuccessful participants are temporarily blacklisted to make DoS attacks expensive.</li> </ol> <p>The key to the privacy guarantee is the combination of using two different sets of identities for input and output registration, and the use of a per-round e-cash-like token. The privacy guarantee against active chainalysis by the coordinator does depend heavily on Tor: if Tor connections can be deanonymized by the coordinator, the coordinator could link inputs to outputs.</p> <h2 id="attacks-on-multi-party-coinjoins">Attacks On Multi-Party Coinjoins</h2> <p>For the purposes of this article, we’re going to assume that the underlying e-cash-like cryptography that Wasabi uses works as advertised and is implemented correctly; I’m not aware of anyone claiming that it doesn’t. Instead, we’re going to look in more detail at the security model of coordinator-blinded multi-party coinjoins, and Kogman’s criticisms of Wasabi.</p> <h3 id="sybil-attack">Sybil Attack</h3> <p>If the coordinator can’t link inputs and outputs, can the coinjoin still be deanonymized? Yes! With a <a href="https://en.wikipedia.org/wiki/Sybil_attack">Sybil Attack</a>: if an active attacker manages to “flood” the coinjoin round with participants, so they are <em>every</em> participant except the target, they can deanonymize the coinjoin through a simple process of elimination.</p> <p>This attack is fundamental to any type of multi-party open-access coinjoin system where anyone can choose to be a participant and can participate anonymously<sup id="fnref:non-anonymous-coinjoin" role="doc-noteref"><a href="#fn:non-anonymous-coinjoin" class="footnote">9</a></sup>. Indeed, this attack even applies — in theory — to systems such as Monero and Zcash. The only question is how expensive is the attack?</p> <p>A typical Wasabi round transaction<sup id="fnref:wasabi-stats" role="doc-noteref"><a href="#fn:wasabi-stats" class="footnote">10</a></sup> using Kruw’s coordinator is about 25,000vB in size, spending about 50,000sats in transaction fees. At current prices, that’s about $50 USD. Additionally, dozens of Wasabi coinjoins happen every day.</p> <p>An adversary who tried to do a straightforward sybil attack, flooding every coinjoin round with so many inputs and outputs that victims were isolated, would probably have to spend thousands or tens of thousands of dollars in fees per day. On top of that, since it’s typical for millions of dollars worth of BTC to be coinjoined every round, a convincing attack would also need access to tens of millions of dollars worth of BTC to simulate that.</p> <p>There is no evidence such an attack is happening. Certainly, no government or other entity has publicly claimed to be doing such an attack, and in my private discussions with people involved in the chainalysis industry, I certainly haven’t heard any claims of such an attack.</p> <p>Ironically, if such an attack is being done, it would arguably be (at least temporarily) <em>improving</em> the privacy of coinjoin participants who weren’t targets of the attack. That would mean some entity is spending enormous resources doing coinjoins and keeping the data to themselves (at least for now).</p> <h3 id="targeted-sybil-attack">Targeted Sybil Attack</h3> <p>Can a sybil attack be made cheaper? With the involvement of the coordinator, maybe. For this section we’ll assume that round consistency holds; we’ll discuss in a further section the analysis if round consistency does not hold.</p> <p>Any multi-party coinjoin scheme will have some type of input registration mechanism, and some notion of “rounds”. If an attacker — including the coordinator itself — can direct different users to different rounds, the attacker could then perform a sybil attack more cheaply. For example, suppose that an attacker was trying to trace where a particular set of one or more coins went after coinjoining: rather than sybil attacking all coinjoin rounds, they could instead only attack coinjoin rounds spending those coins.</p> <p>In Wasabi, <em>without</em> the cooperation of the coordinator, the attacker could only do this by repeatedly trying to join coinjoin rounds and then disconnecting when those rounds do not contain the target inputs. This attack would require access to a significant amount of money due to the blacklisting mechanism, as each round would result in coins being blacklisted and unusable for subsequent rounds.</p> <p>Since individual transactions in Wasabi are fairly expensive, the cost of successful attacks is high: in my example above, a sybil attacker who managed to isolate me would still have had to spend $140 USD in transaction fees to deanonymize me, and they would have had to have access to many multiples of the $10 million USD worth of BTC mixed in that transaction.</p> <p>Additionally, this attack has an inherent trade-off between information gained and disruptiveness/ease-of-detection: if the attacker consistently manages to sybil attack rounds to the point where only one other real user is in the round, the attacker will disrupt all coinjoin activity at the coordinator. Highly suspicious! Conversely, if rounds spending non-target coins succeed, that also means that rounds spending <em>target</em> coins will have <em>non-target</em> coins in them, reducing the information gained by the deanonymization.</p> <p><em>With</em> the cooperation of the coordinator this attack requires much less capital, and can be more successful. First, let’s assume that the attacker knows <em>all</em> coins that the target wants to coinjoin<sup id="fnref:targeted-attack" role="doc-noteref"><a href="#fn:targeted-attack" class="footnote">11</a></sup>.</p> <p>The attacker participates in every coinjoin, registering their sybil coins as inputs. If other participants register <em>non-target</em> coins, the attacker drops out, leading to a blame round without the sybil coins. Since the attacker is cooperating with the coordinator, the sybil coins are <em>not</em> blacklisted and can be reused later.</p> <p>If other participants register <em>target</em> coins, the coordinator prevents <em>non-target</em> coins (other than the sybil coins) from participating. From the point of view of non-target participants, this would just look like a temporary failure of the coordinator. Either the target coins were registered first, which would result in a “successful” round, or after a blame round the coinjoin would complete. Either way the resulting transaction would only have the sybil attacker and target, allowing for easy deanonymization.</p> <p>For a convincing coinjoin this attack is still expensive: the attack still has to pay the transaction fees of their inputs and outputs. But it can be done with access to much less capital as blacklisting is not a concern; if blacklisting can be made visible to other participants, detecting this kind of attack by a malicious coordinator may be more feasible.</p> <h3 id="address-reuse-after-failed-coinjoins">Address Reuse After Failed Coinjoins</h3> <p>Ideally addresses would never be reused. However, like almost all wallet software, Wasabi uses a <a href="https://en.bitcoin.it/wiki/Deterministic_wallet">deterministic wallet</a> where addresses are generated deterministically from a seed. The problem is the <a href="https://bitcoinops.org/en/topics/gap-limits/">gap limit</a>: the maximum number of unused addresses in a row that the wallet will generate and look for when recovering from a seed.</p> <p>Currently, if a coinjoin attempt totally fails — with the blame rounds failing to generate a valid transaction — Wasabi reuses the output addresses used in that round in subsequent coinjoin attempts.</p> <p>What can the attacker learn from this? Suppose we have a failed round with two or more (genuine) participants. Both the coordinator, and all participants, learn the desired mapping of inputs and outputs during the round for all participants collectively. The desired mapping of inputs and outputs for any individual participant is protected by the k-anonymity set of having multiple participants.</p> <p>Now suppose that the round fails, and one or more participants join a subsequent coinjoin round. Unless the same set of participants tries to coinjoin again in a subsequent round, address re-use breaks the k-anonymity set: the intersection of inputs and outputs from a previous failed round, with the set of inputs and outputs from the current round, is likely to be a unique participant. Thus deanonymizing that participant.</p> <p>The fix is to simply not re-use addresses after a failed round. As of writing there is an <a href="https://github.com/WalletWasabi/WalletWasabi/pull/13875">open pull-req</a> that would mark addresses as used in the event of a round failure. But it’s unclear how this should interact with the gap limit.</p> <p>It is probably possible to use a technique based on <a href="https://bitcoinops.org/en/topics/silent-payments/">silent payments</a> to solve this issue as well. Here, fresh output addresses specific to the coinjoin round would be deterministically generated from the inputs, and perhaps the nLockTime field, in such a way that recovery would always be possible, regardless of how many rounds had failed. A disadvantage to doing this would be that Wasabi HD wallet seeds would not be compatible with any other wallet: you’d <em>have</em> to recover your funds with Wasabi.</p> <p>Finally, the Wasabi client supports payments directly within coinjoin rounds via an RPC call. This saves on fees by avoiding a second transaction. But it is inherently vulnerable to this issue if a payment is retried without a fresh address after a coinjoin round failure. That said, in addition to this being an advanced, RPC-only, feature not exposed in the GUI, the GUI also doesn’t make any claims as to the anonymity level of payments made within coinjoins.</p> <h4 id="leaking-commonly-owned-input-sets">Leaking Commonly Owned Input Sets</h4> <p>Avoiding address re-use does not solve the second, lesser, information leak of an attacker learning sets of coins with a common owner. Wasabi will often spend more than one output at once in a coinjoin round for efficiency. An attacker could thus learn statistical evidence that different coins have the same owner. It’s not clear that this could be fully mitigated in any coinjoin scheme that wanted to have the ability to spend more than one output at once.</p> <h4 id="information-extraction-via-invalid-rounds">Information Extraction via Invalid Rounds</h4> <p>A more risky attack, potentially with better information gathering properties, would be for the coordinator to pretend that more Alice’s exist than actually do by using entirely invalid inputs. This is risky, because in the Wasabi protocol participants do learn the inputs to the round before output registration — this is needed for optimal coin amount selection. A participant with access to an up-to-date UTXO set can detect this fraud. However, at the moment the Wasabi client does not assume access to a UTXO set, and thus does not automatically detect this fraud.</p> <p>The advantage over attacking via failed rounds is that a rogue coordinator could get better statistical information at less cost on the mapping of desired inputs to desired outputs. However, once the re-used address problem is fixed, this attack is no more powerful as learning that mapping becomes mostly useless.</p> <h3 id="attacking-round-consistency">Attacking Round Consistency</h3> <p>As discussed above, while it is always possible to sybil attack coinjoins, doing so is supposed to have a high cost because actual transaction fees must be paid for successful rounds that result in mined transactions.</p> <p>But what if you didn’t have to pay that cost?</p> <p>If the coordinator can fool different participants into signing a valid transaction, with different rounds, the coordinator could essentially sybil attack each participant by re-using the liquidity of other participants. Wasabi identifies rounds by a 256-bit Round ID, which is generated by <a href="https://github.com/WalletWasabi/WalletWasabi/blob/v2.6.0/WalletWasabi/WabiSabi/Models/RoundState.cs#L21">hashing all round-related values together</a>. Notably, the Input Registration start time, and the coordinator identity. Those two are sufficient to uniquely identify a round. Additionally, since all round settings are hashed into the Round ID, provided that Round ID consistency holds, the coordinator is unable to deanonymize different participants through differences in behavior due to different round settings.</p> <p>While coinjoining, the Wasabi client requests the status of all rounds periodically. Then, after the client decides to participate in a particular round, it uses the Round ID <a href="https://github.com/WalletWasabi/WalletWasabi/blob/v2.6.0/WalletWasabi/Serialization/Coordination.cs">in messages interacting with the coordinator</a>. In certain cases, such as a full round, multiple rounds can happen in parallel; the coordinator can potentially advertise different Round IDs to different clients.</p> <p>During the input registration phase all Alice’s send <a href="https://github.com/bitcoin/bips/blob/master/bip-0322.mediawiki">BIP-322</a> ownership proofs of their inputs to the coordinator. These ownership proofs <a href="https://github.com/WalletWasabi/WalletWasabi/blob/v2.6.0/WalletWasabi/Crypto/CoinJoinInputCommitmentData.cs">commit to the round ID</a>, preventing ownership proofs from being reused for any other round. Finally, the coordinator gives each client all ownership proofs for all inputs prior to signing. These ownership proofs are <a href="https://github.com/WalletWasabi/WalletWasabi/blob/v2.6.0/WalletWasabi/WabiSabi/Models/MultipartyTransaction/MultipartyTransactionState.cs#L58">validated as they are received by the client</a>.</p> <p>The catch with this that Kogman pointed out is that simply validating the ownership proof itself is not enough: we also need to validate that the ownership proof actually corresponds to the <code class="language-plaintext highlighter-rouge">scriptPubKey</code> of the transaction input the ownership proof is supposed to be proving. The Wasabi client does not assume it has access to a valid UTXO set, and thus does not directly validate ownership.</p> <p>If that were the whole of it, then the ownership proof mechanism could be fooled by “fake” ownership proofs: real pubkeys that don’t actually correspond to the <code class="language-plaintext highlighter-rouge">scriptPubKey</code> of the input they’re supposed to be proving ownership of.</p> <p>However Kogman failed to consider how <a href="https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki">Taproot signing</a> works: the signature commits to the <code class="language-plaintext highlighter-rouge">scriptPubKey</code>, meaning that any faked ownership proofs would ultimately result in an invalid transaction. This scenario is just another form of invalid input attack, which we’ve already dealt with above in the <a href="#information-extraction-via-invalid-rounds">our discussion of invalid rounds</a>.</p> <p>At the moment, Wasabi still supports non-taproot inputs, because many services had historically <a href="https://en.bitcoin.it/wiki/Bech32_adoption">been slow to support Bech32m (Taproot) addresses</a>. Fortunately as long as there are <em>any</em> non-attacker taproot inputs in a Wasabi round, <em>all</em> inputs must have valid ownership proofs. Put another way: to sybil attack via attacking round consistency, the evil coordinator must have as much real liquidity (and spend proportionally as much fees) as all taproot inputs in the round, and they can only attack clients who are not contributing taproot inputs.</p> <p>Why? Because honest nodes will only sign for a single Round ID. Suppose that we have three Alice participants in a round, Alice Adams, Alice Brown, and Alice Turner. We’ll say that Turner has one or more Taproot inputs, and the other two Alice’s have only non-Taproot inputs.</p> <p>If the round is to result in a valid transaction, the coordinator needs to provide Alice Adams and Alice Brown with the correct, valid, ownership proof from Alice Turner. Yet, if the coordinator does that, the coordinator is also forced to give all Alice’s the same Round ID, negating any attempt at a sybil attack as all Alice’s will register outputs with the same Round ID; the liquidity of all Alice’s contributes to the overall anonymity set.</p> <p>Note that the Taproot input can be <em>your</em> input: provided you contribute at least one Taproot input to the coinjoin, you can be sure that all honest liquidity in the round is contributing under the same Round ID. Now that payments to Bech32m (Taproot) addresses are widely supported, it would be a good idea for Wasabi to generate Taproot deposit addresses by default; as of v2.6.0, it does not. That said, for output addresses Taproot address are generated randomly 50% of the time, which protects the vast majority of coinjoins as so much liquidity is trying to register at least one Taproot address.</p> <h3 id="the-k-anonymity-set-of-communication-characteristics">The K-Anonymity Set of Communication Characteristics</h3> <p>Previously, Kogman had brought up the subject of registration delays in a <a href="https://github.com/WalletWasabi/WalletWasabi/issues/6394?s=09#issuecomment-920223952">GitHub issue</a>. While Kogman doesn’t articulate a clear engineering basis for the criticism, we can: the k-anonymity set of communication characteristics is important in any multi-party coinjoin system which aims to anonymize via separate identities for difference phases.</p> <p>Recall that Tor provides an <a href="https://spec.torproject.org/intro/index.html">anonymized equivalent to TCP stream functionality</a>, routed over fixed length relay cells. Now imagine that you have the <em>slowest</em> internet connection of any participant in a coinjoin round by a significant margin. Put another way, you don’t have a k-anonymity set of internet speed. It’s possible that the coordinator could detect this unique characteristic via the exact timings of data exchanged with the coordinator, and thus deanonymize your inputs and outputs by observing that unique characteristic across both input registration, and output registration.</p> <p>It would be ideal if Wasabi could eventually move to a purely packet-based data anonymity scheme, where all communications were done via exchange of atomic packets whose timing characteristics could be thoroughly randomized. Unfortunately, such a widely used scheme with trust characteristics similar to Tor simply doesn’t exist yet. It’s likely that Wasabi could improve on this situation somewhat with increased use of random delays. But without a purely packet-based communication scheme it’s probably best to try to use Wasabi on a relatively common type of internet connection to try to maximize your k-anonymity set. As always, this situation is improved in mixes with higher numbers of participants due to the large k-anonymity set.</p> <p>A related version of this problem that Kogman also brought up<sup id="fnref:kogman-post:2" role="doc-noteref"><a href="#fn:kogman-post" class="footnote">1</a></sup> is subtle differences in serialization and de-serialization. Wasabi makes use of JSON serialization, which is notorious for being underspecified and implemented slightly differently by different implementations. Again, your k-anonymity set is how many other participants use the <em>exact</em> same serialization scheme as you do. Slight differences could result in the coordinator being able to associate inputs and outputs.</p> <p>Fortunately, Wasabi only has one commonly used implementation. So in practice this is unlikely to be an issue. But regardless, Wasabi should eventually move to a fully-specified, rigid, binary serialization protocol.</p> <h2 id="final-thoughts">Final Thoughts</h2> <p>Even though there are ways that Wasabi could be improved, it clearly is the best option out there for coinjoining. PayJoin supporting wallets gets an honorable mention here, as it has clear benefits <em>if</em> both sender and receiver support it. Unfortunately, as much as I would like be able to recommend JoinMarket, the ugly fact is leaving on-chain clues as to where the coins actually came from is a much worse flaw than any hypothetical problem where maybe a coordinator could betray your trust at high cost and risk to themselves.</p> <p>Think about it: would you rather risk one entity possibly being untrustworthy, <em>and</em> finding a way to bypass Wasabi’s cryptographic protections? Or would you rather knowingly broadcast on-chain metadata to the entire world that <em>anyone</em>, now or in the future, could use to deanonymize you?</p> <p>While <em>trusted</em> coordinators are undesirable. Being <em>able</em> to trust your coordinator is a good belt-and-suspenders measure. Its good that Kruw shouldn’t be able to deanonymize my coinjoins even if he wanted to. But it’s also good that <em>on top of that</em> there’s good human-scale reasons to think he’s not going to anyway.</p> <p>JoinMarket fails on the first measure: under normal usage many of your transactions can be deanonymized due to the fee payment flaw. Yet it also fails on the second measure: it picks counterparties purely based on economics and chance, such that any bad actor with funds to spare can easily become your counterparty and trivially deanonymize you. It’s kinda similar to how Tor would be <em>less</em> secure if it were decentralized, because we wouldn’t have any ability to use the human element to keep bad actors out; there’s no way to prove you aren’t keeping logs.</p> <p>Kogman’s hyperbolic behavior here is a good example of what not to do. He failed to do a good engineering analysis of his criticisms (e.g. how Taproot signing made one fairly irrelevant), while turning off people by quickly jumping to accusations of impropriety for simply getting paid for their work (my landlord does not accept blog posts!). Meanwhile he himself has an obvious conflict of interest: a Spiral grant rumored to be worth hundreds of thousands a year, that obviously is only going to get renewed if he continues to find sufficiently important issues. Even that might be understandable. But then to also promote JoinMarket instead despite its long-known issues is not a good look:</p> <blockquote class="twitter-tweet"><p lang="en" dir="ltr">based if joinmarket, otherwise...</p>&mdash; nothingmuch (@not_nothingmuch) <a href="https://twitter.com/not_nothingmuch/status/1882861971130970623?ref_src=twsrc%5Etfw">January 24, 2025</a></blockquote> <script async="" src="https://platform.twitter.com/widgets.js" charset="utf-8"></script> <p>In any case, technology is rarely perfect. I personally do not use Wasabi alone. I prefer to use coinjoined coins to open lightning channels, and actually spend my money with Lighting. That layers two very different privacy techniques, such that both would have to fail for my financial privacy to be affected.</p> <h2 id="footnotes">Footnotes</h2> <div class="footnotes" role="doc-endnotes"> <ol> <li id="fn:kogman-post" role="doc-endnote"> <p><a href="https://gnusha.org/pi/bitcoindev/CAAQdECCdRVV+3ZoJhOotKEvmUV4yrV7EYWE8SOWCE1CF9tZ6Yg@mail.gmail.com/T/#u">“[bitcoindev] Reiterating centralized coinjoin (Wasabi &amp; Samourai) deanonymization attacks”, 2024-12-21 14:16, Yuval Kogman</a>, also available <a href="/assets/2025-07-31/bitcoindev-Reiterating-centralized-coinjoin-Wasabi-Samourai-deanonymization-attacks.mbox">locally</a> <a href="/assets/2025-07-31/bitcoindev-Reiterating-centralized-coinjoin-Wasabi-Samourai-deanonymization-attacks.mbox.ots">(OTS)</a> <a href="#fnref:kogman-post" class="reversefootnote" role="doc-backlink">&#8617;</a> <a href="#fnref:kogman-post:1" class="reversefootnote" role="doc-backlink">&#8617;<sup>2</sup></a> <a href="#fnref:kogman-post:2" class="reversefootnote" role="doc-backlink">&#8617;<sup>3</sup></a></p> </li> <li id="fn:samourai-status" role="doc-endnote"> <p>Kogman also critiques the Whirlpool protocol used by the now-defunct Samourai. We will not cover that protocol here as Samourai was always, and intentionally, horrendously insecure due to its leakage of xpubs by default. <a href="#fnref:samourai-status" class="reversefootnote" role="doc-backlink">&#8617;</a></p> </li> <li id="fn:coinjoin-credit" role="doc-endnote"> <p>Gregory Maxwell’s <a href="https://bitcointalk.org/?topic=279249">CoinJoin: Bitcoin privacy for the real world</a> post popularized the concept, in addition to his earlier <a href="https://bitcointalk.org/index.php?topic=139581">I taint rich!</a> post. There were even earlier mentions of the idea of coinjoin, e.g. in <a href="https://bitcointalk.org/index.php?topic=12751.msg315793#msg315793">2011</a>; Maxwell does not take credit for the idea itself. As for the <em>name</em> “coinjoin”, Maxwell asked me personally to come up with a good name for it — I’m happy with the result! <a href="#fnref:coinjoin-credit" class="reversefootnote" role="doc-backlink">&#8617;</a></p> </li> <li id="fn:chainalysis-term" role="doc-endnote"> <p><a href="https://chainalysis.com">Chainalysis</a> is an American blockchain analysis firm; the term “chainalysis” is used here as a generic term for that activity in general. <a href="#fnref:chainalysis-term" class="reversefootnote" role="doc-backlink">&#8617;</a></p> </li> <li id="fn:meiklejohn-methodology" role="doc-endnote"> <p>For example, I’ve been privately told that Sarah Meiklejohn’s 2013 <a href="https://cseweb.ucsd.edu/~smeiklejohn/files/imc13.pdf">A Fistful of Bitcoins: Characterizing Payments Among Men with No Name</a> clustering methodology is often used by chainalysis companies. This methodology is just a heuristic, not a proper statistical probability analysis, and was not designed to be used for these purposes. <a href="#fnref:meiklejohn-methodology" class="reversefootnote" role="doc-backlink">&#8617;</a></p> </li> <li id="fn:jm-maker-k-anon-set" role="doc-endnote"> <p>This may not be true in practice if makers have significantly different fee policies, as subsequent transactions may deanonymize them by different fees charged. But JoinMarket does randomize maker fees to an extent, which will often mitigate this issue. <a href="#fnref:jm-maker-k-anon-set" class="reversefootnote" role="doc-backlink">&#8617;</a></p> </li> <li id="fn:ginger-wallet" role="doc-endnote"> <p><a href="https://github.com/GingerPrivacy/GingerWallet">GingerWallet</a> also forked the Wasabi Wallet source code when the central Wasabi coordinator was shutdown. Since GingerWallet doesn’t appear to have gotten much development effort, or usage, we won’t discuss it further. <a href="#fnref:ginger-wallet" class="reversefootnote" role="doc-backlink">&#8617;</a></p> </li> <li id="fn:wasabi-standard-denominations" role="doc-endnote"> <p><a href="https://docs.wasabiwallet.io/FAQ/FAQ-UseWasabi.html#what-are-the-equal-denominations-created-in-a-coinjoin-round">5000, 6561, 8192, 10000, 13122, 16384, 19683, 20000, 32768, 39366, 50000, 59049, 65536, 100000, 118098, 131072, 177147, 200000, 262144, 354294, 500000, 524288, 531441, 1000000, 1048576, 1062882, 1594323, 2000000, 2097152, 3188646, 4194304, 4782969, 5000000, 8388608, 9565938, 10000000, 14348907, 16777216, 20000000, 28697814, 33554432, 43046721, 50000000, 67108864, 86093442, 100000000, 129140163, 134217728, 200000000, 258280326, 268435456, 387420489, 500000000, 536870912, 774840978, 1000000000, 1073741824, 1162261467, 2000000000, 2147483648, 2324522934, 3486784401, 4294967296, 5000000000, 6973568802, 8589934592, 10000000000, 10460353203, 17179869184, 20000000000, 20920706406, 31381059609, 34359738368, 50000000000, 62762119218, 68719476736, 94143178827, 100000000000, and 137438953472 sats</a>, which were <a href="https://github.com/WalletWasabi/WabiSabi/blob/27b15d98d3040d5c7d224a0d550c165ebeb1eade/Amount%20Org.ipynb">carefully chosen</a> to minimize the average number of UTXOs needed to decompose typical amounts. <a href="#fnref:wasabi-standard-denominations" class="reversefootnote" role="doc-backlink">&#8617;</a></p> </li> <li id="fn:non-anonymous-coinjoin" role="doc-endnote"> <p>A <em>closed</em> coinjoin scheme could prevent sybil attack by limiting the coinjoin participants to a set of known entities. <a href="#fnref:non-anonymous-coinjoin" class="reversefootnote" role="doc-backlink">&#8617;</a></p> </li> <li id="fn:wasabi-stats" role="doc-endnote"> <p>Statistics on Wasabi rounds are collected and published by <a href="https://wabisator.com/">Wabisator</a> and <a href="https://liquisabi.com/">LiquiSabi</a>, among others. <a href="#fnref:wasabi-stats" class="reversefootnote" role="doc-backlink">&#8617;</a></p> </li> <li id="fn:targeted-attack" role="doc-endnote"> <p>The worst-case scenario. If the attacker does <em>not</em> know all of the coins the target wishes to coinjoin, the attack will be visible as some coins will mysteriously fail to be registered in the input registration phase. <a href="#fnref:targeted-attack" class="reversefootnote" role="doc-backlink">&#8617;</a></p> </li> </ol> </div> Thu, 31 Jul 2025 00:00:00 +0000 https://petertodd.org/2025/coinjoin-comparison https://petertodd.org/2025/coinjoin-comparison bitcoin coinjoin privacy Fake Channels Are Real: Why Client-Side-Validated Lightning Is Easier Than You Think <p>An unintuitive aspect of the Lightning protocol is that channels in the middle of your route don’t have to be real. If Alice is trying to pay BTC to David, through the route Alice ↔ Bob ↔ Charlie ↔ David, whether or not the Lightning channels between Bob and Charlie represent real channels with real Bitcoin doesn’t matter! Indeed, it doesn’t even matter to Alice whether or not David received genuine BTC at all. All that matters to her is that David accepted the payment as valid by revealing the preimage; if he didn’t, Alice never gave a single sat to Bob.</p> <p>Equally, if Alice is <em>receiving</em> a BTC payment from David, through the David ↔ Charlie ↔ Bob ↔ Alice route, it doesn’t matter to Alice whether or not David sent genuine sats to Charlie. Or whether or not Charlie sent genuine BTC to Bob. All she cares is that somehow Bob was convinced to send genuine BTC to Alice.</p> <p>The existing Lightning protocol does ensure that public channels correspond to valid UTXOs. But the <em>reason</em> why this is done is really just an anti-DoS measure: there has to be <em>some</em> limit on how many channels people can advertise. Tying the Lightning channel UTXO to the gossip advertisement happens to be the way we do that right now.</p> <h2 id="lightning-with-client-side-validated-tokens">Lightning With Client-Side-Validated Tokens</h2> <p>The fact that Lightning payments can be safely routed over public fake channels has so far been a theoretical curiosity for Lightning over Bitcoin. It’s been proposed before as a way to reduce liquidity requirements for channels between entities that trust each other. But the idea has never actually been implemented.</p> <p>However, it makes a very big difference to Lightning on top of client-side-validated tokens.</p> <p>To recap, a client-side-validated coin using a protocol such as <a href="https://rgb.tech">RGB</a> uses Bitcoin as a pure anti-doublespend mechanism: Bitcoin ensures there is exactly one history for a given coin. The <em>validity</em> of that history is verified client side. Thus if Alice gives Bob a coin representing $1 USD on RGB, she convinces Bob that the coin is real by giving Bob all the coin history data back to the genesis outputs(s) that created her particular coin.</p> <p>Since history is not global, client-side-validation has the potential of enormous scalability. As I have <a href="/2017/scalable-single-use-seal-asset-transfer">explained on this blog before</a>, a client-side-validation token could have a total volume of literally billions of transactions per second. But, these transactions are still a kind of on-chain transaction, which means they will take time to confirm; Lightning transactions can be almost instant.</p> <p>Thus both RGB and Taproot Assets are working towards implementing Lightning channels that trade client-side validated tokens.</p> <p>Which gets back to the issue of “fake” channels: while it might take a few megabytes of transaction data to prove that an RGB token in your posession is real, if you’re using that token for a Lightning channel, you do <em>not</em> need to know whether or not the RGB tokens of anyone else’s Lightning channels are real! It’s sufficient to have proof that your channel is real to be fully self-sovereign; if other people have been fooled into accepting fake coins, that’s not your problem.</p> <h2 id="taproot-asset-universes">Taproot Asset Universes</h2> <p>This does raise an interesting question: are the <a href="https://github.com/Roasbeef/bips/blob/bd3cdc153beaa901f26ef6504ea89e8f5e00b921/bip-tap.mediawiki#user-content-Asset_Universes">Asset Universes</a> in Taproot Assets really necessary? The idea behind them is that light clients would — instead of proper validation — trust third party “universes” to perform coin validation for the asset(s) they are transacting. The universes would be expected to have most if not all transactions for a given asset, and would create large, signed, merkle trees committing to all valid coins at a given block height.</p> <p>If the typical “light” wallet simply uses Lightning channels, by simply downloading a few MB worth of data they can have full client-side-validation of their coins, without relying on any third parties. Since it doesn’t actually matter whether or not intermediary Lightning channels are real, the light wallet could even do full routing themselves, based on gossiped channels (e.g. using, say, a proof-of-sacrifice anti-DoS mechanism).</p> Sat, 25 Jan 2025 00:00:00 +0000 https://petertodd.org/2025/fake-channels-and-rgb-lightning https://petertodd.org/2025/fake-channels-and-rgb-lightning bitcoin lightning rgb client-side-validation taproot-assets Keeping it Cool: Mining Bitcoin in Space <p>With the recent success of Starship’s 5th and 6th test flights, <a href="/2017/bitcoin-mining-space-hard-sci-fi">mining Bitcoin in space</a> and <a href="https://www.lumenorbit.com/">data centers in space</a> have gotten renewed attention. But every time this is discussed, people inevitably raise the objections that “space isn’t cold”, “keeping things cool in space is almost impossible”, and “latency is too high”.</p> <p>These people are wrong. They’ve read too much over-simplified “pop science”, and haven’t done the physics for themselves.</p> <p>So we’re going to do that physics now. We’re going to understand the thermal behavior of a solar power Bitcoin miner, what heats it up, and what cools it down, as well as the impact of latency on stale rate. I’m going to assume you’ve done enough high-school-level physics to understand what units are and some basic math. You don’t have to remember it all — I’ll link to Wikipedia where appropriate so you can refresh your memory.</p> <p>What we’ll find out is that there’s nothing fundamentally stopping space mining from being possible. That’s not to say it’s going to actually happen — launch costs need to be reduced. But <em>if</em> launch costs can in fact be reduced enough, the economics of it might make sense.</p> <div class="post-toc"> <h1 class="no_toc" id="contents">Contents</h1> <ol id="markdown-toc"> <li><a href="#how-cold-is-space-anyway" id="markdown-toc-how-cold-is-space-anyway">How Cold is Space Anyway?</a> <ol> <li><a href="#why-do-people-say-space-is-hot" id="markdown-toc-why-do-people-say-space-is-hot">Why Do People Say Space is Hot?</a></li> </ol> </li> <li><a href="#flat-pack-solar-powered-space-miner" id="markdown-toc-flat-pack-solar-powered-space-miner">Flat-Pack Solar Powered Space Miner</a> <ol> <li><a href="#heat-spreading" id="markdown-toc-heat-spreading">Heat Spreading</a></li> </ol> </li> <li><a href="#latency" id="markdown-toc-latency">Latency</a></li> <li><a href="#footnotes" id="markdown-toc-footnotes">Footnotes</a></li> </ol> </div> <h2 id="how-cold-is-space-anyway">How Cold is Space Anyway?</h2> <p>On average, very cold!</p> <p>What do we mean by “cold”? Well, there’s a bunch of definitions of temperature that get used in various contexts. But for our purposes, we’re going to use the simple definition most relevant to engineering: if we put a non-heat-producing object in space and leave it there, what temperature will it eventually reach?</p> <p>The equilibrium temperature is reached when the non-heat-producing object is losing heat as fast as it is absorbing heat. Since space is a vacuum, we know that the only non-trivial mechanism by which our object must be losing heat is <a href="https://en.wikipedia.org/wiki/Thermal_radiation">thermal radiation</a>. Equally, the only way our object can gain heat is also radiation, such as the <a href="https://en.wikipedia.org/wiki/Cosmic_microwave_background">Cosmic Microwave Background</a>, and light from stars and other astronomical objects.</p> <p>The Cosmic Microwave Background is equivalent to a <a href="https://en.wikipedia.org/wiki/Black_body">black body radiator</a> at \(2.7K\), just slightly above absolute zero. As for starlight, just look at a night sky: it’s black! Space is incredibly empty, so while individual stars are very hot, the total energy you receive from them must be tiny.</p> <p>For our purposes — engineering a Bitcoin miner — exactly how tiny doesn’t matter much. We’re quite confident that the number is essentially zero when compared to the energy from sunlight. For example, <a href="https://en.wikipedia.org/wiki/Pluto">Pluto’s surface</a> gets as cold as \(-240^{\circ}C\), or \(33K\), even though Pluto is heated by the sun, as well as internal radioactive decay, and the remaining heat of formation<sup id="fnref:heat-of-formation" role="doc-noteref"><a href="#fn:heat-of-formation" class="footnote">1</a></sup>.</p> <p>Suppose that Pluto is a perfect black-body radiator with emissivity, \(\epsilon = 1\), in thermal equilibrium with the radiation from interstellar space. That would mean that the <a href="https://en.wikipedia.org/wiki/Radiant_exitance">radiant exitance</a> \(M\) of the surface would be equal to the <em>flux density</em> \(E\) of the night sky. That is, rate at which energy is leaving the surface, \(M\), is equal to the rate at which energy is being absorbed, \(E\).</p> <p>While we know that this is <strong>not</strong> true — Pluto is heated by other sources, like the sun, internal heat energy from formation, radioactive decay, etc. — we can use the known temperature at the surface with the <a href="https://en.wikipedia.org/wiki/Stefan%E2%80%93Boltzmann_law">Stefan–Boltzmann law</a> to calculate an <em>upper bound</em> on what the flux density of the night sky could be:</p> \[\begin{align} E = M &amp;= \epsilon \sigma T^4 \\ M &amp;= 5.67 \times 10^{-8} \frac{W}{m^2 K^4} (33K)^4 \\ M &amp;= 0.067 \frac{W}{m^2} \end{align}\] <p>In comparison to the flux density of sunlight at Earth’s orbit, \(1380 \frac{W}{m^2}\), the night sky is pretty much zero.</p> <p>Space is very cold!</p> <h3 id="why-do-people-say-space-is-hot">Why Do People Say Space is Hot?</h3> <p>Mostly because space is empty. Here on Earth you can easily get rid of large amounts of waste heat by transferring it to the atmosphere. But in space, the only way to expel waste heat with a closed system is to expel it via thermal radiation.</p> <p>Secondly, if you are in space at a similar distance to the sun as Earth is, sunlight is significant: \(1380\frac{W}{m^2}\). Without an atmosphere to dump heat to, this makes spacesuit design tricky.</p> <p>A typical adult male has a resting metabolic rate of about \(P = 100W\), and a <a href="https://en.wikipedia.org/wiki/Body_surface_area">body surface area</a> of about \(A = 2m^2\). In daylight, about half that surface area would be exposed to the sun, \(A_E = 1m^2\). Suppose our spaceman wears a sci-fi looking jet black spacesuit, a perfect black body radiator with with \(\epsilon = 1\). For our spaceman to be in thermal equilibrium, the energy he is absorbing from the sun, and the energy released by his metabolism, must be equal to the energy released via thermal radiation:</p> \[\begin{align} P + A_E E = A M \end{align}\] <p>Applying Stefan-Boltzman’s law again:</p> \[\begin{align} P + A_E E &amp;= A M = A \epsilon \sigma T^4 \\ T &amp;= \left( \frac{P + A_E E}{A \epsilon \sigma} \right)^{\frac{1}{4}} \\ &amp;= \left( \frac{100W + 1m^2 1380\frac{W}{m^2}}{2m^2 \times 5.67 \times 10^{-8} \frac{W}{m^2 K^4}} \right)^{\frac{1}{4}} \\ &amp;= 338K = 64^{\circ}C \end{align}\] <p>Oops! Our spaceman is going to be cooked alive! To solve this problem real-life spacesuits are usually white, to absorb less heat, and typically reject heat to space via the evaporation of water<sup id="fnref:spacesuit-subliminator" role="doc-noteref"><a href="#fn:spacesuit-subliminator" class="footnote">2</a></sup>; spacesuits are <em>not</em> closed systems.</p> <p>However, if he were an computer chip, he’d survive just fine at those temperatures…</p> <h2 id="flat-pack-solar-powered-space-miner">Flat-Pack Solar Powered Space Miner</h2> <p>Unlike most other computing tasks, Bitcoin mining is simple, highly parallelizable, and requires essentially no communication between compute elements. This means we can reduce launch mass to a minimum while still expelling heat effectively with a flat-pack design: mount the computation elements to the backside of the solar panels powering them.</p> <p>Since this design is <em>solar powered</em>, our total heat budget per square-meter is always exactly equal to the flux density, \(M = 1380\frac{W}{m^2}\) at Earth’s orbital distance. The electrical usage and efficiency of the solar panels doesn’t matter: either solar energy is converted to electricity, and turned into heat via the computation, or solar energy is absorbed by the panel and converted directly to heat. Some solar energy is reflected by the panels. But the absorption ratio and emissivity of currently available solar panels is pretty close to 1. So for our rough analysis, we can round up to 1.</p> <p>How hot will this design get? Since a flat panel radiates on <em>both</em> sides, our energy budget is:</p> \[\begin{align} E = 2M \end{align}\] <p>Applying Stefan-Boltzman’s law again:</p> \[\begin{align} E &amp;= 2 \epsilon \sigma T^4 \\ T &amp;= \left( \frac{E}{2 \epsilon \sigma} \right)^{\frac{1}{4}} \\ &amp;= \left( \frac{1380\frac{W}{m^2}}{2 \times 5.67 \times 10^{-8} \frac{W}{m^2 K^4}} \right)^{\frac{1}{4}} \\ &amp;= 332K = 59^{\circ}C \end{align}\] <p>Not a problem at all! Silicon runs just fine at those temperatures.</p> <p>But for sake of argument, what if that number wasn’t good enough? There’s a very easy solution: tilt the panels. Rather than make them perpendicular to the sun, simply put them at some angle \(\theta\). Now we can reduce the solar flux absorbed, \(E_\theta\), to whatever fraction of \(E\) that we want by changing the angle, giving us:</p> \[\begin{align} E_\theta = \cos(\theta) E &amp;= 2M \\ \cos(\theta) E &amp;= 2 \epsilon \sigma T^4 \\ T &amp;= \left( \frac{\cos(\theta) E}{2 \epsilon \sigma} \right)^{\frac{1}{4}} \end{align}\] <p>The <a href="https://en.wikipedia.org/wiki/Parker_Solar_Probe">Parker Solar Probe</a> uses this technique to avoid overheating its solar panels while it’s close to the sun.</p> <h3 id="heat-spreading">Heat Spreading</h3> <p>Our previous calculation has an assumption: that heat is generated evenly across the entire surface of the panel. While this is true for the solar flux that is absorbed directly as heat, it might not be true for the percentage of sunlight that is turned into electricity and used to actually power the computation.</p> <p>A Bitmain Antminer S21 has <a href="https://braiins.com/blog/antminer-s21-technical-deep-dive">324 ASIC chips in total</a> consuming 3500W in total, 11W per chip. Each chip is about \(1cm^2\) in size. That works out to a power density of \(110\frac{kW}{m^2}\), about two orders of magnitude more than the sun. Without any heat spreading, and assuming a black body, that would lead to a surface temperature of:</p> \[\begin{align} P &amp;= 2 \sigma T^4 \\ T &amp;= \left( \frac{E}{2 \epsilon \sigma} \right)^{\frac{1}{4}} \\ &amp;= \left( \frac{110\frac{kW}{m^2}}{2 \times 5.67 \times 10^{-8} \frac{W}{m^2 K^4}} \right)^{\frac{1}{4}} \\ &amp;= 992K \end{align}\] <p>We don’t even need to convert that to Celsius to know that’s unacceptable! If we’re going to use chips in that package, we need to spread that heat. Roughly speaking, we need to spread the heat from a \(1cm^2\) area to a \(80cm^2\), or a circle with a radius of \(5cm^2\).</p> <p>It’s obviously <em>possible</em> to do this with a sufficiently thick heat spreader. Unfortunately unlike our previous calculation, there’s no easy way to derive a closed form equation. It’s also a question of economics: since the cost of the heat spreader can be reduced spreading the heat generation across a higher number of ASIC chips, the optimal design will likely be a combination of heat spreading and reducing the power intensity of the ASICs. What these trade-offs are depends on the mass of the heat spreader, launch costs, ASIC costs, etc.</p> <p>Regardless, the fact that off-the-shelf planar heat pipes exist that can handle \(1000W\) in an area that large — significantly more than the 11W we need — is sufficient to prove that the idea is plausible.</p> <h2 id="latency">Latency</h2> <p>The final objection to space mining and putting data centers in space is communication latency due to the speed of light. For the needs of data centers in general, latency may or may not matter depending on the application — bulk tasks like AI training do exist that can tolerate hours of latency.</p> <p>For Bitcoin mining, <em>if</em> the space miner in question has a small percentage of total hash power, latency translates into a higher stale rate and thus less profit; if the space miner has a large percentage (roughly more than 30%) of total hash power, higher latency results in their competitors having a higher state rate. This is why space mining is potentially very dangerous for Bitcoin as a whole<sup id="fnref:solar-powered-space-pirates" role="doc-noteref"><a href="#fn:solar-powered-space-pirates" class="footnote">3</a></sup>.</p> <p>In summary, latency is not a valid objection. But let’s analyze it in depth anyway.</p> <p>Let’s assume we have negligible hash power — low enough that the probability of finding two blocks in a row is negligible. Secondly, we’ll treat all other hash power as a uniform entity, with negligible communication latency between other miners. Let \(t\) be our communication latency, which we will assume is symmetric in both directions. For a block found by us to <em>not</em> be stale, two conditions must be true:</p> <ol> <li>No blocks were found prior to our block. If we assume we switch instantly upon learning of a new block, the time window for this to happen has duration \(t\).</li> <li>No blocks are found after our block, before our block gets to the rest of the hash power. Again, the time window for this to happen has duration \(t\).</li> </ol> <p>If \(t\) is small relative to the block rate \(r\) — the number of blocks per time interval; the inverse of the block interval — we can approximate this probability linearly:</p> \[P(\mathrm{stale}) \approx 2tr\] <p>This approximation is commonly used, and, for example, AI tools like Grok tend to give it as an answer. However, this approximation overestimates the stale rate as \(t\) increases: as \(t\) increases the probability reaches 1, even though there is always a chance that other miners fail to find blocks regardless of how large the communication latency is.</p> <p>We can do better by applying the <a href="https://en.wikipedia.org/wiki/Poisson_distribution">Poisson distribution</a>:</p> \[P(N = k) = \frac{\lambda^k e^{-\lambda}}{k!}\] <p>Thus the probability of no blocks being found, \(N=0\), in a time period \(t\) is:</p> \[\begin{align} \lambda &amp;= tr \\ P(N = 0) &amp;= \frac{\lambda^0 e^{-rt}}{0!} = e^{-rt} \end{align}\] <p>In our case the win condition is no blocks being found in <em>two</em> different \(t\) time periods. Thus our probability of a stale is:</p> \[P(\mathrm{stale}) = 1 - P(N = 0)^2 = 1 - e^{-2rt}\] <p>As an aside, by taking the derivative of \(P(\mathrm{stale})\) with respect to \(t\) we can see why the linear approximation is very good for small \(t\):</p> \[\frac{d}{dt}P(\mathrm{stale}) = 2r e^{-2rt}\] <p>If \(rt\) is small, \(e^{-2rt} \approx 1\). For example, assume \(r = \frac{1}{600s}\) and \(t = 133s\), the average speed of light delay from Earth to Venus. The approximation gives us:</p> \[P(\mathrm{stale}) \approx 2tr = 44.3\%\] <p>…while the poisson equation gives us:</p> \[P(\mathrm{stale}) = 2r e^{-2rt} = 35.8\%\] <p>Our approximation overestimates the stale rate by only 24%.</p> <p>Now, for a more realistic example, let’s suppose that our solar powered space miners are at the L1 or L2 <a href="https://en.wikipedia.org/wiki/Lagrange_point">Lagrange points</a>, 1.5 million km from Earth. Even that far out, the communication delay is only \(5s\), corresponding to a stale rate of \(1.7\%\). Assuming your space mining operation is sufficiently profitable to be worth doing at all, it’ll probably be profitable enough that the latency hit doesn’t matter.</p> <p>Furthermore, you probably don’t have to go that far out anyway. A <a href="https://en.wikipedia.org/wiki/Sun-synchronous_orbit">sun-synchronous orbit</a> is sufficient to ensure that the panels are always in sunlight, and those are typically no more than 1000km in altitude. If anything, that would be sufficiently low that <a href="https://en.wikipedia.org/wiki/Orbital_decay">atmospheric drag</a> would be an issue. Though it may be feasible to use <a href="https://en.wikipedia.org/wiki/Atmosphere-breathing_electric_propulsion">atmospheric-breathing electric propulsion</a> to counteract drag.</p> <h2 id="footnotes">Footnotes</h2> <div class="footnotes" role="doc-endnotes"> <ol> <li id="fn:heat-of-formation" role="doc-endnote"> <p>That is, the heat that was created when the mass that created Pluto collapsed into a ball, turning gravitational potential energy into heat. <a href="#fnref:heat-of-formation" class="reversefootnote" role="doc-backlink">&#8617;</a></p> </li> <li id="fn:spacesuit-subliminator" role="doc-endnote"> <p>For example, the <a href="https://www.nasa.gov/wp-content/uploads/static/history/alsj/ALSJ-FlightPLSS.pdf">Apollo program suits</a>, as well as the modern day suits used <a href="https://www.nasa.gov/wp-content/uploads/2009/07/188963main_extravehicular_mobility_unit.pdf">by NASA for the ISS</a> use water subliminators. <a href="#fnref:spacesuit-subliminator" class="reversefootnote" role="doc-backlink">&#8617;</a></p> </li> <li id="fn:solar-powered-space-pirates" role="doc-endnote"> <p>See my <a href="https://www.youtube.com/watch?v=0WCaoGiAOHE&amp;t=128s">Solar Powered Space Pirates: A threat to Bitcoin?</a> talk (<a href="https://btctranscripts.com/breaking-bitcoin/2017/solar-powered-space-pirates">transcript</a>) at Breaking Bitcoin 2017 for a good description of this problem. <a href="#fnref:solar-powered-space-pirates" class="reversefootnote" role="doc-backlink">&#8617;</a></p> </li> </ol> </div> Tue, 03 Dec 2024 00:00:00 +0000 https://petertodd.org/2024/keeping-it-cool-mining-bitcoin-in-space https://petertodd.org/2024/keeping-it-cool-mining-bitcoin-in-space bitcoin space physics Soft-Fork/Covenant Dependent Layer 2 Review <p>On-chain wallets achieve a roughly 1-1 mapping of transactions to transactions: for every <em>economic</em> transaction that a user performs, roughly one <em>blockchain</em> transaction is needed. Aggregations, coinjoin, cut-through-payments, etc. change this statement a bit. But it’s roughly correct.</p> <p>Lightning achieved a <em>many-to-one</em> mapping of transactions to transactions: the magic of Lightning is that an effectively infinite number of economic transactions can happen in a single Lighting channel, which itself is tied to a single unspent transaction output (UTXO). Essentially we’ve taken the “time” dimension — transactions — and achieved a significant scaling by collapsing that dimension.</p> <p>But creating even a single UTXO per user is, arguably, not good enough. So there are many proposals out there to achieve even greater scaling by allowing multiple users to share a single UTXO in a self-sovereign way. Again, collapsing another “space” dimension of scaling — users — into one UTXO.</p> <p>Our goal here is to do an overview of all these proposals, figure out what technical patterns they share, figure out what kinds of new opcodes and other soft fork upgrades they need to function, and create a comparison table of how all the parts fit together. Along the way we’ll also define what an L2 protocol actually is, what kind of scaling Lightning is already capable of, and get an understanding of what improvements we need to do to mempools to achieve all this.</p> <p><em>Thanks goes to <a href="https://fulgur.ventures/">Fulgur Ventures</a> for sponsoring this research. They had no editorial control over the contents of this post and did not review it prior to publication.</em></p> <p><em>Thanks also goes to <a href="https://twitter.com/danielabrozzoni">Daniela Brozzoni</a>, <a href="https://twitter.com/starcox64">Sarah Cox</a>, and others for pre-publication review, and <a href="https://wpsoftware.net/andrew/blog/">Andrew Poelstra</a> and others for post-publication review.</em></p> <div class="post-toc"> <h1 class="no_toc" id="contents">Contents</h1> <ol id="markdown-toc"> <li><a href="#definitions" id="markdown-toc-definitions">Definitions</a> <ol> <li><a href="#what-is-layer-2" id="markdown-toc-what-is-layer-2">What is Layer 2?</a></li> <li><a href="#what-are-covenants" id="markdown-toc-what-are-covenants">What are Covenants?</a> <ol> <li><a href="#recursive-covenants" id="markdown-toc-recursive-covenants">Recursive Covenants</a></li> </ol> </li> </ol> </li> <li><a href="#goals" id="markdown-toc-goals">Goals</a> <ol> <li><a href="#lightnings-scaling-limits" id="markdown-toc-lightnings-scaling-limits">Lightning’s Scaling Limits</a></li> </ol> </li> <li><a href="#l2-overview" id="markdown-toc-l2-overview">L2 Overview</a> <ol> <li><a href="#lightning" id="markdown-toc-lightning">Lightning</a> <ol> <li><a href="#non-interactive-channels" id="markdown-toc-non-interactive-channels">Non-Interactive Channels</a></li> </ol> </li> <li><a href="#channel-factories" id="markdown-toc-channel-factories">Channel Factories</a></li> <li><a href="#eltooln-symmetry" id="markdown-toc-eltooln-symmetry">Eltoo/LN-Symmetry</a></li> <li><a href="#ark" id="markdown-toc-ark">Ark</a> <ol> <li><a href="#ark-economics" id="markdown-toc-ark-economics">Ark Economics</a></li> <li><a href="#bootstrapping-ark" id="markdown-toc-bootstrapping-ark">Bootstrapping Ark</a></li> <li><a href="#interactivity" id="markdown-toc-interactivity">Interactivity</a></li> <li><a href="#advanced-ark" id="markdown-toc-advanced-ark">Advanced Ark</a></li> <li><a href="#on-chain-fee-payment-in-unilateral-withdraw" id="markdown-toc-on-chain-fee-payment-in-unilateral-withdraw">On-Chain Fee Payment In Unilateral Withdraw</a></li> </ol> </li> <li><a href="#validity-rollups" id="markdown-toc-validity-rollups">Validity Rollups</a></li> <li><a href="#bitvm" id="markdown-toc-bitvm">BitVM</a></li> <li><a href="#hierarchical-channels" id="markdown-toc-hierarchical-channels">Hierarchical Channels</a></li> <li><a href="#coinpool" id="markdown-toc-coinpool">CoinPool</a></li> <li><a href="#enigma-network" id="markdown-toc-enigma-network">Enigma Network</a></li> </ol> </li> <li><a href="#mempool-considerations" id="markdown-toc-mempool-considerations">Mempool Considerations</a> <ol> <li><a href="#transaction-pinning" id="markdown-toc-transaction-pinning">Transaction Pinning</a></li> <li><a href="#fee-payment-rbf-cpfp-sighash_anyonecanpay-anchors-and-sponsorship" id="markdown-toc-fee-payment-rbf-cpfp-sighash_anyonecanpay-anchors-and-sponsorship">Fee Payment: RBF, CPFP, <code class="language-plaintext highlighter-rouge">SIGHASH_ANYONECANPAY</code>, Anchors, and Sponsorship</a></li> <li><a href="#replacement-cycling" id="markdown-toc-replacement-cycling">Replacement Cycling</a></li> </ol> </li> <li><a href="#feature-patterns-and-soft-forks" id="markdown-toc-feature-patterns-and-soft-forks">Feature Patterns and Soft Forks</a> <ol> <li><a href="#op_expire" id="markdown-toc-op_expire"><code class="language-plaintext highlighter-rouge">OP_Expire</code></a></li> <li><a href="#sighash_anyprevout" id="markdown-toc-sighash_anyprevout"><code class="language-plaintext highlighter-rouge">SIGHASH_ANYPREVOUT</code></a></li> <li><a href="#op_checktemplateverify" id="markdown-toc-op_checktemplateverify"><code class="language-plaintext highlighter-rouge">OP_CheckTemplateVerify</code></a> <ol> <li><a href="#lnhance" id="markdown-toc-lnhance">LNHANCE</a></li> </ol> </li> <li><a href="#op_txhash" id="markdown-toc-op_txhash"><code class="language-plaintext highlighter-rouge">OP_TXHASH</code></a></li> <li><a href="#op_cat" id="markdown-toc-op_cat"><code class="language-plaintext highlighter-rouge">OP_CAT</code></a> <ol> <li><a href="#is-op_cat-too-powerful" id="markdown-toc-is-op_cat-too-powerful">Is <code class="language-plaintext highlighter-rouge">OP_CAT</code> Too Powerful?</a></li> </ol> </li> <li><a href="#incremental-hashing" id="markdown-toc-incremental-hashing">Incremental Hashing</a></li> <li><a href="#script-revival" id="markdown-toc-script-revival">Script Revival</a> <ol> <li><a href="#simplicity" id="markdown-toc-simplicity">Simplicity</a></li> </ol> </li> <li><a href="#op_fancytreemanipulationstuff" id="markdown-toc-op_fancytreemanipulationstuff"><code class="language-plaintext highlighter-rouge">OP_FancyTreeManipulationStuff</code></a></li> </ol> </li> <li><a href="#fund-pools" id="markdown-toc-fund-pools">Fund Pools</a> <ol> <li><a href="#individual-pre-signed-transactions" id="markdown-toc-individual-pre-signed-transactions">Individual Pre-Signed Transactions</a></li> <li><a href="#txout-trees" id="markdown-toc-txout-trees">Txout Trees</a></li> <li><a href="#balance-based-schemes" id="markdown-toc-balance-based-schemes">Balance Based Schemes</a></li> </ol> </li> <li><a href="#failure-data-ratio" id="markdown-toc-failure-data-ratio">Failure Data Ratio</a></li> <li><a href="#consensus-cleanup" id="markdown-toc-consensus-cleanup">Consensus Cleanup</a></li> <li><a href="#testing-soft-fork-dependent-l2s" id="markdown-toc-testing-soft-fork-dependent-l2s">Testing Soft-Fork Dependent L2’s</a></li> <li><a href="#potential-soft-forks" id="markdown-toc-potential-soft-forks">Potential Soft-Forks</a></li> <li><a href="#footnotes" id="markdown-toc-footnotes">Footnotes</a></li> </ol> </div> <h2 id="definitions">Definitions</h2> <h3 id="what-is-layer-2">What is Layer 2?</h3> <p>Often the term “Layer 2” is defined broadly, to the point where even a bank-like entity (e.g. Liquid) could be defined as a Layer 2. For the purposes of this article we will adopt a strict definition: a Layer 2 (L2) is a Bitcoin-denominated system, with the purpose of allowing BTC to be transacted more often than the number of on-chain transactions with other parties. Such that either:</p> <ol> <li>No-one is able to profitably steal funds in the system, taking into account <em>in-system</em> punishments and costs. Out-of-system costs and punishments like reputation loss, legal consequences, etc. are <em>not</em> considered in our definition.</li> <li><strong>(Preferred)</strong> The true owners of the funds are able to unilaterally withdraw their funds, minus transaction fees, without the cooperation of any third parties.</li> </ol> <p>The first option is required because we want our L2 systems to be able to represent amounts and transactions of such small value that they are unable to be represented on-chain. For example, in Lightning, HTLCs can have a value too small to represent on-chain. In that circumstance the HTLC value is added to the transaction fee of the commitment transaction. While a Lightning node can “steal” a dust HTLC by closing a channel at the right moment, doing so is more expensive<sup id="fnref:dust-htlc-theft" role="doc-noteref"><a href="#fn:dust-htlc-theft" class="footnote">1</a></sup> than the HTLC is worth, making the theft unprofitable.</p> <p>That said, unilateral withdrawal is always our primary design goal.<sup id="fnref:fidelity-bonded-banking" role="doc-noteref"><a href="#fn:fidelity-bonded-banking" class="footnote">2</a></sup></p> <p>With this definition things like Lightning are considered L2 systems. However systems such as Liquid, Cashu, and Fedimint are <em>not</em> L2’s, because another party or parties has control of your funds. Client-side validation schemes like RGB are also <em>not</em> L2’s under this definition, because they are unable to trustlessly transact BTC itself. Finally, <a href="https://medium.com/@RubenSomsen/statechains-non-custodial-off-chain-bitcoin-transfer-1ae4845a4a39">Statechains</a> fails to make the cut, because the Statechain entity can steal funds if they do not follow the protocol.</p> <h3 id="what-are-covenants">What are Covenants?</h3> <p>…and why do more scalable L2 systems need them?</p> <p>In Bitcoin scripting, covenants are mechanisms by which the way a txout can be spent is is restricted in advance, such that the form of transactions used to spend that txout are pre-defined or otherwise restricted in a way that is not purely limited to signatures. L2 systems that share UTXOs between multiple parties need covenants because they need ways of constraining how the UTXO can be spent to implement the rules and incentives of the L2 protocol.</p> <h4 id="recursive-covenants">Recursive Covenants</h4> <p>A recursive covenant is a covenant with the property that the rules constraining how a UTXO can be spent can be applied recursively, to child UTXOs of the spending transaction indefinitely. Recursive covenants have <a href="https://bitcointalk.org/index.php?topic=278122.0">long been considered to be undesirable by some</a> because they can encumber coins indefinitely. Or at least, indefinitely without the permission of a third party such as a government.</p> <h2 id="goals">Goals</h2> <p>Lightning is the current “best in class” Layer 2 system out there. However it has limitations. Namely:</p> <ol> <li><strong>Scaling</strong> - Lightning currently requires at least one UTXO per end user.<sup id="fnref:one-utxo-per-user" role="doc-noteref"><a href="#fn:one-utxo-per-user" class="footnote">3</a></sup></li> <li><strong>Liquidity</strong> - Lightning requires that funds be tied up in channels.</li> <li><strong>Interactivity</strong> - Lightning requires the recipients of payments to be online in order to receive them trustlessly.</li> </ol> <p>In evaluating Layer 2 systems, our goal will be to improve on these key limitations, ideally without adding new limitations.</p> <h3 id="lightnings-scaling-limits">Lightning’s Scaling Limits</h3> <p>What does “one UTXO per end user” mean in practice? Since Lightning channels can operate indefinitely, one way of looking at this is to ask how many new channels can be created per year<sup id="fnref:bosworth-ln-analysis" role="doc-noteref"><a href="#fn:bosworth-ln-analysis" class="footnote">4</a></sup>. Creating a taproot output has a marginal cost of \(43\mathrm{vB}\); if channel creation is amortized, with many channels created in a single transaction, the other transaction overhead can be made negligible and fairly large numbers of channels can be opened per year to on-board new users. For example, suppose that 90% of block capacity went to opening new taproot Lightning channels:</p> \[52{\small,}560\frac{\mathrm{blocks}}{\mathrm{year}} \times 1{\small,}000{\small,}000\frac{\mathrm{vB}}{\mathrm{block}} \times 90\% \times 1\frac{\mathrm{channel}}{43\mathrm{vB}} = 1.1\,\mathrm{billion}\frac{\mathrm{channels}}{\mathrm{year}}\] <p>It’s estimated that <a href="https://www.gsma.com/newsroom/press-release/smartphone-owners-are-now-the-global-majority-new-gsma-report-reveals/">about half of the global population own a smartphone</a>, 4.3 billion people. So we can in fact on-board a significant percentage of the entire population that is likely to be able to make use of a Lightning channel per year.</p> <p>However, channels do not last forever. On occasion users will want to switch wallets, increase or decrease channel capacity, etc. The most efficient method to change the capacity of a channel is via <a href="https://bitcoinops.org/en/topics/splicing/">splicing</a>, notably implemented in <a href="https://acinq.co/blog/phoenix-splicing-update">Phoenix Wallet</a>.</p> <p>Like channel opens, splicing could also be done in an amortized fashion to improve efficiency, with multiple splice operations sharing a single transaction to reduce the number of inputs and outputs necessary to add and remove funds<sup id="fnref:splice-netting" role="doc-noteref"><a href="#fn:splice-netting" class="footnote">5</a></sup>. Thus the delta blockspace required per users’ splice, assuming the use of <a href="https://bitcoinops.org/en/topics/musig/">musig</a>, is the \(43\mathrm{vB}\) taproot output plus the \(57.5\mathrm{vB}\) taproot keypath spend, for a total of \(100.5\mathrm{vB}\). If we again assume a 90% blockspace usage, we get:</p> \[52{\small,}560\frac{\mathrm{blocks}}{\mathrm{year}} \times 1{\small,}000{\small,}000\frac{\mathrm{vB}}{\mathrm{block}} \times 90\% \times 1\frac{\mathrm{splice}}{100.5\mathrm{vB}} = 470\,\mathrm{million}\frac{\mathrm{splices}}{\mathrm{year}}\] <p>Finally, note how switching Lightning channels between wallets can be done in a single transaction by either trusting the next wallet to sign a commitment transaction after the funds have been sent to the commitment address, or with co-operative close-to-new-channel support in both wallet implementations.</p> <p>Of course, there are competing use-cases for Bitcoin beyond Lightning channels, and how that will translate into fee-rates is difficult to know. But these numbers give us a rough ball-park that suggests that with current technology, it is at least technically possible to support hundreds of millions of self-sovereign Lightning users.</p> <h2 id="l2-overview">L2 Overview</h2> <p>Under our definition of L2 systems, there are two main design patterns being discussed in the Bitcoin development community:</p> <ol> <li>Channels</li> <li>Virtual UTXOs</li> </ol> <p>In the channel pattern, of which Lightning is the main example, the protocol progresses by exchanging pre-signed transactions between the parties that <em>could</em> be mined, but are not in the “happy path”. These pre-signed transactions split a UTXO between the parties; transactions happen by repeatedly changing the balance of that split, with new pre-signed transactions. Since there will be many different possible valid transactions spending the same UTXO, some incentive mechanism is needed to make sure the correct transaction is the one actually mined.</p> <p>In the Virtual UTXO (V-UTXO) design pattern, of which Ark is the most prominent example, V-UTXOs are created via covenants or multi-party agreement, via the creation of transactions that <em>could</em> be mined to unilaterally withdraw the V-UTXO funds by putting them on-chain, but are not in the “happy path”. In that respect, V-UTXO’s are similar to channels. But unlike channels, V-UTXO schemes do transactions by spending the V-UTXOs themselves, in (conceptually) a single<sup id="fnref:vutxo-single-tx" role="doc-noteref"><a href="#fn:vutxo-single-tx" class="footnote">6</a></sup> pre-signed transaction.</p> <p>The “happy path” design pattern is the use of an “all parties agree” script path, such as a N-of-N multisig; taproot is designed specifically for this concept, allowing the key path to be a N-of-N multisig via musig. Assuming that all parties agree, the happy path allows for the coins to be efficiently (and privately) spent.</p> <p>Interestingly, since virtual UTXOs are “real” in many senses, it is quite easy to build channels on top of virtual UTXOs by simply creating virtual UTXOs that, if mined, would lead to the creation of the UTXOs required for the channels. In that sense, virtual UTXO schemes are a slightly lower layer than channels.</p> <h3 id="lightning">Lightning</h3> <p>The status quo, implemented in production as the Lightning Network, primarily based on the <a href="https://github.com/lightning/bolts/">BOLTs standards</a>. Lightning is a combination of a number of things, including Lightning channels and HTLCs, the P2P routing network, onion routing, invoice standards, etc. Notably, Lightning is <em>not</em> a consensus system, so different elements of the “Lightning system” need not be adopted in the exact same way by all users. For the purpose of this article, when we say “Lightning” we’ll use it in the broad sense, including easily foreseen upgrades to the current (typical) Lightning protocol(s) that are widely used.</p> <p>As discussed above, the key characteristic of Lightning is its end-user scalability limit, due to the need to have at least one UTXO per user. That said, for the “core” routing element of Lightning — the public Lightning nodes that route the vast majority of transactions — these scalability limits aren’t much of a concern as Lightning functions just fine if there are far more end-users than routing nodes, because each public channel used for payment routing can easily support a large number of transactions per second. This is also why so many future L2 systems are expecting to also participate in the Lightning network. We also see this in how existing not-quite-L2 systems like Cashu rely heavily on the Lightning network to actually be useful: the primary usage of Cashu is probably to send and receive Lightning payments.</p> <h4 id="non-interactive-channels"><a href="https://utxos.org/uses/non-interactive-channels/">Non-Interactive Channels</a></h4> <p>This construction improves on Lightning channels by using <code class="language-plaintext highlighter-rouge">OP_CTV</code> to reduce the interactivity requirements. However, as it doesn’t improve on the 1-UTXO-per-user scaling limit, we won’t discuss it further.</p> <h3 id="channel-factories"><a href="https://bitcoinops.org/en/topics/channel-factories/">Channel Factories</a></h3> <p>Here we have multiple parties negotiate a single n-of-n multisig address, along with a transaction spending that multisig address to create n different UTXO’s splitting up the funds. Those UTXOs in turn are used for payment channels. The channels can be used with the same security as if they had been directly opened on-chain, because in the event that the channel state needs to be put on-chain, the split transaction can be mined. This potentially saves on-chain space when the channels are closed, as the \(n\) parties can — in theory — co-operatively close all \(n\) channels at once.</p> <p>Since channel factories are negotiating UTXO’s that <em>could</em> be mined, but are not expected to actually be mined in the happy path, they are a <em>very</em> primitive example of V-UTXOs.</p> <p>Channel factories by themselves do not require any soft-forks to be possible. However, the simple channel factories described above are probably impractical beyond small numbers of parties due to the coordination required to actually achieve a scaling benefit. Thus, covenant proposals such as <a href="https://bitcoinops.org/en/newsletters/2022/03/02/#proposed-opcode-to-simplify-shared-utxo-ownership">OP_Evict</a> or CTV (via txout trees) aim to allow more fine-grained outcomes where individual parties can be forced on-chain, without forcing everyone on-chain at once.</p> <h3 id="eltooln-symmetry"><a href="https://bitcoinops.org/en/topics/eltoo/">Eltoo/LN-Symmetry</a></h3> <p><em>Since Eltoo is a terribly confusing name, we’ll only use the updated name LN-Symmetry going forward.</em></p> <p>While Poon-Dryja channels encourage the correct state to be published on-chain by punishing incorrect states, LN-Symmetry instead allows incorrect states to be updated with an additional transaction. This has the advantage of simplifying Lightning channels by removing the complexity of penalties. However, this is likely to be a disadvantage in untrusted scenarios, as penalties are arguably needed to discourage fraud.</p> <p>LN-Symmetry needs a soft-fork to enable <a href="https://bitcoinops.org/en/topics/sighash_anyprevout/">SIGHASH_ANYPREVOUT</a>, which is required to allow state transactions to re-spend other state transactions during updates.</p> <p>By itself, LN-Symmetry offers no scaling improvements on conventional Lightning channels. But <a href="https://bitcoinops.org/en/newsletters/2018/12/28/#april">proponents have argued</a> that it makes things like channel factories easier to implement.</p> <h3 id="ark"><a href="https://www.arkpill.me/">Ark</a></h3> <p>Ark takes a new approach to transaction scaling: fully transferable virtual UTXOs (V-UTXOs), that can be merged and split in atomic<sup id="fnref:ark-atomicity" role="doc-noteref"><a href="#fn:ark-atomicity" class="footnote">7</a></sup> off-chain transactions. In Ark a central co-ordinator, the Ark Service Provider (ASP), provides V-UTXOs for users with a defined lifetime, e.g. 4 weeks. These periods are known as <em>rounds</em>. These V-UTXOs are created via pool txouts, one per round, via some kind of mechanism such as CTV to allow a single on-chain txout to commit to a tree of V-UTXOs. The round expiration is how Ark achieves a scaling advantage: at the end of a round, the pool txout unlocks, allowing the ASP to unilaterally spend it with a single signature in a small transaction. Due to the round expiry time, the V-UTXOs themselves expire when the pool txouts creating them expire: users who own a V-UTXO must either spend that V-UTXO prior to the pool txout expiry time being reached, or put it on-chain (unilateral withdrawal).</p> <p>To transact V-UTXOs between parties, the Ark coordinator co-signs transactions that spend one or more V-UTXOs, such that the transactions are only valid if one or more other V-UTXOs are created in a <em>different</em> round. In combination with some careful timeouts — see the Ark docs for the full details — this dependency is what makes spending V-UTXO’s trustless: the V-UTXO’s can’t be claimed on-chain unless new V-UTXOs are created in a different pool transaction. There’s a few potential ways to actually implement that dependency. But the exact details aren’t relevant to the purposes of this article.</p> <p>Notice how this means that a given ASP will have many different active rounds happening at once. New rounds are frequently created to allow funds in existing rounds to be transferred. But the existing rounds overlap the new rounds, as they will generally expire sometime after new rounds, and new pool txouts, are created.</p> <h4 id="ark-economics">Ark Economics</h4> <p>When a V-UTXO is spent, the ASP must provide matching BTC in a new pool txout representing a new round. But they can’t recover the value of the spent V-UTXO until the round expires. Thus the economics of V-UTXO spends has a time-value-of-money cost, due to the liquidity the ASP has to provide.</p> <p>Specifically, the cost is incurred when the V-UTXO is <em>spent</em>. While the V-UTXO is unspent, it represents a very real potential UTXO that could be put onchain to unilaterally withdraw the funds; the user owns those funds. However, to spend the V-UTXO, the ASP must create a <em>new</em> pool txout, using funds the ASP obtains elsewhere, while the funds in the spent V-UTXO are not available to the ASP until the expiry time is reached.</p> <p>Thus spending a V-UTXO requires a short term loan, borrowing funds to cover the time interval between now and when the round expires. This means that the liquidity cost to spend a V-UTXO actually declines as the V-UTXO gets older and the expiry time gets closer, eventually — in theory — reaching zero when the round finally expires.</p> <p>Finally, remember that the cost to spend a V-UTXO is related to the <em>total</em> size of the V-UTXO spent. <em>Not</em> the amount paid to the recipient. This means that wallets intended for transacting V-UTXOs directly (as opposed to managing one V-UTXO for the purposes of, e.g., a V-UTXO-based Lighting channel), have to make trade-offs in how they split up funds into V-UTXOs. A single V-UTXO minimizes the cost of unilateral withdrawal, while maximizing liquidity-based transaction fees; splitting up funds into many V-UTXOs does the opposite. This is entirely unlike the economics of on-chain Bitcoin, or Lightning transactions.</p> <p>What is this liquidity cost? As of writing, the Lightning wallet Phoenix charges a 1% fee to reserve channel liquidity for 1 year; at worst Phoenix would have to tie up their funds for 1 year. However, that assumes that the liquidity isn’t used. It’s quite possible that the cost-of-capital to Phoenix is in fact higher, and they are assuming that the average customer uses their incoming liquidity in less than one year. Phoenix also earns money off transaction fees, potentially subsidizing channel liquidity. Finally, Phoenix might not be profitable!</p> <p>The US Treasury Bill Rate gives us another estimate. As of writing the 3 Month Treasury Bill Rate is about 5% per year. Since there is an argument that this rate is inflated due to US dollars being inflationary, we’ll assume the cost of liquidity for BTC denominated funds is 3% per year for our analysis.</p> <p>If the round interval is 4 weeks, this means that a transaction would start off with a liquidity cost of \(3\% / \frac{52}{4} = 0.23\%\)<sup id="fnref:fixed-rate" role="doc-noteref"><a href="#fn:fixed-rate" class="footnote">8</a></sup>, eventually declining to zero. Assuming the user tries to move their funds to a new round two weeks prior to the round expiring, the user is paying about 1.5% per year in liquidity costs to achieve self-custody of their funds. On the other hand, if the user waits until the last moment<sup id="fnref:last-moment-ark-spend" role="doc-noteref"><a href="#fn:last-moment-ark-spend" class="footnote">9</a></sup>, the cost could be nearly zero, at the risk of missing the expiration time.</p> <p>Users may not see this as a trivial cost. And this cost assumes that fixed costs of each round have been made insignificant by amortising transaction fees and other costs over large numbers of participants.</p> <p>What if fixed costs aren’t so insignificant? Suppose that the ASP has 1000 users, and pool txouts are created once an hour on average. Over a 4 week period, that’s 672 on-chain transactions. Which means to simply hold their funds, the ASP’s users collectively have to pay for almost as many transactions as users! It would probably be cheaper for them to all open their own Lightning channels, even though the ASP is requiring them to wait an entire hour for a confirmation.</p> <h4 id="bootstrapping-ark">Bootstrapping Ark</h4> <p>A new ASP with few users faces a dilemma: either ASP rounds happen infrequently, and users have to wait a long time for the proposed round to gather enough V-UTXOs to achieve a useful scaling and transaction fee reduction. Or ASP pool transactions happen frequently, with high transaction fees paid per user. As we showed in the previous section, it can take a lot of users to amortize frequent rounds, and their underlying pool txouts.</p> <p>Because rounds expire, this problem is an ongoing one, even worse than that faced by Lightning channels: at least a Lightning channel can continue to be useful indefinitely, allowing a channel to be opened now and amortized gradually over many months. Secondly, because rounds expire, there is less flexibility as to <em>when</em> to create the new txouts backing these rounds: if fees are high for a week or two, users whose pool txouts are expiring have no choice but to (collectively) pay those high fees to maintain their custody over their funds. With Lightning channels, there is much more flexibility as to when to actually open a channel.</p> <p>While the authors of Ark initially imagined a very optimistic scenario where new rounds every few seconds, initial bootstrapping will probably have to happen with use-cases that can afford to wait multiple hours for an Ark transaction to confirm, if transaction fees are not subsidized.</p> <h4 id="interactivity">Interactivity</h4> <p>Non-custodial Ark is a highly interactive protocol: since your V-UTXOs expire, you have hard deadlines to interact with your ASP, or else the ASP could choose to take your funds. This interactivity can’t be outsourced either: while Lightning has <a href="https://docs.lightning.engineering/the-lightning-network/payment-channels/watchtowers">watchtowers</a> that discourage counterparties from trying to rip you off — even if your channel hasn’t been online — Ark coin owners must use their own private keys to refresh funds without trust. The closest thing possible in Ark to watchtowers would be to sign transactions allowing a watch tower to unilaterally withdraw your funds on-chain towards the expiration time, which has a significant transaction fee cost.</p> <p>Consider what happens to a V-UTXO if the owner goes offline: after the round expires, the ASP needs to recover the funds to get their liquidity back for further rounds. If a V-UTXO owner goes offline, putting that V-UTXO on-chain has significant transaction costs, as the ASP now needs to recover funds at multiple levels of the V-UTXO tree. The ASP can recreate the unspent V-UTXOs in a new round. But this isn’t trustless from the perspective of the V-UTXO owners, as they can’t spend those V-UTXO’s without obtaining data<sup id="fnref:asp-pop" role="doc-noteref"><a href="#fn:asp-pop" class="footnote">10</a></sup> from the ASP. The ASP could also simply record unspent V-UTXOs as a custodial balance. Or maybe even have a policy of seizing the funds!</p> <p>Personally, I suspect that given the non-trivial cost of self-custody in Ark, many users will instead choose ASPs with a policy of rolling over funds into a new round and simply accept the potential for fraud at the end of each round. This is cheaper than proactively moving their funds early enough to guarantee safety in the event that, e.g., they fail to turn their phone on in time for their wallet to move the funds to a new round.</p> <h4 id="advanced-ark">Advanced Ark</h4> <p>It may be feasible to reduce the liquidity requirements of Ark through more advanced covenants, if it is typical for liquidity to be used up part way through a round. For example, let’s suppose that 50% of the total V-UTXO value in a pool txout has been spent. If the ASP could redeem just that part of the round’s pool txout, they could recover liquidity quicker, reducing overall liquidity costs. While no concrete proposals on how to do this have been published, it certainly seems like it should be possible with Sufficiently Advanced™ covenants. Most likely through some kind of script revival soft-fork that adds many useful opcodes at once.</p> <p>Similarly, through Sufficiently Advanced™ covenants the entire txout tree structure could be replaced with some kind of rolling withdrawal scheme, potentially offering space savings. We’ll cover this in a further section, as this technique is potentially useful for other schemes.</p> <p>The end-of-round custody issue is another case where Sufficiently Advanced™ covenants could solve a problem: a covenant, in particular, a ZK-proof covenant, could force the ASP to recreate all unspent V-UTXO’s in the next round, removing the problem of custody reverting to them at the end of a round. While it is probably not possible to make this <em>trustless</em>, as the user will likely need some data from the ASP to spend their V-UTXO on the new round, it could prevent the ASP from financially gaining from fraud against offline users.</p> <h4 id="on-chain-fee-payment-in-unilateral-withdraw">On-Chain Fee Payment In Unilateral Withdraw</h4> <p>Similar to Lightning, the economics of on-chain fee payment and the actual value of a V-UTXO after fees determine whether Ark usage meets our definition of an L2 via unilateral withdrawal, or fraud failing to benefit the ASP. We’ll discuss the specifics of this further when we discuss the txout tree design pattern.</p> <h3 id="validity-rollups"><a href="https://github.com/john-light/validity-rollups/blob/fecc3433d8e95ab40263db8c2941794e0115d2d5/validity_rollups_on_bitcoin.md">Validity Rollups</a></h3> <p>A large class of sidechain-like constructs, generally proposed to use various forms of zero knowledge (ZK) proof technology to enforce the rules of the chain. The ZK-proof technology is the critical difference between validity rollup technology and other forms of sidechain: if the ZK-proof scheme works, the validity of the transactions can be guaranteed by math rather than trusting a third party. The “zero knowledge” aspect of a ZK proof is not actually a requirement in this use-case: it’s perfectly OK if the proof “leaks” information about what it is proving. It just happens to be that most of the mathematical schemes for this class of proof happen to be zero-knowledge proofs.</p> <p>From the point of view of Bitcoin, a validity rollup scheme requires a covenant, as we want to be able to create UTXO’s for the scheme that can only be spent if the rules of the scheme are followed. This is <em>not</em> necessarily a decentralized process. Many validity rollup schemes are in fact entirely centralized; the rollup proof is proving that the centralized transaction sequencer followed the rules for a particular sequence of transactions.</p> <p>As for what covenant… Zero-Knowledge Proof technology is still a very new field, with advancements still being frequently made. So it is highly unlikely that we will see any opcodes added to Bitcoin that directly validate any specific ZK-proof schemes. Instead it is generally accepted that specific schemes would instead use more general opcodes, in particular <code class="language-plaintext highlighter-rouge">OP_CAT</code>, to validate ZK-proofs via scripts. For example, <a href="https://starkware.co">StarkWare</a> is <a href="https://starkware.co/blog/scaling-bitcoin-for-mass-use/">campaigning</a> to have <code class="language-plaintext highlighter-rouge">OP_CAT</code> adopted.</p> <p>Validity rollups is such a large potential topic, with so many low-substance/high-hype projects, that we won’t discuss it further beyond pointing out what opcodes potentially make this design class viable.</p> <h3 id="bitvm"><a href="https://bitvm.org/">BitVM</a></h3> <p>Very roughly speaking BitVM is a way to construct a lightning channel between two parties such that the rules of the Lightning channel are enforced by a zero-knowledge proof. Since it doesn’t actually need covenants to be implemented on Bitcoin today, and because it can’t directly be used to create an L2 system that scales beyond the 1-UTXO-per-user limit, we won’t discuss it further.</p> <h3 id="hierarchical-channels">Hierarchical Channels</h3> <p>Hierarchical Channels<sup id="fnref:hierarchical-channels" role="doc-noteref"><a href="#fn:hierarchical-channels" class="footnote">11</a></sup> aims to make channel resizing fast and cheap: “Hierarchical channels do for channel capacity what the LN does for bitcoin”. However they still don’t fundamentally exceed the 1 UTXO-per-user limit. They also don’t require any changes to the Bitcoin protocol anyway. So we’re not going to discuss them further. Their proponents should simply implement them! They don’t need our permission.</p> <h3 id="coinpool"><a href="https://coinpool.dev/v0.1.pdf">CoinPool</a></h3> <p>CoinPool allows multiple users to share a single UTXO, transfer funds between different users, and unilaterally withdraw. The CoinPool paper proposal requires three new softfork features, <code class="language-plaintext highlighter-rouge">SIGHASH_ANYPREVOUT</code>, a <code class="language-plaintext highlighter-rouge">SIGHASH_GROUP</code> allowing a signature to only apply to specific UTXOs, and an <code class="language-plaintext highlighter-rouge">OP_MerkleSub</code> to validate the removal of specific branches from a merkle tree; the latter could also be accomplished with <code class="language-plaintext highlighter-rouge">OP_CAT</code>.</p> <p>At the moment CoinPool development seems to have stagnated, with the last commit to the specification website being two years ago.</p> <h3 id="enigma-network">Enigma Network</h3> <p>While I was asked to cover the Engima Network, there seems to be a lack of documentation as to what the proposal really is. Bitfinex’s <a href="https://blog.bitfinex.com/education/what-is-the-enigma-network/">blog post</a> makes a lot of claims; the <a href="https://www.media.mit.edu/projects/enigma/overview/">MIT page</a> is empty. Since the blog post doesn’t really make it clear what exactly is supposed to be going on, we won’t discuss it further.</p> <h2 id="mempool-considerations">Mempool Considerations</h2> <p>Current mempool policy in Bitcoin Core is not ideal for L2 systems. Here we’ll go over some of the main challenges they face, and potential improvements.</p> <h3 id="transaction-pinning">Transaction Pinning</h3> <p>Ultimately an economic exploit, transaction pinning attacks, refer to a variety of situations where someone can intentionally (<a href="https://x.com/peterktodd/status/1793380279018803208">or unintentionally</a>) make it difficult to get a desired transaction mined due to the prior broadcast of a conflicting transaction that does <em>not</em> get mined. This is an economic exploit, because in a true transaction pinning situation, there exists a desirable transaction that miners would profit from if they mined it; the conflicting pinning transaction is <em>not</em> mined in a reasonable amount of time, if ever.</p> <p>The simplest example of pinning comes from the fact without full-RBF, transaction replacement can be turned off. Thus, we can have a low fee-rate transaction, with replacement turned off, that will not be mined yet can’t be replaced. Essentially 100% of hash power has fixed this issue by enabling full-RBF, and as of writing, full-RBF should be enabled by default in the next release of Bitcoin Core (after <a href="https://stacker.news/items/637115">11 years of effort</a>!).</p> <p>That leaves BIP-125 Rule #3 pinning, the only remaining pinning issue that is relevant to multiparty L2 protocols and unfixed in Bitcoin Core. For reference, BIP-125 Rule #3 states the following:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>A replacement transaction is required to pay the higher absolute fee (not just fee rate) than the sum of fees paid by all transactions being replaced. </code></pre></div></div> <p>This rule can be exploited by broadcasting a large, low fee-rate pinning transaction spending the output(s) relevant to the multiparty protocol (alternatively, a group of transactions). Since the transaction has a low fee-rate, it will not be mined in a timely fashion, if ever. Yet, since it has a high total fee, replacing it with a different transaction is uneconomical.</p> <p>Rule #3 pinning is fairly easily fixed via <a href="/2024/one-shot-replace-by-fee-rate">replace-by-fee-rate</a>, and this fix works in all situations. Unfortunately it’s unclear if RBFR will be adopted by Core in the near future, as they’ve spent a substantial amount of effort on a inferior partial solution, <a href="/2023/v3-transactions-review">TRUC/V3 Transactions</a>.</p> <h3 id="fee-payment-rbf-cpfp-sighash_anyonecanpay-anchors-and-sponsorship">Fee Payment: RBF, CPFP, <code class="language-plaintext highlighter-rouge">SIGHASH_ANYONECANPAY</code>, Anchors, and Sponsorship</h3> <p>Since fee-rates are unpredictable, reliably and economically paying in situations where transactions are pre-signed is difficult. The gold standard for fee-payment is to use RBF, starting with an initial “low-ball” estimate, and replacing the transaction with higher fee versions as needed until it gets mined. For example, the OpenTimestamps calendar software has used RBF this way for years, and LND added support for <a href="https://lightning.engineering/posts/2024-05-30-lnd-0.18-launch/">deadline aware RBF in v0.18</a>.</p> <p>RBF is the gold standard for fee-payment because it is the most blockspace efficient in almost all<sup id="fnref:rbf-vs-out-of-band" role="doc-noteref"><a href="#fn:rbf-vs-out-of-band" class="footnote">12</a></sup> situations: the replacement transaction(s) do not need any extra inputs or outputs, relative to what would have been necessary if the correct fee had been guessed the first try.</p> <p>Efficiency is important, because inefficiencies in fee payment make <a href="https://bitcoinops.org/en/topics/out-of-band-fees/">out-of-band fee payment</a> a profitable source of revenue for large miners; smaller, decentralized, miners can’t profit from out-of-band fee payments due to the impracticality and uselessness of paying a small miner to get a transaction confirmed. Out-of-band fee payment also seems to invite AML/KYC issues: at present, most of the out-of-band fee payment systems actually available right now require some kind of AML/KYC process to make a fee payment, with the notable exception of the <a href="https://mempool.space/accelerator">mempool.space accelerator</a>, which as of writing (Aug 2024), accepts Lightning without an account.</p> <p>To make use of RBF directly in situations with pre-signed transactions, you need to pre-sign fee-variants covering the full range of potential fees. While this is quite feasible in many cases as the number of variants necessary is usually small<sup id="fnref:number-of-fee-variants" role="doc-noteref"><a href="#fn:number-of-fee-variants" class="footnote">13</a></sup>, so far the production Lightning protocol — and other proposed protocols — have opted instead to use <a href="https://bitcoinops.org/en/topics/cpfp/">Child-Pays-For-Parent</a> (CPFP), usually via anchor outputs.</p> <p>The idea behind an anchor output is you add one or more outputs to a transaction with a minimal or zero value, with the intent of paying fees via CPFP by spending those output(s) in secondary transactions. This of course is very inefficient when applied to protocols such as LN that have small on-chain transactions, almost <a href="/2023/v3-transactions-review#efficiency">doubling the total size of a ephemeral-anchor-output-using LN commitment transaction</a>. It would be less of a concern when applied protocols making use of larger transactions, such as anything using <code class="language-plaintext highlighter-rouge">OP_CAT</code> to implement covenants.</p> <p>A less-obvious problem with anchor outputs is the need to keep around additional UTXOs to pay fees with. In a typical “client” application, this can be a significant overall burden, as without the anchor outputs there is often no need at all to maintain more than one UTXO. Indeed, it is likely that some existing consumer-focused Lightning wallets are vulnerable to theft by the remote side of the channel in high-fee environments due to inability to pay fees.</p> <p><code class="language-plaintext highlighter-rouge">SIGHASH_ANYONECANPAY</code> can be used for fee payment in some cases by allowing additional inputs to be added to signed transactions; <code class="language-plaintext highlighter-rouge">SIGHASH_SINGLE</code> allows outputs to also be added. Lightning uses this for HTLC transactions. At the moment this practice can be vulnerable to transaction pinning if not handled carefully<sup id="fnref:safe-sighash-anyonecanpay" role="doc-noteref"><a href="#fn:safe-sighash-anyonecanpay" class="footnote">14</a></sup>, as an attacker could add a large number of inputs and/or outputs to a transaction to create a high-fee/low-fee-rate pin. RBFR fixes this issue; the approach used in TRUC/V3 transactions is unable to fix this issue. This style of fee-payment isn’t as efficient as RBF. But it can be more efficient than anchor outputs.</p> <p>Finally there have been a variety of soft-fork proposals to add a <a href="https://bitcoinops.org/en/topics/fee-sponsorship/">fee sponsorship</a> system to the Bitcoin protocol. This would allow transactions to declare dependencies on other transactions, such that the sponsor transaction could only be mined if the sponsored transaction was also mined (most likely in the same block). This could be much more efficient than a traditional CPFP as the sponsor transaction could declare that dependency using significantly less vbytes than the size of a transaction input.</p> <h3 id="replacement-cycling">Replacement Cycling</h3> <p>The Replacement Cycling Attack<sup id="fnref:replacement-cycling" role="doc-noteref"><a href="#fn:replacement-cycling" class="footnote">15</a></sup> takes advantage of transaction replacement to attempt to replace a desired L2 transaction long enough to get an undesired one mined instead. Essentially, replacement cycling attacks are, for the attacker, an alternative to transaction pinning techniques in that they aim to prevent a desired, honest, transaction from being mined long enough to allow an undesired, dishonest, transaction to be mined instead. Unlike transaction pinning attacks, a replacement cycling attack can’t happen by accident.</p> <p>The canonical example is against a Hashed-Time-Locked-Contract (HTLC). While it’s easy to think of an HTLC as being a contract to <em>either</em> allow a transaction to be spent via the revealing of a preimage, <em>or</em> via a timeout. In reality due to Bitcoin scripting limitations, an HTLC allows a transaction to <em>always</em> be spent via revealing a preimage, and then after a timeout, <em>additionally</em> via the timeout mechanism.</p> <p>Replacement cycling takes advantage of this using the preimage <em>after</em> the timeout, to replace the transaction trying to redeem the HLTC output via the timeout mechanism without the victim learning the preimage. A successful replacement cycling attack does this long enough for a different channel’s HTLC to time out.</p> <p>A main challenge in profitably exploiting replacement cycling is that each replacement round costs money. A deadline aware Lightning implementation will spend higher and higher fees attempting to spend the expired HTLC output before the expiry of the next HTLC output in turn expires. Secondly, anyone can defeat the attack by simply rebroadcasting the replaced transaction<sup id="fnref:altruistic-rebroadcasting" role="doc-noteref"><a href="#fn:altruistic-rebroadcasting" class="footnote">16</a></sup> once the replacement cycle is finished.</p> <p>As with transaction pinning, replacement cycling is also an economic exploit on miners. At the end of each replacement cycle, there exists a transaction that has been removed from mempools, yet is fully valid and could be mined if only miners still had it in their mempools.</p> <h2 id="feature-patterns-and-soft-forks">Feature Patterns and Soft Forks</h2> <p>Now that we’ve given you an overview of the variety of covenant-dependent L2 systems out there, and mempool challenges, we’re going to try to distil that information down to a set of notable soft fork features (mainly new opcodes) and design patterns that these L2 systems share. For soft-fork proposals, we’ll also discuss the proposal-specific technical risks and challenges of getting each proposal deployed.</p> <h3 id="op_expire"><code class="language-plaintext highlighter-rouge">OP_Expire</code></h3> <p>We’ll get this out of the way first. <code class="language-plaintext highlighter-rouge">OP_Expire</code> was proposed<sup id="fnref:op-expire" role="doc-noteref"><a href="#fn:op-expire" class="footnote">17</a></sup> as a simple way of eliminating the replacement cycling attack by fixing the problem at the source: the fact that HTLC’s can be spent in two different ways at once. In the context of L2 systems, this is relevant for anything using an HTLC-like mechanism, and possibly other use-cases. <code class="language-plaintext highlighter-rouge">OP_Expire</code> would make it possible for a transaction output to be unspendable <em>after</em> a point in time, allowing the HTLC spending conditions to be a true exclusive-OR rather than a “programmers OR”.</p> <p>An actual <code class="language-plaintext highlighter-rouge">OP_Expire</code> soft-fork would most likely consist of two features, similar to how the <a href="https://github.com/bitcoin/bips/blob/master/bip-0065.mediawiki"><code class="language-plaintext highlighter-rouge">OP_CheckLockTimeVerify</code></a> and <a href="https://github.com/bitcoin/bips/blob/master/bip-0112.mediawiki"><code class="language-plaintext highlighter-rouge">OP_CheckSequenceVerify</code></a> opcodes come in two parts:</p> <ol> <li>A expiration height field for transactions, most likely implemented in the taproot annex.</li> <li>A <code class="language-plaintext highlighter-rouge">OP_Expire</code> opcode that checks that the expiration height is set to at least the desired height.</li> </ol> <p>While <code class="language-plaintext highlighter-rouge">OP_Expire</code> itself barely qualifies as a covenant, it does appear to be useful for many covenant-dependent L2 systems. However, it may not be useful enough given that replacement cycling can also be mitigated by altruistic rebroadcasting<sup id="fnref:altruistic-rebroadcasting:1" role="doc-noteref"><a href="#fn:altruistic-rebroadcasting" class="footnote">16</a></sup></p> <p>A very notable challenge with deploying and using <code class="language-plaintext highlighter-rouge">OP_Expire</code> is reorgs: the Bitcoin technical community, starting with Satoshi<sup id="fnref:coinbase-timelock" role="doc-noteref"><a href="#fn:coinbase-timelock" class="footnote">18</a></sup>, has tried to ensure that the Bitcoin consensus protocol is designed in such a way that after a deep reorg, previously-mined transactions can be mined into new blocks. This design principal attempts to avoid the nightmare scenario of a large number of confirmed coins becoming permanently invalid — and thus people relying on those coins losing money — if a consensus failure leads to a large reorg.</p> <p>In the event of a large reorg, transactions using expiration could become unminable due to their expiry height being reached. The <code class="language-plaintext highlighter-rouge">OP_Expire</code> proposal, proposes to mitigate this issue by treating the outputs of expiration-using transactions similarly to coinbase transactions, also making them unspendable for ~100 blocks.</p> <p>A significant barrier to deploying transaction expiration is coming to consensus on whether or not this trade-off is acceptable, or even needed. The types of transactions where <code class="language-plaintext highlighter-rouge">OP_Expire</code> would be useful already involve long-ish timeouts where user funds are frozen. Adding even more time to these timeouts isn’t desirable. Also, double-spends have always been another way to invalidate coins after a reorg: with the increased use of RBF and proposed use of keyless anchor outputs, would transaction expiration make a significant difference?</p> <h3 id="sighash_anyprevout"><code class="language-plaintext highlighter-rouge">SIGHASH_ANYPREVOUT</code></h3> <p><a href="https://github.com/bitcoin/bips/blob/master/bip-0118.mediawiki">BIP-118</a> proposes two new signature hashing modes, both of which do <em>not</em> commit to the specific UTXO being spent. <code class="language-plaintext highlighter-rouge">SIGHASH_ANYPREVOUT</code>, which (essentially) commits to the <code class="language-plaintext highlighter-rouge">scriptPubKey</code> instead, and <code class="language-plaintext highlighter-rouge">SIGHASH_ANYPREVOUTANYSCRIPT</code>, which allows any script. As discussed above, this was originally proposed for use by LN-Symmetry to avoid the need to separately sign every single prior channel state that may need to be reacted to.</p> <p><code class="language-plaintext highlighter-rouge">SIGHASH_ANYPREVOUT</code> is also potentially useful in cases where we want to use pre-signed RBF fee-rate variants in conjunction with pre-signed transactions, as the fact that the signature no longer depends on a specific txid avoids a <a href="https://petertodd.org/2023/v3-transactions-review#htlcs-and-replace-by-fee">combinatorial explosion of fee-rate variants</a>. However, the current BIP-118 proposal doesn’t address this usecase, and may be incompatible with it due to the fact that <code class="language-plaintext highlighter-rouge">SIGHASH_ANYPREVOUT</code> is proposed to also commit to the value of the UTXO.</p> <p>An initial objection to <code class="language-plaintext highlighter-rouge">SIGHASH_ANYPREVOUT</code> was the idea that wallets would get themselves into trouble by using it in inappropriate ways. The issue is that once a <em>single</em> <code class="language-plaintext highlighter-rouge">SIGHASH_ANYPREVOUT</code> signature has been published, it can be used to spend <em>any</em> txout with the specified script. Thus if a second outputs with the same script is accidentally created, <code class="language-plaintext highlighter-rouge">SIGHASH_ANYPREVOUT</code> allows for a trivial replay attack to steal those coins. However, as there are so many other footguns inherent to wallets and L2 implementations, this concern seems to have died out.</p> <p>At the moment, the general technical community seems reasonably positive about implementing BIP-118. However, as discussed above in our discussion of LN-Symmetry, there is debate about whether it’s main use-case — LN-Symmetry — is actually a good idea.</p> <h3 id="op_checktemplateverify"><a href="https://bitcoinops.org/en/topics/op_checktemplateverify/"><code class="language-plaintext highlighter-rouge">OP_CheckTemplateVerify</code></a></h3> <p>Our first covenant-specific opcode proposal, <code class="language-plaintext highlighter-rouge">OP_CheckTemplateVerify</code> — or “CTV” as it’s commonly referred to — aims to create a very specific, restricted, covenant opcode by doing exactly one thing: hashing the spending transaction in a specified way that does not commit to the input UTXOs, and checking the resulting digest against the top stack element. This allows the spending transaction to be constrained in advance, <em>without</em> making true recursive covenant restrictions possible.</p> <p>Why aren’t recursive covenants possible in CTV? Because hash functions: the CTV checks the spending transaction against a template hash, and there’s no way<sup id="fnref:recursive-hash-function" role="doc-noteref"><a href="#fn:recursive-hash-function" class="footnote">19</a></sup> of creating a template containing a CTV with a hash of itself.</p> <p>That said, this isn’t necessarily a real limitation: you can easily hash a chain of CTV template hashes to a depth of tens of millions of transactions in just a few seconds on a modern computer. With <a href="https://github.com/bitcoin/bips/blob/master/bip-0068.mediawiki">relative nSequence timelocks</a> and the limited blocksize actually reaching the end of such a chain could easily be made to take thousands of years.</p> <p>The current CTV proposal in <a href="https://github.com/bitcoin/bips/blob/5d774404790ce79d45588974b9964260a55bcbcd/bip-0119.mediawiki">BIP-119</a> has only one hashing mode, known as the <code class="language-plaintext highlighter-rouge">DefaultCheckTemplateVerifyHash</code>, which essentially commits to every aspect of the spending transaction in the template hash. From a practical point of view this means that in many circumstances the only available mechanism for fee payment will be CPFP. As mentioned above, this is a potential problem due to it making out-of-band fee payment a non-trivial cost savings in cases where the CTV-using transactions are small.</p> <p>It’s fair to say that CTV has the broadest support among the technical community of any covenant opcode proposal because of its relative simplicity and wide range of use-cases.</p> <h4 id="lnhance"><a href="https://github.com/bitcoin/bitcoin/pull/29198">LNHANCE</a></h4> <p>One proposal to implement CTV is to combine it with two more opcodes, <code class="language-plaintext highlighter-rouge">OP_CheckSigFromStack(Verify)</code> and of <code class="language-plaintext highlighter-rouge">OP_InternalKey</code>. The problem is, as of writing, the documentation in that pull-req and associated BIPs simply isn’t sufficient to argue for or against this proposal. The BIPs are entirely lacking any rational for what the opcodes are expected to actually do in real-world examples, let alone in-depth example scripts.</p> <p>While the authors probably have good reasons for their proposal, the onus is on them to actually explain those reasons and justify them properly. Thus we won’t discuss it further.</p> <h3 id="op_txhash"><a href="https://github.com/bitcoin/bips/pull/1500"><code class="language-plaintext highlighter-rouge">OP_TXHASH</code></a></h3> <p>Similar to CTV, this proposal achieves a non-recursive covenant functionality by hashing data from the spending transaction. Unlike CTV, the TXHASH proposal provides a “field selector” mechanism, allowing flexibility in exactly how the spending transaction is constrained. This flexibility achieves two main goals:</p> <ol> <li>Enabling the addition of fees to a transaction without breaking a multi-tx protocol.</li> <li>Multi-user protocols where users only constrain their own inputs and outputs.</li> </ol> <p>The main problem with <code class="language-plaintext highlighter-rouge">OP_TXHASH</code> is that the field selector mechanism adds quite a lot of complexity, making review and testing challenging compared to the much simpler CTV proposal. At the moment there simply hasn’t been much design analysis on how beneficial the field selector mechanism would actually be, or how exactly it would be used. Thus we won’t discuss it further.</p> <h3 id="op_cat"><code class="language-plaintext highlighter-rouge">OP_CAT</code></h3> <p>The concatenation operator, that concatenates the top two elements of the stack and pushes the concatenated result back on the stack. Bitcoin originally shipped with <code class="language-plaintext highlighter-rouge">OP_CAT</code> enabled. But Satoshi <a href="https://github.com/bitcoin/bitcoin/commit/4bd188c4383d6e614e18f79dc337fbabe8464c82">quietly removed it in 2010</a>, probably due to the fact that the initial implementation was vulnerable to DoS attacks due to the lack of restrictions on the size of the resulting script element. Consider the following script:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>DUP CAT DUP CAT... </code></pre></div></div> <p>Without an element size restriction, each <code class="language-plaintext highlighter-rouge">DUP CAT</code> iteration doubles the size of the top stack element, eventually using up all available memory.</p> <p>Concatenation is sufficient to implement many types of covenants, including recursive covenants, by doing the following:</p> <ol> <li>Assemble a <em>partial</em> transaction, <em>without witness data</em>, on the stack with one or more invocations of <code class="language-plaintext highlighter-rouge">OP_CAT</code> (and whatever covenant-specific logic is needed).</li> <li>Validate that the transaction on the stack matches the spending transaction.</li> </ol> <p>As it turns out, by <a href="https://medium.com/blockstream/cat-and-schnorr-tricks-i-faf1b59bd298">abusing the math of Schnorr signatures</a>, it’s possible to perform the second step with <code class="language-plaintext highlighter-rouge">OP_CheckSig</code> via carefully constructed signatures. However it’s more likely that an <code class="language-plaintext highlighter-rouge">OP_CAT</code> soft-fork would be combined with <code class="language-plaintext highlighter-rouge">OP_CheckSigFromStack</code>, allowing the second step to be performed by validating that a signature on the stack is a valid signature for the transaction<sup id="fnref:checksig-hashing" role="doc-noteref"><a href="#fn:checksig-hashing" class="footnote">20</a></sup>, and then reusing that same signature with <code class="language-plaintext highlighter-rouge">OP_CheckSig</code> to validate that the spending transaction matches.<sup id="fnref:ctv-match" role="doc-noteref"><a href="#fn:ctv-match" class="footnote">21</a></sup></p> <p>The fact that we only need to assemble the transaction <em>without</em> witness data is a key point: the covenant only needs to validate <em>what</em> the transaction does — its inputs and outputs — not the witness data (if any) that actually makes it valid.</p> <p>Modulo script size limits, the combination of <code class="language-plaintext highlighter-rouge">OP_CAT</code> and <code class="language-plaintext highlighter-rouge">OP_CheckSigFromStack</code> is sufficient to build many types of covenants, including recursive covenants. Compared to more efficient solutions like CTV it is more expensive. But the difference in cost is less than you would expect!</p> <p>Roughly speaking, using <code class="language-plaintext highlighter-rouge">OP_CAT</code> to do this requires all of the non-witness part of the spending transaction to be placed on the stack via the witness. For typical CTV use-cases such as txout trees, the spending transaction will have no witness data at all. Since witness space is discounted 75%, that increases our effective transaction fee for the child transaction by only 25%. Not bad!</p> <h4 id="is-op_cat-too-powerful">Is <code class="language-plaintext highlighter-rouge">OP_CAT</code> Too Powerful?</h4> <p>This is probably the biggest political and technical obstacle to deploying <code class="language-plaintext highlighter-rouge">OP_CAT</code>: it’s very hard to predict what use-cases will be made possible by <code class="language-plaintext highlighter-rouge">OP_CAT</code>. And once the “cat” is out of the bag, it’s very hard to put it back in.</p> <p>A great example is how <code class="language-plaintext highlighter-rouge">OP_CAT</code> is claimed to be sufficient to allow reasonably efficient and secure <a href="https://starkware.co/scaling-bitcoin-for-mass-use/">STARK verification to implemented in Bitcoin script</a>. Since STARKs are capable of proving extremely general statements, making it possible to implement STARKs efficiently has significant ramifications that go beyond the scope of L2 systems as it would allow many different systems to be built on top of Bitcoin. A strong argument against <code class="language-plaintext highlighter-rouge">OP_CAT</code> is that these use-cases may not be on a whole good for Bitcoin users.</p> <p>The creation of harmful centralizing Miner Extractable Value is a key potential problem, <a href="https://bluematt.bitcoin.ninja/2024/04/16/stop-calling-it-mev/">termed “MEV that is evIL” (MEVil)</a> by Matt Corallo. In short, MEVil is any circumstance where large miners/pools can extract additional value by employing sophisticated transaction mining strategies — beyond simply maximizing total fees — that are impractical for smaller miners/pools to adopt. The shear complexity of potential financial instruments that could be created with <code class="language-plaintext highlighter-rouge">OP_CAT</code> makes ruling out MEVil very difficult. Significant MEVil has already appeared on Bitcoin from token auction protocols; fortunately that specific case was defeated via the adoption of full-RBF.</p> <p>In addition to the potential of MEVil, there are many other concrete <code class="language-plaintext highlighter-rouge">OP_CAT</code> use-cases that are potentially harmful. For example, the Drivechains proposal has been <a href="/2023/drivechains">reviewed here</a>, and is widely considered to be harmful to Bitcoin. It is <a href="https://delvingbitcoin.org/t/drivechain-with-and-without-bip-300-301/958">believed to be possible</a> to implement Drivechain’s with <code class="language-plaintext highlighter-rouge">OP_CAT</code>. Another example is token proposals such as Taproot Assets. While it is impossible in general to prevent them from being implemented with <a href="/2017/scalable-single-use-seal-asset-transfer">client side validation</a>, there are proposals to implement them with <code class="language-plaintext highlighter-rouge">OP_CAT</code> in ways that are potentially much more attractive to end users, while also using much more blockspace, which could potentially outbid “legitimate” Bitcoin transactions. These use-cases may also raise legal issues due to how often token protocols are used for financial fraud.</p> <h3 id="incremental-hashing">Incremental Hashing</h3> <p>For covenants, <code class="language-plaintext highlighter-rouge">OP_CAT</code> would be primarily used to concatenate data, and then hash it. Another way to achieve this same goal is with some kind of incremental hashing opcode that takes a <code class="language-plaintext highlighter-rouge">SHA256</code> midstate of some kind, and hashes more data into it; SHA256 itself operates on 64-byte blocks. There are many possible designs for incremental hashing opcodes.</p> <p>One important design decision is whether or not to expose the actual midstate bytes on the stack in some kind of canonical form, or represent them in some new kind of opaque stack item type whose actual byte value can’t be directly manipulated. SHA256 is specified for a particular, fixed, initialization vector and it appears to be unknown whether or not SHA256’s cryptographic properties hold true if arbitrary midstates/initialization vectors are allowed.</p> <p>Of course, since incremental hashing can do pretty much what <code class="language-plaintext highlighter-rouge">OP_CAT</code> can do, just more efficiently, it shares all the concerns about <code class="language-plaintext highlighter-rouge">OP_CAT</code> being too powerful.</p> <h3 id="script-revival">Script Revival</h3> <p><code class="language-plaintext highlighter-rouge">OP_CAT</code> was one of 15 opcodes that Satoshi disabled. In addition to restoring <code class="language-plaintext highlighter-rouge">OP_CAT</code>, Rusty Russell is proposing<sup id="fnref:script-revival-proposal" role="doc-noteref"><a href="#fn:script-revival-proposal" class="footnote">22</a></sup> to essentially restore Bitcoin’s script to “Satoshi’s Original Vision” by re-enabling most of those opcodes, adding DoS limits, and potentially adding a few more in the same soft-fork. In particular, an <code class="language-plaintext highlighter-rouge">OP_CheckSigFromStack</code> is likely.</p> <p>While <code class="language-plaintext highlighter-rouge">OP_CAT</code> alone does make (recursive) covenants possible, a full “script revival” would make more sophisticated covenants possible — and much easier to implement — as parts of the spending transaction could be manipulated directly. For example, you could imagine a covenant script that uses arithmetic opcodes to ensure that the total value of the txouts in the transaction adheres to some desired property.</p> <p>Again, script revival raises all the same concerns, and more, about being overly powerful that <code class="language-plaintext highlighter-rouge">OP_CAT</code> alone does.</p> <h4 id="simplicity"><a href="https://blog.blockstream.com/en-simplicity-github/">Simplicity</a></h4> <p>Similar to Script Revival, Simplicity is relevant to L2’s and covenants by making it possible to do anything. Unlike Script Revival, a Simplicity soft-fork would add an entirely new programming language to Bitcoin’s scripting system based on nine primitive operators known as combinators.</p> <p>In practice, Simplicity is both too simple, and not simple at all. The primitive combinators are so ridiculously low level that basic operations like addition have to be laboriously implemented from scratch; raw Simplicity would be exceptionally verbose in practice. Thus, any real usage of Simplicity would make use of a system of code substitutions, similar to library function calls, known as <a href="https://blog.blockstream.com/simplicity-jets-release/">jets</a>. This poses a practical/political problem: how do you decide on which jets to implement? Most likely jets would be implemented in C++, like any other opcode, requiring a soft-fork for each new jet.</p> <h3 id="op_fancytreemanipulationstuff"><code class="language-plaintext highlighter-rouge">OP_FancyTreeManipulationStuff</code></h3> <p>There’s a large variety of relatively specialized opcodes that have been proposed to do tree manipulation in a space efficient manner for covenant dependent L2 proposals. For example, the Coinpools have proposed both <a href="https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2021-September/019419.html">TAPLEAF_UPDATE_VERIFY</a> and <a href="https://github.com/ariard/bips/blob/ddb77158a8309f307faaaf643830e4d0f07b90d3/bip-merklesub.mediawiki">OP_MERKLESUB</a>, both of which manipulate taproot trees in ways necessary for the Coinpools proposal, and the <a href="https://bitcoinops.org/en/topics/matt/">MATT</a> proposal has proposed a <code class="language-plaintext highlighter-rouge">OP_CheckContractVerify</code> opcode that, basically, verifies statements about merkle trees.</p> <p>For the purposes of this article, we don’t need to go into detail about each one of these many proposals. Rather, we can talk about them as a group: they’re all relatively use-case specific proposals that make one class of L2 possible, ideally without unintended side-effects. They all have the advantage of efficiency: they all use less blockspace than achieving the same goal with more generic opcodes such as <code class="language-plaintext highlighter-rouge">OP_CAT</code> manipulation. But they all have the disadvantage of adding complexity to the script system, for a potentially niche use-case.</p> <p>The same dynamic would happen if Bitcoin adopted the Simplicity scripting system. The equivalent to opcodes in Simplicity is adding a jet for a commonly used pattern. Again, implementing jets for use-case-specific operations like tree manipulation has similar pros and cons as implementing complex opcodes for use-case-specific operations.</p> <h2 id="fund-pools">Fund Pools</h2> <p>All L2 systems that try to have multiple users share a single UTXO can be thought of as some kind of multi-user fund pool, with users being in possession of some kind of right of withdraw. Potentially, there will also be a mechanism to add funds to the pool (beyond creating the pool with funds pre-assigned).</p> <p>For a fund pool to be useful, it must have some kind of “share data state” associated with it: how is the txout value split up? If the fund pool is to evolve over time, that state must also change as funds are added or removed from the pool. Since we’re building on Bitcoin, adding or removing funds from the pool will inevitably involve spending the UTXO the pool controls.</p> <p>Remember that the Bitcoin consensus system itself is based on <em>validation</em> of <em>state changes</em>: transactions prove via their witnesses that changes to the UTXO set state are valid; proof-of-work lets us come to consensus over which set of transactions is correct. This means that fund pools are themselves also going to be based on validation of state changes: we’re proving to every Bitcoin node that the rules for the fund pool are being followed on every state change.</p> <p>But there’s another key aspect to <em>trustless</em> L2 fund pools: when the state of the fund pool changes, the system must inherently publish sufficient data for users participating in the fund pool to recover their funds. If we haven’t done that, then our system fails to provide unilateral withdrawal, without the cooperation of third parties. Many rollup-based schemes fail here: they suffer from <em>data availability</em> failures, where the user is unable to recover their funds if third-party coordinators go offline, because they have no way of getting the data necessary for them to construct a valid fund recovery transaction.</p> <p>With these constraints in mind, what data structures are fund pools going to be based on? Inevitably, they’re all some kind of tree. Specifically, some kind of merkle tree. They have to be a tree, because that’s pretty much the only scalable data structure in computer science; they have to be merkelized, because that’s basically the only reasonable way to cryptographically commit to the state of the tree. Finally, updates to the tree are inevitably going to be published to the Bitcoin blockchain, because that’s the one <a href="/2013/disentangling-crypto-coin-mining">publication medium</a> all L2 users share, and the only one that we can force users to publish on to move coins. And because any covenant implementation is going to need parts of the tree to validate that the rules of the covenant are being followed.</p> <p>So, with the high-level theory out of the way, how does this actually translate into Bitcoin scripts and transactions?</p> <h3 id="individual-pre-signed-transactions">Individual Pre-Signed Transactions</h3> <p>The degenerate case of a tree, with exactly one leaf in it. Here the state of our fund pool can change state, roughly speaking, once. For example, a standard Lightning channel falls into this category, and once opened, can only be closed. The data that is published when a channel is closed is the transaction itself, which is sufficient information for the counterparty in the channel to learn the txid from blockchain data, and recover their funds by spending them.</p> <p>The only “covenant” required here is the most basic covenant: the pre-signed transaction.</p> <h3 id="txout-trees">Txout Trees</h3> <p>The next, more complex, design pattern we see in fund pools is the txout tree. Ark is a notable example. Here the fund pool can be split up by spending the root UTXO in a tree of pre-defined transactions, enforced with simple covenants like pre-signed transactions or CTV, splitting up the value of that UTXO into smaller and smaller amounts until leaf nodes are reached that are spendable by the rightful owners.</p> <p>It’s important to recognize that the purpose of the txout tree is to give users <em>options</em> as to how to recover their funds, and those options come at a cost: a txout tree will always be a more expensive way to split up a pool of funds, returning them to their owners, than simply splitting up the UTXO in a single transaction. Each layer in the tree adds cost because of the bytes used in the txouts and txins necessary to create that layer.</p> <p>So, what kind of options might a txout tree provide? Again, Ark is a great example: we don’t want the on-chain redemption of a single V-UTXO to require every single V-UTXO to be put on chain. By using a tree, redemption can instead split up the tree into smaller parts until the desired V-UTXO is put on chain.</p> <p>Similar to the individual pre-signed transaction case, the information being published is the transactions themselves, which informs other users’ wallet how to spend their funds if necessary.</p> <p>The scalability of txout trees has interesting economies of scale. The cost for the first V-UTXO to be put on chain, in a fund pool with \(n\) V-UTXOs, is roughly \(\log_2(n)\) times more expensive than a single transaction as \(\log_2(n)\) levels of split transactions must be put on chain. However, once the first V-UTXO is put on chain, subsequent V-UTXOs become cheaper to redeem on-chain because someone else has already paid the cost of getting the intermediary transactions mined.</p> <p>Recall that the total number of elements in a binary tree with \(n\) leaves is \(2n\). This means that to put <em>all</em> V-UTXOs on chain, the total cost to do so via a txout tree would be a small multiple of the total cost to do so in a single transaction. Surprisingly efficient!</p> <p>Or maybe not… If the total size of the fund pool redemptions are sufficiently high, they may represent a non-trivial demand on total overall blockspace. Blockspace is a supply and demand system, so at some point fees will go up due to high demand. At the extreme, it’s quite possible to create txout trees so big and so deep that actually redeeming every V-UTXO in the tree is impossible.</p> <p>An open question with txout trees is who pays the fees, and how? One obvious solution is to use keyless anchor outputs on the leaf transactions, and allow whomever wants the leaf transactions to get mined to pay the fees via CPFP. In some use-cases the V-UTXOs themselves can be spent immediately after creation, without a CSV delay, so the V-UTXOs themselves could be spent to add fees via CPFP.</p> <p>RBF is complex to implement due to permission: the obvious place to take fees for RBF from is the V-UTXO value. But how do you ensure that only the owner has the ability to sign for a higher fee transaction? In many circumstances it’s not obvious how to do this in a way that is more efficient than a keyless anchor output. However, failing to do that does pose serious challenges for schemes used by end-user wallets, that may not have a UTXO to spend to perform a CPFP, if the V-UTXOs themselves can’t be spent immediately.</p> <p>Finally, careful thought needs to be put into what incentives there are in txout tree systems, taking fee payment into account. For example, in an Ark like system, if a set of V-UTXOs <em>individually</em> cost too much money to be worth taking to on-chain V-UTXOs, an uncooperative coordinator could refuse to allow those V-UTXOs to be redeemed off-chain, and then make a profit by stealing the value of those V-UTXOs in a single UTXO spend once a a timeout is reached.</p> <p>If this is the case, arguably such a system would fail our criteria to be an L2 for small V-UTXOs.</p> <h3 id="balance-based-schemes">Balance Based Schemes</h3> <p>The state machine of a txout tree is still relatively simple: either the fund pool exists, or it is spent, to create two or more smaller fund pools. With more advanced covenants we could instead treat the fund pool as an evolving balance, with the ability to add and subtract funds from that balance.</p> <p>To do this we need to implement a non-trivial state machine. But we also need what is essentially a shared database. Why? Because the goal here is to share one UTXO across many different owners. Finally, if we’re actually going to get a scalability improvement, we must do so in a way that puts as little as possible of that ownership data on chain.</p> <p>These requirements inherently lead us to some kind of tree-like merkelized data structure, such as a merkle sum tree. Manipulating that data structure is inherently going to require something like <code class="language-plaintext highlighter-rouge">OP_CAT</code>, some kind of zero-knowledge proof verification opcode, or a purpose specific tree manipulation opcode.</p> <p>Interestingly, as in txout trees, you can’t do better than order \(\log(n)\) scaling while maintaining similar security properties. Why? Let’s suppose we had a hypothetical <code class="language-plaintext highlighter-rouge">OP_ZKP</code> which through some advanced mathematics, needed a mere 32 bytes to prove any statement. While this zk-proof could <em>prove</em> that the merkelized data structure had been manipulated according to the rules of the layer 2 system, it would fail to provide the <em>data</em> necessary for the next user to also make a state change. This fails our preferred criteria of enabling unconditional withdrawal: at best one user might be able to achieve an unconditional withdrawal. But no further users could do so.</p> <p>By contrast, if the modified parts of the merklized data structure are published via the covenant scriptsig — e.g. the sibling digests in a merkle tree — the next user has enough data to update their understanding of the system state and themselves make an unconditional withdrawal.</p> <p>A potential way around this problem is if the covenant requires proof of publication on a different publication medium than the Bitcoin chain. However, the security guarantees will be weaker than is possible via Bitcoin.</p> <p>Finally, notice how txout trees and a balance based approach can be combined. If the data structure being manipulated <em>is</em> a txout tree, funds could be added to the txout tree by spending the output and adding new funds, with a covenant script that validates that the funds were in fact added to the txout tree. Equally, funds can be removed by all the mechanisms normally available to a txout tree. Advanced Ark is an example of this class of scheme.</p> <h2 id="failure-data-ratio">Failure Data Ratio</h2> <p>L2’s achieve scaling by adding an interactivity requirement in adversarial situations. In nearly all cases this means that honest parties in the protocol have deadlines by which they need to get transactions mined; if the deadlines are not met, funds can be stolen.</p> <p>The maximum block capacity in all decentralized (and centralized) blockchains is limited by technical constraints. In Bitcoin, the maximum blocksize is such that Bitcoin operates essentially at capacity ~100% of the time. Since Bitcoin mining acts as an auction system, auctioning off blockspace to the highest bidder, in practice this means that the minimum fee-rate to get a transaction mined goes up and down as demand increases and decreases.</p> <p>Fee-rate always factors into L2 economics and failure modes. For example, in Lightning “dust-sized” HTLCs that are too small to be profitably redeemed on-chain use a different security model than larger HTLCs. While the Lightning protocol doesn’t properly implement this yet, in theory this threshold should be dynamic, based on fee-rates as they go up and down, ideally to the point where a party could choose whether or not an HTLC even exists in a given commitment transaction based on fee-rate.</p> <p>A variety of attacks have been proposed where this situation is intentionally triggered on Lightning, such as flood and loot<sup id="fnref:flood-and-loot" role="doc-noteref"><a href="#fn:flood-and-loot" class="footnote">23</a></sup> and the mass exit attack<sup id="fnref:mass-exit-attack" role="doc-noteref"><a href="#fn:mass-exit-attack" class="footnote">24</a></sup>. Since Bitcoin blockchain capacity is shared across all use-cases, attacks between different L2 systems are also possible: eg triggering a mass exit on Ark to profit from Lightning channels.</p> <p>L2’s that share UTXO’s amongst multiple users inherently make these problems potentially worse, as the worst case blockspace demand during a failure is proportionally higher. As of writing, we’ve never actually seen large scale failures on Lightning where large numbers of channels had to be closed at once. There is a good argument that we should get additional operational experience with Lightning and its approximately 1-UTXO-per-user scaling, before pushing the limits even further with UTXO sharing schemes.</p> <p>Secondly, before new UTXO sharing schemes are widely adopted, careful research should be done on the potential profitability of attacks during high demand for blockspace. For example, in a system like Ark where the ASP can redeem funds using much less blockspace than other parties, it may be the case that intentionally triggering high fee-rates and then seizing funds that can’t be profitably unilaterally withdrawn is a profitable fraud, violating both our conditions for a true L2 system.</p> <h2 id="consensus-cleanup"><a href="https://bitcoinops.org/en/topics/consensus-cleanup-soft-fork/">Consensus Cleanup</a></h2> <p>There’s a number of things that Satoshi got wrong in the initial Bitcoin protocol, in particular, scripting DoS attacks, the timewarp attack, and issues with the merkle tree. Previously, a number of other consensus bugs have already been fixed with soft-forks, such as the switch to evaluating time-based nLockTime’s against the median time past, (attempting to) fix the duplicate txid issue, etc.</p> <p>The most recent soft-fork, taproot, had a relatively contentious deployment process, taking quite a long time to actually get deployed. An argument for doing a consensus cleanup soft-fork first, prior to enabling any new opcodes or other features for new types of L2’s, is that we’d learn more about how willing the wider community is to implement what should be a relatively uncontroversial soft-fork that arguably benefits everyone.</p> <h2 id="testing-soft-fork-dependent-l2s">Testing Soft-Fork Dependent L2’s</h2> <p>Developers do not need to wait for a soft-fork to actually happen to test out their ideas. One particularly sophisticated approach being used by the Ark developers in <a href="https://arkdev.info/docs/learn/clark/">covenant-less Ark</a> is to simulate the covenants they need with pre-signed transactions. This allows them to test out the ideas of Ark with real BTC, on mainnet, with the same trust characteristics, as Ark is expected to achieve with covenants. The trade-off is that covenant-less Ark requires all parties to be online to sign the pre-signed transactions. Since clArk does work with real BTC, it may prove to even be useful enough to use in production for certain use-cases transfer that can tolerate the interactivity trade-off.</p> <p>A simpler approach is to simply pretend that certain parties can’t do the actions that covenants would prevent. For example, if a proposed protocol wants to use CTV to enforce that a txout tree is spent in a transaction tree, each use of CTV could be replaced with a <code class="language-plaintext highlighter-rouge">NOP</code> or <code class="language-plaintext highlighter-rouge">CheckSig</code>. While in reality the txout tree isn’t actually being enforced, every bit of code interacting with the tree and each party can be tested as though it is, and since <code class="language-plaintext highlighter-rouge">NOP</code> and <code class="language-plaintext highlighter-rouge">CheckSig</code> are allowed in standard scripts, the protocol can be tested on mainnet with real funds.</p> <h2 id="potential-soft-forks">Potential Soft-Forks</h2> <p>What’s the path forward? Here we’re going to chart out all the main L2 schems we’ve analyzed, and what soft-forks are useful (U) or required (R) to make these L2 schemes successful. As discussed above, <code class="language-plaintext highlighter-rouge">OP_CAT</code> (and by extension, Script Revival, which includes <code class="language-plaintext highlighter-rouge">OP_CAT</code>), can emulate all of the other soft-forks in this list — with the exception of <code class="language-plaintext highlighter-rouge">OP_Expire</code> and Fee Sponsorship — so where a project’s needs are most efficiently met by some other soft-fork directly we won’t include <code class="language-plaintext highlighter-rouge">OP_CAT</code>.</p> <p>We’re also going to leave off all the proposed merkle tree manipulation opcodes. They’re all too niche, too use-case-specific, to have a significant chance of getting adopted at this time. To the extent that these opcodes are useful, implementing their effects via <code class="language-plaintext highlighter-rouge">OP_CAT</code> and/or Script Revival is a much more likely path to adoption.</p> <table> <thead> <tr> <th style="text-align: left"> </th> <th style="text-align: center"><code class="language-plaintext highlighter-rouge">OP_Expire</code></th> <th style="text-align: center"><code class="language-plaintext highlighter-rouge">SIGHASH_ANYPREVOUT</code></th> <th style="text-align: center">CTV</th> <th style="text-align: center"><code class="language-plaintext highlighter-rouge">OP_CAT</code></th> <th style="text-align: center">Script Revival</th> </tr> </thead> <tbody> <tr> <td style="text-align: left">Lightning</td> <td style="text-align: center">U</td> <td style="text-align: center">U</td> <td style="text-align: center">U</td> <td style="text-align: center"> </td> <td style="text-align: center"> </td> </tr> <tr> <td style="text-align: left">Channel Factories</td> <td style="text-align: center">U</td> <td style="text-align: center"> </td> <td style="text-align: center">U</td> <td style="text-align: center"> </td> <td style="text-align: center"> </td> </tr> <tr> <td style="text-align: left">LN-Symmetry</td> <td style="text-align: center">U</td> <td style="text-align: center">R</td> <td style="text-align: center"> </td> <td style="text-align: center"> </td> <td style="text-align: center"> </td> </tr> <tr> <td style="text-align: left">Ark</td> <td style="text-align: center">U</td> <td style="text-align: center"> </td> <td style="text-align: center">R</td> <td style="text-align: center"> </td> <td style="text-align: center"> </td> </tr> <tr> <td style="text-align: left">Advanced Ark</td> <td style="text-align: center">U</td> <td style="text-align: center"> </td> <td style="text-align: center">U</td> <td style="text-align: center"> </td> <td style="text-align: center">R</td> </tr> <tr> <td style="text-align: left">Validity Rollups</td> <td style="text-align: center"> </td> <td style="text-align: center"> </td> <td style="text-align: center"> </td> <td style="text-align: center">R</td> <td style="text-align: center">U</td> </tr> </tbody> </table> <p>CTV is the clear winner here, followed by <code class="language-plaintext highlighter-rouge">SIGHASH_ANYPREVOUT</code> (<code class="language-plaintext highlighter-rouge">OP_Expire</code> is useful to many things by being a replacement cycling fix, but not essential). CTV wins because so many things fit into the design pattern of “make sure the spending transaction matches this template”; even <code class="language-plaintext highlighter-rouge">OP_CAT</code> constructions can efficiently make use of CTV.</p> <p>Unlike <code class="language-plaintext highlighter-rouge">OP_CAT</code>, CTV doesn’t appear to raise much risk of unintended consequences beyond encouraging out-of-band fee payments in certain cases. This isn’t ideal. But no-one has come up with a widely supported alternative.</p> <p>My personal recommendation: do a consensus cleanup soft-fork, followed by CTV.</p> <h2 id="footnotes">Footnotes</h2> <div class="footnotes" role="doc-endnotes"> <ol> <li id="fn:dust-htlc-theft" role="doc-endnote"> <p>At least, it should be! It is likely that Lightning implementations exist that don’t properly limit the total value of dust HTLCs in flight. <a href="#fnref:dust-htlc-theft" class="reversefootnote" role="doc-backlink">&#8617;</a></p> </li> <li id="fn:fidelity-bonded-banking" role="doc-endnote"> <p>Over a decade ago I proposed a class of L2 systems — <a href="https://bitcointalk.org/index.php?topic=146307.0">fidelity bonded banks</a> — that met the requirement of third-parties being unable to profitably steal. But not the preferred requirement of unilateral withdrawal. I’ll be the first to say that Lighting is a <em>much</em> better idea than fidelity bonded banks! <a href="#fnref:fidelity-bonded-banking" class="reversefootnote" role="doc-backlink">&#8617;</a></p> </li> <li id="fn:one-utxo-per-user" role="doc-endnote"> <p>You might ask why does Lightning requires at least one UTXO per end user, when a channel has two users? The reason is Lightning is the Lightning <em>Network</em>: with just one UTXO per two users, the best you can do is a bunch of isolated <em>pairs</em> of users, with no wider network. One UTXO per node is just enough to form a chain of nodes, users, which is technically fully connected. Of course, in practice you actually need <em>more</em> than one-UTXO-per-user, as a single chain isn’t useful beyond a handful of nodes as it’s not technically feasible to route payments though hundreds of hops. <a href="#fnref:one-utxo-per-user" class="reversefootnote" role="doc-backlink">&#8617;</a></p> </li> <li id="fn:bosworth-ln-analysis" role="doc-endnote"> <p>Alex Bosworth independently <a href="https://x.com/alexbosworth/status/1481104624085917699">tweeted</a> an analysis coming up with essentially the same numbers as me in 2022! I either didn’t see — or had forgotten about — his analysis when I wrote mine. So it’s good to see us coming up with the same numbers. <a href="#fnref:bosworth-ln-analysis" class="reversefootnote" role="doc-backlink">&#8617;</a></p> </li> <li id="fn:splice-netting" role="doc-endnote"> <p>The fact that splice-ins and splice-outs can be combined in the same transaction also reduces the number of additional inputs necessary, as splice-outs can supply the funds for splice-ins. Also note how to the external observer, such transactions are indistinguishable from coinjoins. <a href="#fnref:splice-netting" class="reversefootnote" role="doc-backlink">&#8617;</a></p> </li> <li id="fn:vutxo-single-tx" role="doc-endnote"> <p>For the purpose of RBF, a V-UTXO scheme might actually have a variety of pre-signed transactions. But the purpose of those multiple transactions would be to perform a single economic transaction. Not — as in Lightning — to allow multiple economic transactions to happen. Of course, this is a somewhat fuzzy definition; maybe someone will come up with a scheme that combines the V-UTXO and channel balance ideas! <a href="#fnref:vutxo-single-tx" class="reversefootnote" role="doc-backlink">&#8617;</a></p> </li> <li id="fn:ark-atomicity" role="doc-endnote"> <p>That is, an Ark transaction either does or does not happen; it could take hours or even days to setup. But either all intended funds are moved or none are. <a href="#fnref:ark-atomicity" class="reversefootnote" role="doc-backlink">&#8617;</a></p> </li> <li id="fn:fixed-rate" role="doc-endnote"> <p>Notice how we are <em>not</em> calculating this as a compound interest rate. This is appropriate because the principal amount does not change, similar to how bond payments work. <a href="#fnref:fixed-rate" class="reversefootnote" role="doc-backlink">&#8617;</a></p> </li> <li id="fn:last-moment-ark-spend" role="doc-endnote"> <p>Remember that if the ASP refuses to allow the V-UTXO to be spent into a new round, the only alternative the user has is to unilaterally withdraw on-chain. Not only is this expensive, it takes time: the user’s transactions might not confirm before the ASP is able to spend the pool txout. If the round is big enough, they may even end up competing with other users in that same round for blockspace. <a href="#fnref:last-moment-ark-spend" class="reversefootnote" role="doc-backlink">&#8617;</a></p> </li> <li id="fn:asp-pop" role="doc-endnote"> <p>An example of a proof-of-publication problem, which we will discuss later. <a href="#fnref:asp-pop" class="reversefootnote" role="doc-backlink">&#8617;</a></p> </li> <li id="fn:hierarchical-channels" role="doc-endnote"> <p><a href="https://lists.linuxfoundation.org/pipermail/lightning-dev/2023-March/003886.html">[Lightning-dev] Resizing Lightning Channels Off-Chain With Hierarchical Channels</a>, jlspc, Mar 18th 2023. Also <a href="https://github.com/JohnLaw2/ln-hierarchical-channels">on github</a>. <a href="#fnref:hierarchical-channels" class="reversefootnote" role="doc-backlink">&#8617;</a></p> </li> <li id="fn:rbf-vs-out-of-band" role="doc-endnote"> <p>In certain rare cases where the inputs and outputs of a transaction are fixed due to some constraint, RBF can be less efficient than an out-of-band fee payment, sponsor payment, etc, allowing the transaction to be even smaller. <a href="#fnref:rbf-vs-out-of-band" class="reversefootnote" role="doc-backlink">&#8617;</a></p> </li> <li id="fn:number-of-fee-variants" role="doc-endnote"> <p>\(1.05^{75} = 1272\), so 75 fee variants differing by 5% each would cover more than the <a href="https://mempool.space/graphs/mempool#all">entire variation of next-block fee-rates</a> Bitcoin mainnet has had in its entire lifetime. <a href="#fnref:number-of-fee-variants" class="reversefootnote" role="doc-backlink">&#8617;</a></p> </li> <li id="fn:safe-sighash-anyonecanpay" role="doc-endnote"> <p><code class="language-plaintext highlighter-rouge">SIGHASH_ANYONECANPAY</code> can be made safe with respect to transaction pinning by only using it for some signatures, thus preventing attacking parties from being able to add inputs. Lightning does this with <a href="https://github.com/lightning/bolts/blob/fd83d7cee0369eb1d9068eb9864bff8b1f940938/05-onchain.md#generation-of-htlc-transactions">HTLCs transactions, by having only one party sign with <code class="language-plaintext highlighter-rouge">SIGHASH_ANYONECANPAY</code></a>. <a href="#fnref:safe-sighash-anyonecanpay" class="reversefootnote" role="doc-backlink">&#8617;</a></p> </li> <li id="fn:replacement-cycling" role="doc-endnote"> <p>While the canonical source is Antoine Riard’s <a href="https://github.com/ariard/mempool-research/blob/2023-10-replacement-paper/replacement-cycling.pdf">paper</a>, I strongly recommend reading <a href="https://twitter.com/mononautical">mononautical</a>’s <a href="https://twitter.com/mononautical/status/1715736832950825224">replacement cycling tweet thread</a> for an easier to understand explanation. <a href="#fnref:replacement-cycling" class="reversefootnote" role="doc-backlink">&#8617;</a></p> </li> <li id="fn:altruistic-rebroadcasting" role="doc-endnote"> <p><a href="https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2023-December/022188.html">[bitcoin-dev] Altruistic Rebroadcasting - A Partial Replacement Cycling Mitigation</a>, Peter Todd, Dec 9th 2023 <a href="#fnref:altruistic-rebroadcasting" class="reversefootnote" role="doc-backlink">&#8617;</a> <a href="#fnref:altruistic-rebroadcasting:1" class="reversefootnote" role="doc-backlink">&#8617;<sup>2</sup></a></p> </li> <li id="fn:op-expire" role="doc-endnote"> <p><a href="https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2023-November/022108.html">[bitcoin-dev] OP_Expire and Coinbase-Like Behavior: Making HTLCs Safer by Letting Transactions Expire Safely</a>, Peter Todd, Nov 2nd 2023 <a href="#fnref:op-expire" class="reversefootnote" role="doc-backlink">&#8617;</a></p> </li> <li id="fn:coinbase-timelock" role="doc-endnote"> <p>Coinbase transactions are inherently tied to the blocks they exist in. Satoshi made these outputs unspendable until the block they are contained in <a href="https://github.com/bitcoin/bitcoin/blob/v27.1/src/validation.cpp#L377">has reached 100 confirmations</a>. Satoshi also wrote about this exact problem <a href="https://bitcointalk.org/index.php?topic=1786.msg22119#msg22119">on bitcointalk</a>, explaining why an <code class="language-plaintext highlighter-rouge">OP_BLOCKNUMBER</code> opcode would be dangerous. <a href="#fnref:coinbase-timelock" class="reversefootnote" role="doc-backlink">&#8617;</a></p> </li> <li id="fn:recursive-hash-function" role="doc-endnote"> <p>If you do find a message containing it’s own SHA256 hash, I strongly recommend selling your Bitcoin for guns, food, and ammo, and finding a nice cave to camp out in. <a href="#fnref:recursive-hash-function" class="reversefootnote" role="doc-backlink">&#8617;</a></p> </li> <li id="fn:checksig-hashing" role="doc-endnote"> <p>Technically we would actually build up the serialization that <code class="language-plaintext highlighter-rouge">CheckSig</code> uses for our chosen <code class="language-plaintext highlighter-rouge">SIGHASH</code> mode, which is different from the way transactions are serialized to generate the txid. <a href="#fnref:checksig-hashing" class="reversefootnote" role="doc-backlink">&#8617;</a></p> </li> <li id="fn:ctv-match" role="doc-endnote"> <p>If CTV is available, you could also just assemble the CTV template, hash it, and check it with CTV. This is useful if the covenant-specific logic is more complex than what CTV alone can do. <a href="#fnref:ctv-match" class="reversefootnote" role="doc-backlink">&#8617;</a></p> </li> <li id="fn:script-revival-proposal" role="doc-endnote"> <p>Rusty first publicly proposed the script revival via <a href="https://btcplusplus.dev/conf/atx24/talks#restoration">a talk</a> at the <a href="https://btcplusplus.dev/conf/atx24">bitcoin++ Austin 2024</a> conference. As of writing, he is also working on a <a href="https://github.com/bitcoin/bips/blob/c2f268e83031b9b67e798c5c72a1171bfc463d1f/bip-unknown-var-budget-script.mediawiki">draft BIP</a> and implementation. <a href="#fnref:script-revival-proposal" class="reversefootnote" role="doc-backlink">&#8617;</a></p> </li> <li id="fn:flood-and-loot" role="doc-endnote"> <p><a href="https://arxiv.org/abs/2006.08513">“Flood &amp; Loot: A Systemic Attack On The Lightning Network”</a>, Jona Harris and Aviv Zohar, Jun 15th 2020 <a href="#fnref:flood-and-loot" class="reversefootnote" role="doc-backlink">&#8617;</a></p> </li> <li id="fn:mass-exit-attack" role="doc-endnote"> <p><a href="https://arxiv.org/abs/2208.01908">“Mass Exit Attacks on the Lightning Network”</a>, Cosimo Sguanci and Anastasios Sidiropoulos, Feb 7th 2024 <a href="#fnref:mass-exit-attack" class="reversefootnote" role="doc-backlink">&#8617;</a></p> </li> </ol> </div> Mon, 02 Sep 2024 00:00:00 +0000 https://petertodd.org/2024/covenant-dependent-layer-2-review https://petertodd.org/2024/covenant-dependent-layer-2-review bitcoin layer2 convanants Over Half of Replace-by-Fee-Rate Replacements Are Mined <p>I recently released a <a href="https://github.com/petertodd/bitcoin/tree/libre-relay-v26.0">prototype Libre Relay fork</a> of Bitcoin Core v26.0, that among other things, implements <a href="/2024/one-shot-replace-by-fee-rate#pure-replace-by-fee-rate">Pure Replace-By-Fee-Rate</a> (RBFR) with a 2x ratio. This means that transactions will be replaced if the fee-rate of the new transaction is at least 2x higher than the old transaction(s), even if the absolute fee is lower.</p> <p>RBFR policies are highly desirable for Lightning and similar smart contract systems as they have the potential to help solve pinning attacks, by ensuring that it’s always possible to make forward progress in a protocol by bidding a fee rate sufficiently high to get mined in a short period of time. The only question is whether or not some form of RBFR is feasible to implement.</p> <p>Even though RBFR allows the total fee of a mempool to be reduced, one reason why it is incentive compatible for miners is because it is likely that a RBFR transaction will be mined by another miner anyway: mempools do <em>not</em> have strict consensus, and miners mine transactions in what is essentially fee-rate order. Thus it is likely that even without RBFR a higher fee-rate transaction will be picked up by another miner, invalidating the lower fee-rate transactions it conflicted with.</p> <p>Here I’ll present data showing this is in fact the case. At the moment, I have no reason to believe that any miners have implemented RBFR. Yet, in the past month, of the RBFR replacements seen by one of my well-connected Libre Relay nodes, meeting the current 2x fee-rate requirement, at least 64% of those replacements were mined by a variety of pools. This success rate suggests two things:</p> <ol> <li>By <em>not</em> implementing RBFR, miners are leaving money on the table by failing to mine profitable transactions now, before other miners collect those fees.</li> <li>Relaying RBFR replacements is a good use of relay bandwdith, because the majority of transactions are getting mined.</li> </ol> <p>In conclusion, more nodes and miners should experiment with running RBFR, eg by running Libre Relay.</p> <h2 id="limitations">Limitations</h2> <p>This is a fairly limited data set: just 14 RBFR replacements in total over a 1 month period. Based on inspection of the transactions, they most likely originate from a variety of different wallets in circumstances where one or more transactions were replaced by a double-spend because the original transaction(s) were of fee-rates too low to be quickly mined.</p> <p>I only tried to analyze RBFR replacements in cases where the absolute fee decreased. There are cases where the absolute fee can increase. Yet the replacement is still RBFR as the fee was not increased <em>sufficiently</em> to be a normal BIP125 RBF replacement. Due to how I was collecting logs, actually finding those replacements isn’t easy, so I didn’t bother. Thus my count of 14 RBFR replacements is probably an underestimate.</p> <h2 id="data">Data</h2> <p>The following is my actual notes that I used while analyzing the log file data from my node:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Log start: Jan 23rd 2024 Log end: Feb 23rd 2024 grep replacing ~/.bitcoin/debug.log |cut -d ' ' -f 11 | sort -n | head -n 50 2024-02-14T08:34:48Z [mempool] replacing tx 238459ee4e10b6ba6b8d4008c77d9bd2333ee1c81105f7be0e45497a6649c073 (wtxid=c328f7cca2aa3b3468d7cbf866138ff2a687125f91bee2cd1b653865f18dd5e3) with b8b7252047f5725531a9f1020f011e9d9b24d50ce2362fb5ef80a622b6f5280b (wtxid=1f987a7b85f958751803a276e631c16aa2704ecdf2cd70d32a8640483ba384b7) for -0.00022019 additional fees, -168 delta bytes 2024-02-14T08:34:48Z [mempool] replacing tx 71b0c8ca444b60bfb16a19bad8b399c2b5e9722865e00e713d47c65cf77728a3 (wtxid=d9f8dec57ff3905694691ea871897fa7e2011a6a7a95132a63fb4166942895b9) with b8b7252047f5725531a9f1020f011e9d9b24d50ce2362fb5ef80a622b6f5280b (wtxid=1f987a7b85f958751803a276e631c16aa2704ecdf2cd70d32a8640483ba384b7) for -0.00022019 additional fees, -168 delta bytes outcome: unknown, as none of the transactions above were mined 2024-01-24T04:08:22Z [mempool] replacing tx c827e801a46db784892718bde7115fefda59dad3db095c75df820fc42ccf3916 (wtxid=c827e801a46db784892718bde7115fefda59dad3db095c75df820fc42ccf3916) with e053b6efef61bc76463fe1e916043b0aa84d2f8383c5b4efac7e70c279df4c2e (wtxid=e053b6efef61bc76463fe1e916043b0aa84d2f8383c5b4efac7e70c279df4c2e) for -0.00015576 additional fees, -1184 delta bytes 2024-01-24T04:08:22Z [mempool] replacing tx c5bb43f2411b4617677a73663f148a73478ab6c9d01362110784724542c4842d (wtxid=c5bb43f2411b4617677a73663f148a73478ab6c9d01362110784724542c4842d) with e053b6efef61bc76463fe1e916043b0aa84d2f8383c5b4efac7e70c279df4c2e (wtxid=e053b6efef61bc76463fe1e916043b0aa84d2f8383c5b4efac7e70c279df4c2e) for -0.00015576 additional fees, -1184 delta bytes 2024-01-24T04:08:22Z [mempool] replacing tx edbf7a134ec379938fc27dc3a4df0e4d145676dea818459af2653383ab49d574 (wtxid=edbf7a134ec379938fc27dc3a4df0e4d145676dea818459af2653383ab49d574) with e053b6efef61bc76463fe1e916043b0aa84d2f8383c5b4efac7e70c279df4c2e (wtxid=e053b6efef61bc76463fe1e916043b0aa84d2f8383c5b4efac7e70c279df4c2e) for -0.00015576 additional fees, -1184 delta bytes 2024-01-24T04:08:22Z [mempool] replacing tx 31b74b7375c966a9a27ee5ed9146e2913a2e55ac7ccee5c8bcc74be4048a97b6 (wtxid=31b74b7375c966a9a27ee5ed9146e2913a2e55ac7ccee5c8bcc74be4048a97b6) with e053b6efef61bc76463fe1e916043b0aa84d2f8383c5b4efac7e70c279df4c2e (wtxid=e053b6efef61bc76463fe1e916043b0aa84d2f8383c5b4efac7e70c279df4c2e) for -0.00015576 additional fees, -1184 delta bytes 2024-01-24T04:08:22Z [mempool] replacing tx e012768b6069c2e61a53cb31de293bcbefcb715c818e9b6b50e2034329ddbcee (wtxid=e012768b6069c2e61a53cb31de293bcbefcb715c818e9b6b50e2034329ddbcee) with e053b6efef61bc76463fe1e916043b0aa84d2f8383c5b4efac7e70c279df4c2e (wtxid=e053b6efef61bc76463fe1e916043b0aa84d2f8383c5b4efac7e70c279df4c2e) for -0.00015576 additional fees, -1184 delta bytes outcome: e053b6efef61bc76463fe1e916043b0aa84d2f8383c5b4efac7e70c279df4c2e won, mined by f2pool; unclear how old replaced txs were 2024-02-10T01:48:15Z [mempool] replacing tx 6cff130587e5424ff11157ae4e84aa3a8b1663b591d77b0b3029258b65164274 (wtxid=028d3f85bac8aba30a2ab5c598f9dd511e5f3d6a8e8b03b01021b9b70ef60f1a) with 34debb7e99e0539d3671105aae44a6b06ae0b0b56907deb3232caa45ec75efc1 (wtxid=c85cf5b3cb64328dc455d8b2e62ba61ff48a34b7e3059128ef04b95b64b58683) for -0.00009301 additional fees, -481 delta bytes 2024-02-10T01:48:15Z [mempool] replacing tx 8a6c86e7e12af5905abafadbff8c9edd741e34f87559e53472c104504ab16e81 (wtxid=76e95ac81ad1ba5151687d4bb4309721746271284a4c563c79a201b2c90f0019) with 34debb7e99e0539d3671105aae44a6b06ae0b0b56907deb3232caa45ec75efc1 (wtxid=c85cf5b3cb64328dc455d8b2e62ba61ff48a34b7e3059128ef04b95b64b58683) for -0.00009301 additional fees, -481 delta bytes 2024-02-10T01:48:15Z [mempool] replacing tx a7258a7a5cef585f75bb9d67eb6f8a2bd832bb42e7a4cf962c37ea8c1a3ca3dd (wtxid=b3ab131da10e8de47459c4920aff4bc6cc5beb34249c41cdeb96b785d9632fac) with 34debb7e99e0539d3671105aae44a6b06ae0b0b56907deb3232caa45ec75efc1 (wtxid=c85cf5b3cb64328dc455d8b2e62ba61ff48a34b7e3059128ef04b95b64b58683) for -0.00009301 additional fees, -481 delta bytes 2024-02-10T01:48:15Z [mempool] replacing tx 624e6a56f8bd9acaf594a180d77fa2dad21ec0164f6496b1875af600e3d64cf2 (wtxid=26afba898925788e23781d509dd3918fca8b2cdeaf6ff06a65640cb639b5a1bd) with 34debb7e99e0539d3671105aae44a6b06ae0b0b56907deb3232caa45ec75efc1 (wtxid=c85cf5b3cb64328dc455d8b2e62ba61ff48a34b7e3059128ef04b95b64b58683) for -0.00009301 additional fees, -481 delta bytes outcome: lost 2024-01-24T02:12:47Z [mempool] replacing tx 639ab332c1c257b04cffd3410199cb0af547e8ea9f7eeb29f9d0b4b24801680c (wtxid=639ab332c1c257b04cffd3410199cb0af547e8ea9f7eeb29f9d0b4b24801680c) with 281405690ccf1e6b3e18b37856fa60d5a66d7aae47577776ed8dcef73ce5d6c7 (wtxid=281405690ccf1e6b3e18b37856fa60d5a66d7aae47577776ed8dcef73ce5d6c7) for -0.00009195 additional fees, -976 delta bytes outcome: 281405690ccf1e6b3e18b37856fa60d5a66d7aae47577776ed8dcef73ce5d6c7 won, mined by f2pool; replaced tx ~4 hours old 2024-01-23T22:57:15Z [mempool] replacing tx 54a33daa3eb300f2ea7261d6f4fdd026424aad3a9e65383b97576d70c59ff625 (wtxid=54a33daa3eb300f2ea7261d6f4fdd026424aad3a9e65383b97576d70c59ff625) with 867f9bf7e1aaec55f2a6552cb6e31ccce7c0aa75f9a08ae84c23960fc5951247 (wtxid=867f9bf7e1aaec55f2a6552cb6e31ccce7c0aa75f9a08ae84c23960fc5951247) for -0.00008978 additional fees, -326 delta bytes 2024-01-23T22:57:15Z [mempool] replacing tx 2cee5a3753ea4906677a749300ff95d00d4dfd9c1c49fb8ea42b6919e5b8075b (wtxid=e73f5cfaf6a6c5ec6fa68edcf2c741a2c9306bf85e1f2ed6d7424757aa0ceeff) with 867f9bf7e1aaec55f2a6552cb6e31ccce7c0aa75f9a08ae84c23960fc5951247 (wtxid=867f9bf7e1aaec55f2a6552cb6e31ccce7c0aa75f9a08ae84c23960fc5951247) for -0.00008978 additional fees, -326 delta bytes outcome: lost 2024-02-08T02:53:17Z [mempool] replacing tx fdf726e40c61c9e78a4cbefcc38a9683b4a270020109ccc6584275d05dcffe88 (wtxid=793d89e1d27b1b001d485c277f2228a96674c6d15d21b012e84cffd89bb2f919) with 14b25c18e9ed920fac5e824ac92dc459f61abf89ea5a2c887b48bac4db4d5642 (wtxid=f8aac96aebdd5f4ed1094fae09bfe5be062e3e14f3907a94cc2573067137d764) for -0.00005916 additional fees, -180 delta bytes 2024-02-08T02:53:17Z [mempool] replacing tx 700179e09161b178f4346c296d28d1273a5b487a10e1dad6c90a763736fc40b6 (wtxid=b39281d543eacd32187b5b9b226dddfccdf33c6d979bfd8d58b73d5168d60968) with 14b25c18e9ed920fac5e824ac92dc459f61abf89ea5a2c887b48bac4db4d5642 (wtxid=f8aac96aebdd5f4ed1094fae09bfe5be062e3e14f3907a94cc2573067137d764) for -0.00005916 additional fees, -180 delta bytes outcome: unclear, as fdf72 never got mined and don't have logs as to what it actually was 2024-02-14T08:33:03Z [mempool] replacing tx e16b43bfc2fb510ed2d7e5e4e89f94790f5f44ef6c643efe5eab1b12a30f016f (wtxid=7536fbdcfcfe3381be4f6bffed2ef68228615c1b29080029389cf6b29e0a4bd1) with 71b0c8ca444b60bfb16a19bad8b399c2b5e9722865e00e713d47c65cf77728a3 (wtxid=d9f8dec57ff3905694691ea871897fa7e2011a6a7a95132a63fb4166942895b9) for -0.0000588 additional fees, -168 delta bytes 2024-02-14T08:33:03Z [mempool] replacing tx b309997ea34321a16649bdb0998b1e6252aa48ed5f293ae1c251db6cd32dd9a5 (wtxid=b18d3e91956ddb7e78590aad4e3bdb25f5ec44e912ff96bacd5426c71f2b3f3d) with 71b0c8ca444b60bfb16a19bad8b399c2b5e9722865e00e713d47c65cf77728a3 (wtxid=d9f8dec57ff3905694691ea871897fa7e2011a6a7a95132a63fb4166942895b9) for -0.0000588 additional fees, -168 delta bytes outcome: lost 2024-01-24T12:51:40Z [mempool] replacing tx 622d04cfa4b0c2da7ff52d787369139f14dfb7374ce8361636eeaf1ede0d1795 (wtxid=8107c0f45175d1cc07bf0fbf12ccd05bce2bd01adf9a75ff6fb20023fdb2b565) with 5c611198a41cb9f8ec9a44c3d66752312524dc265ee9ccbacf338dd14b202f8c (wtxid=b0567ae9a84f4467a6fe70f84de4dc89b9aec1aca156419b1463149055e7b27b) for -0.00005218 additional fees, -402 delta bytes 2024-01-24T12:51:40Z [mempool] replacing tx ded2f2189c2d6292104457d4d8006bb0e6f06b5be7c63fa3893bcd83059313a3 (wtxid=f43098191c4674c480ef2a278015561101043b815be484feb776b9e2a1cac9ed) with 5c611198a41cb9f8ec9a44c3d66752312524dc265ee9ccbacf338dd14b202f8c (wtxid=b0567ae9a84f4467a6fe70f84de4dc89b9aec1aca156419b1463149055e7b27b) for -0.00005218 additional fees, -402 delta bytes 2024-01-24T12:51:40Z [mempool] replacing tx ee09c7533f59ee69dc8bea7f1b63ea9b10ede7de3c2fb2ee0870b6160cac74ab (wtxid=30575e5c7d64222687febebd47124bbc25ec06ae90ebaf679ed120684fe73075) with 5c611198a41cb9f8ec9a44c3d66752312524dc265ee9ccbacf338dd14b202f8c (wtxid=b0567ae9a84f4467a6fe70f84de4dc89b9aec1aca156419b1463149055e7b27b) for -0.00005218 additional fees, -402 delta bytes 2024-01-24T12:51:40Z [mempool] replacing tx 04c4dd8ac5c9356e34aed870e9b221da2e358c904e6c8abecb1edc63b6808fdd (wtxid=e4f39d7cd0614b7e85b33e213989aed3376d4b78787081c2e6a3c32fb20bb5b8) with 5c611198a41cb9f8ec9a44c3d66752312524dc265ee9ccbacf338dd14b202f8c (wtxid=b0567ae9a84f4467a6fe70f84de4dc89b9aec1aca156419b1463149055e7b27b) for -0.00005218 additional fees, -402 delta bytes outcome: 5c611198a41cb9f8ec9a44c3d66752312524dc265ee9ccbacf338dd14b202f8c won, mined by mara pool; unclear how old replaced txs were 2024-02-09T22:09:44Z [mempool] replacing tx ec5e68cc99d1184a5e01c92a01cee43104e09934eacb9489bd71039240b2409f (wtxid=0c179ced549a2ce013ecf75e210d6de43c5331d6c06c1593a2d7619216e2f6ae) with 1d25f2be63cad67c68528bfdcdf248fda1909dd7bef71f27a5fe9056ff9368b7 (wtxid=2d6e55531676b7b3b0dba67a9367f3f25536463c3e96c59b1c0b67945c4d90bc) for -0.00003893 additional fees, -1133 delta bytes outcome: 1d25f2be63cad67c68528bfdcdf248fda1909dd7bef71f27a5fe9056ff9368b7 won, mined by f2pool; replaced tx was ~35 hours old 2024-02-15T15:00:13Z [mempool] replacing tx 4d4deb6e9170486724cdb0df8a1e4a1869d8b09c3e734a4781488a37417df8be (wtxid=4b65734a764b80cd80dccd26180ec7cba7463e66f347969c3b9ff450be8adfd7) with bbb06e7bd26e3010c9c0c8907850ac27aa7d842f8a888d757e41e1cf7c4f8cc0 (wtxid=88410651f659d234115180c959af0c958fb19e427cddd2b57c670c40fa37b59a) for -0.00003468 additional fees, -1487 delta bytes 2024-02-15T15:00:13Z [mempool] replacing tx 21696be674c6b02d013baf58f7f8f2bde8db6de17a8bc413714b69e3f2f9a0c8 (wtxid=b5d3e6f97bd695450fcb00731e69b2c4cf671508e17f5068cc4ee28e8d3edb42) with bbb06e7bd26e3010c9c0c8907850ac27aa7d842f8a888d757e41e1cf7c4f8cc0 (wtxid=88410651f659d234115180c959af0c958fb19e427cddd2b57c670c40fa37b59a) for -0.00003468 additional fees, -1487 delta bytes outcome: bbb06e7bd26e3010c9c0c8907850ac27aa7d842f8a888d757e41e1cf7c4f8cc0 won, mined by f2pool; replaced txs were multiple days old 2024-02-04T16:11:10Z [mempool] replacing tx bfe8dbd86485710e0d562b8b4df58583aeb96f26beb180668f113127acffb3fb (wtxid=bac1485cc7cc99e46525c258fe682284e2ae9a9a650ea547a83719cab9cbc8c0) with 6cc0ea35c16a99828071d0ace21726c889cc920c6e4986b58c2e08ed0024787e (wtxid=51d23c0488460dd3e3db887c13a724eefdd2e0660d7abaf5ab598fe2334ddb15) for -0.00002919 additional fees, -360 delta bytes outcome: 6cc0ea35c16a99828071d0ace21726c889cc920c6e4986b58c2e08ed0024787e won, mined by mara pool; replaced tx was ~13 hours old 2024-02-21T12:36:46Z [mempool] replacing tx 2a73fdfdb16a71f55ad6fb0e3165029c51b6b9247fdb88e0e44ad2bb432f8612 (wtxid=3fb092bf764450f3c90cc8856a578283a6586ecda5271004df0db4e65faab0a1) with 1a188e2d321f2b4a544a46843f9c0ce16bdd2cb40b560815297bfab506f53aa5 (wtxid=589dbfe1f80a569bd9253e61b88dfb8ea5e9305698a060bf68633852c75e596f) for -0.0000167 additional fees, -208 delta bytes 2024-02-21T12:36:46Z [mempool] replacing tx ace0e82d9b3df4a4571d2b764223626536fb4a21bb19eff110cbe235cacb8062 (wtxid=8f45a033255c246ecf67bef065ba9be1d4c38295aa0a2849f641c69b13123bfc) with 1a188e2d321f2b4a544a46843f9c0ce16bdd2cb40b560815297bfab506f53aa5 (wtxid=589dbfe1f80a569bd9253e61b88dfb8ea5e9305698a060bf68633852c75e596f) for -0.0000167 additional fees, -208 delta bytes outcome: 1a188e2d321f2b4a544a46843f9c0ce16bdd2cb40b560815297bfab506f53aa5 won, mined by antpool; replaced txs only a few minutes old 2024-01-25T00:52:59Z [mempool] replacing tx 3bdd7b3c76cde41c0d8602a4d21c277350bc2f111f1ce1e543b6b49957c43244 (wtxid=3bdd7b3c76cde41c0d8602a4d21c277350bc2f111f1ce1e543b6b49957c43244) with d38eaf2d7a0a4443703a1f52804aadf2ded6c92bcd010ece323b7dea66427910 (wtxid=d38eaf2d7a0a4443703a1f52804aadf2ded6c92bcd010ece323b7dea66427910) for -0.00001142 additional fees, -191 delta bytes 2024-01-25T00:52:59Z [mempool] replacing tx 24c977c2306a56bb29734e97f1d5c674e324b090a108a267cd9a91ef84d8d671 (wtxid=24c977c2306a56bb29734e97f1d5c674e324b090a108a267cd9a91ef84d8d671) with d38eaf2d7a0a4443703a1f52804aadf2ded6c92bcd010ece323b7dea66427910 (wtxid=d38eaf2d7a0a4443703a1f52804aadf2ded6c92bcd010ece323b7dea66427910) for -0.00001142 additional fees, -191 delta bytes outcome: d38eaf2d7a0a4443703a1f52804aadf2ded6c92bcd010ece323b7dea66427910 won, mined by mara pool; replaced txs ~20 minutes old 2024-02-20T01:11:00Z [mempool] replacing tx 2d58982eacae6acdebc719018de62669a8d47bdac068e8f48316406ab1ac4b03 (wtxid=f99e1001786a067d48045dc7abc7f3bc2cb98e9578f3dc1bb90fc93a004d6b47) with 9f5e001faf92b801eb626587f68986bf2ff1a8c3eddaa0d471d28bcdabe4af54 (wtxid=ab043f343c704f90af12a252b98cdf15c0e7adb2eb07abe9b8579ba13e4d3353) for -0.00000198 additional fees, -349 delta bytes 2024-02-20T01:11:00Z [mempool] replacing tx 300e937ea3617a99d1a9f0bcbdb7b51ad8785015e343e40822071653d913da2c (wtxid=253af0c23392ba028a8af719bdada8dc4aab0bcd6c4dd7b146a4b0717fd83d1c) with 9f5e001faf92b801eb626587f68986bf2ff1a8c3eddaa0d471d28bcdabe4af54 (wtxid=ab043f343c704f90af12a252b98cdf15c0e7adb2eb07abe9b8579ba13e4d3353) for -0.00000198 additional fees, -349 delta bytes 2024-02-20T01:11:00Z [mempool] replacing tx f758901698069d7649e02b50d7f96b6ade7f4d782a17fc7a5d0b4f95c7f595ea (wtxid=9a9f7d5398f9f56d113448cab25dfd17714727fc4f912b3a72f36d4ef005b1d6) with 9f5e001faf92b801eb626587f68986bf2ff1a8c3eddaa0d471d28bcdabe4af54 (wtxid=ab043f343c704f90af12a252b98cdf15c0e7adb2eb07abe9b8579ba13e4d3353) for -0.00000198 additional fees, -349 delta bytes outcome: 9f5e001faf92b801eb626587f68986bf2ff1a8c3eddaa0d471d28bcdabe4af54 won, mined by sbi crypto; replaced txs were many hours old total: 14 unclear: 2 lost: 3 rbfr mined: 9 total rbfr mined: 64% </code></pre></div></div> Sat, 24 Feb 2024 00:00:00 +0000 https://petertodd.org/2024/replace-by-fee-rate-success-rate https://petertodd.org/2024/replace-by-fee-rate-success-rate bitcoin rbf rbfr One-Shot Replace-by-Fee-Rate <p>Currently Bitcoin Core implements a Replace-by-Fee (RBF) policy, where transactions are not replaced unless the new transaction pays at least a higher total fee than the replaced transaction, regardless of fee-rate.</p> <p>When RBF was first implemented over 8 years ago this was a reasonable, conservative, default. However, since then we’ve found that strictly requiring a higher absolute fee creates the potential for <a href="https://bitcoinops.org/en/topics/transaction-pinning/">transaction pinning</a> attacks in contracting protocols such as Lightning; replacing transactions based on <em>fee-rate</em> would make it possible<sup id="fnref:bip125-rule-5-pinning" role="doc-noteref"><a href="#fn:bip125-rule-5-pinning" class="footnote">1</a></sup> to eliminate these attacks by eliminating BIP-125 Rule #3 pinning.</p> <p>Here we will propose an incentive compatible solution, One-Shot Replace-By-Fee-Rate, that mitigates prior concerns over replace-by-fee-rate policies by allowing the replacement to only happen when it would immediately bring a transaction close enough to the top of a mempool to be mined in the next block or so. Finally, we will show that both one-shot and pure replace-by-fee-rate policies sufficiently resist bandwidth exhaustion attacks to be implementable.</p> <p><em>Thanks goes to <a href="https://fulgur.ventures/">Fulgur Ventures</a> for sponsoring this research. They had no editorial control over the contents of this post and did not review it prior to publication.</em></p> <div class="post-toc"> <h1 class="no_toc" id="contents">Contents</h1> <ol id="markdown-toc"> <li><a href="#background" id="markdown-toc-background">Background</a> <ol> <li><a href="#the-expected-return-of-an-unconfirmed-transaction" id="markdown-toc-the-expected-return-of-an-unconfirmed-transaction">The Expected Return of an Unconfirmed Transaction</a></li> <li><a href="#unconfirmed-transactions-are-honest-signals" id="markdown-toc-unconfirmed-transactions-are-honest-signals">Unconfirmed Transactions are Honest Signals</a></li> <li><a href="#expected-return-vs-fee-rate" id="markdown-toc-expected-return-vs-fee-rate">Expected Return vs Fee-Rate</a></li> </ol> </li> <li><a href="#one-shot-replace-by-fee-rate" id="markdown-toc-one-shot-replace-by-fee-rate">One-Shot Replace-by-Fee-Rate</a></li> <li><a href="#denial-of-service-attacks" id="markdown-toc-denial-of-service-attacks">Denial of Service Attacks</a> <ol> <li><a href="#the-status-quo" id="markdown-toc-the-status-quo">The Status Quo</a> <ol> <li><a href="#conflicting-versions" id="markdown-toc-conflicting-versions">Conflicting Versions</a></li> <li><a href="#re-using-third-party-outputs" id="markdown-toc-re-using-third-party-outputs">Re-using Third Party Outputs</a></li> <li><a href="#fill-and-dump-attack" id="markdown-toc-fill-and-dump-attack">Fill and Dump Attack</a></li> </ol> </li> <li><a href="#is-one-shot-replace-by-fee-rate-similar-to-the-status-quo" id="markdown-toc-is-one-shot-replace-by-fee-rate-similar-to-the-status-quo">Is One Shot Replace-By-Fee-Rate Similar To The Status Quo?</a></li> <li><a href="#pure-replace-by-fee-rate" id="markdown-toc-pure-replace-by-fee-rate">Pure Replace-By-Fee-Rate</a></li> </ol> </li> <li><a href="#impact-on-coinjoins" id="markdown-toc-impact-on-coinjoins">Impact on Coinjoins</a></li> <li><a href="#footnotes" id="markdown-toc-footnotes">Footnotes</a></li> </ol> </div> <h2 id="background">Background</h2> <h3 id="the-expected-return-of-an-unconfirmed-transaction">The Expected Return of an Unconfirmed Transaction</h3> <p>Suppose there exists a transaction that pays a fee of \(F\) at a fee-rate \(r\). What is the expected return \(E\) of that transaction to miners as a whole? If the transaction pays a fee-rate high enough to definitely get mined in the next block, the answer seems obvious: \(E = F\). The transaction will be mined, and miners as a whole will earn the entire \(F\) fee.</p> <p>But what if that transaction pays a lower fee-rate? For example, as I write this, <a href="https://mempool.space">mempool.space</a> reports that their mempool contains \(535\mathrm{MvB}\) of transactions, enough that a typical Bitcoin Core node with its typical \(300\mathrm{MB}\) mempool size limit would reject transactions paying less than \(22.9\frac{\mathrm{sat}}{\mathrm{vB}}\).</p> <p>If a transaction has a fee-rate of \(23\frac{\mathrm{sat}}{\mathrm{vB}}\), just barely enough to get into a default mempool, what is that transaction worth to miners? How do we even answer this question?</p> <p>Intuitively it seems obvious that the low fee-rate transaction should be worth less than the high fee-rate transaction, because the low fee-rate transaction probably won’t be mined for days, or even weeks, if ever. Certainly, in a shorter time frame, a transaction at the bottom of a mempool does not directly represent income to the miner.</p> <p>We can think about this a bit more rigorously by observing that because block finding is a Poisson Process, <strong>even if</strong> we ignore the supply of new transactions, the probability that a transaction \(n\) blocks deep is mined in a time interval \(t\) is the probability that \(N \ge n\) blocks are found in the time interval \(t\). That probability rapidly diminishes as \(n\) increases, because it’s less and less likely for so many blocks to be found in a short period of time.</p> <h3 id="unconfirmed-transactions-are-honest-signals">Unconfirmed Transactions are Honest Signals</h3> <p>Do low fee-rate transactions have a value? Yes!</p> <p>Assuming your node is well connected, unconfirmed transactions in your mempool are <em>honest signals</em>: because unconfirmed transactions <em>could</em> be mined, they’re clear evidence that if you wish your transaction to be mined sooner, you need to offer an even higher fee-rate. There’s a constant supply of people with high time preference who want their transactions mined in a short period of time. So low fee-rate transactions indirectly increase the revenue of miners in the short term, because they force higher time preference transactors to outbid them.</p> <p>Note how I said a higher fee-rate, not fee: because it maximizes revenue to mine transactions in fee-rate order, fee-rate is what matters in terms of priority.</p> <h3 id="expected-return-vs-fee-rate">Expected Return vs Fee-Rate</h3> <p>Suppose we now have <em>two</em> different conflicting transactions, \(a\) and \(b\). Suppose that the total size of \(a\) is \(100000\mathrm{vB}\), and pays \(23\frac{\mathrm{sat}}{\mathrm{vB}}\), for a total fee of \(2300000\mathrm{sat}\). Meanwhile \(b\) has a size of just \(150\mathrm{vB}\), and pays \(15000\frac{\mathrm{sat}}{\mathrm{vB}}\), for a total fee of \(2250000\mathrm{sat}\).</p> <p>It seems intuitive that transaction \(b\) is the one the miner should accept to maximize revenue. It pays a <em>far</em> higher fee-rate, almost certainly high enough to be mined in the next block. \(a\) might never get mined, in part because another miner might mine \(b\) first<sup id="fnref:mempool-consensus" role="doc-noteref"><a href="#fn:mempool-consensus" class="footnote">2</a></sup>. Yet currently, Bitcoin Core will reject \(b\), because BIP-125 Rule #3 requires a transaction to pay a higher <em>total</em> fees than the replacement!</p> <p>Conversely if transaction \(b\) was broadcast first, transaction \(a\) would not be accepted even though it pays a higher total fee: Bitcoin Core does not allow a transaction to be replaced unless the replacement pays a higher fee-rate.</p> <h2 id="one-shot-replace-by-fee-rate">One-Shot Replace-by-Fee-Rate</h2> <p>We can mitigate Rule #3 transaction pinning in a miner-incentive compatible way by replacing transactions (or alternatively, transaction packages) that do <em>not</em> qualify for replacement based on the existing rules, if they qualify under these alternative rules:</p> <ol> <li>The new transaction (package) has a fee-rate more than \(r\) times higher than the fee-rate of the transactions it replaces.</li> <li>The new transaction (package) has a sufficiently high fee-rate to place it into the upper \(N\) blocks worth of your mempool.</li> <li>The <em>highest mineable replaced fee-rate</em> is <em>not</em> high enough to place the replaced transactions in the upper \(N\) blocks of your mempool. Highest mineable replaced fee-rate in this context refers to the fee-rate a miner can obtain by mining one or more of the replaced transactions, taking unconfirmed parents<sup id="fnref:unconfirmed-parents" role="doc-noteref"><a href="#fn:unconfirmed-parents" class="footnote">3</a></sup> into account.</li> </ol> <p>Setting \(r = 1.25\) and \(N = 1\) would be reasonable.</p> <p>Provided that a small \(N\) is chosen, this alternative Replace-by-Fee-Rate mechanism solves BIP-125 Rule #3 transaction pinning for contracting protocols such as Lightning because:</p> <ol> <li>If the one-shot RBFr replacement conditions <em>are</em> met, the higher fee-rate intended transaction replaces the pin, and will be mined in the near future.</li> <li>If the replacement conditions are <em>not</em> met, the pin must already have a sufficiently high fee-rate to be mined “soon”, allowing the protocol to make forward progress anyway.</li> </ol> <p>This works because contracting protocols are not secure if they absolutely depend on the highest fee/fee-rate transaction being mined. Mempools don’t have consensus, so it’s impossible to guarantee that a particular transaction gets mined when more than one transaction is possible. But, contracting protocols do require forward progress to be made, defined as transactions getting mined. So as long as we can ensure that a transaction is mined, the protocol can make progress.</p> <p>For miners, these one-shot RBFr rules are reasonably incentive compatible because:</p> <ol> <li>In the typical case where fees are reasonably steady, there is a constant supply of new transactions created by people who want those transactions to be mined in the near future.</li> <li>The old transaction did <em>not</em> have a high enough fee-rate to be mined soon. Thus the value to the miner of that transaction was not the fees themselves. But rather, the <em>fee-rate</em>, which new, high time preference, bidders have to outbid.</li> <li>The new transaction <em>does</em> have a high enough fee-rate to be mined soon. Which means other high time preference transactors will have to outbid it, or alternatively, the transactions it pushed further down their mempool.</li> <li>Contracting protocols, in particular Lightning-like protocols, are profitable to miners because they allow many layer 2 transactions to pay for the transaction fees of a single layer 1 transaction. Adopting rules that allow these protocols to work better will, in the long run, increase miner revenue.</li> <li>It is sufficient for only a subset of miners to run replace-by-fee-rate policies, as well-designed contracting protocols only need to make forward progress eventually, prior to deadlines being reached.</li> </ol> <p>Remember that we are <em>not</em> claiming that one-shot RBFr is always perfectly incentive compatible; no one set of rules could ever be perfectly incentive compatible in all possible scenarios. We are simply claiming that on average, in the situations where these rules are active, miners make more money.</p> <p>Finally node runners should adopt these rules because:</p> <ol> <li>If we assume node runners are donating their bandwidth to be used for the good of Bitcoin users and miners, all the above arguments apply.</li> <li>These rules are usually a strict increase in the number of transactions that nodes propagate to miners; replace-by-fee-rate policies propagate transactions that otherwise would not have been propagated.</li> </ol> <h2 id="denial-of-service-attacks">Denial of Service Attacks</h2> <h3 id="the-status-quo">The Status Quo</h3> <p>The amount of bandwidth transactors can consume by broadcasting Bitcoin transactions must be limited. But even without transaction replacement, the exact way these limits work is non-obvious.</p> <p>You might think that the minimum relay fee implements a direct <em>cost</em> that must be paid to use up bandwidth, if you assume that any transaction will eventually be mined. But in fact this is <strong>not</strong> true! There are a variety of ways that a previously broadcast transaction might become impossible to mine due to a double spend of one of the inputs, by a transaction that did not pay the full cost of the minimum relay fee for that transaction.</p> <p>For example, an attacker could broadcast a large, \(400{\small,}000\mathrm{byte}\), low fee-rate transaction that violates <a href="https://ocean.xyz/">Ocean</a> mining pool’s restrictions on data carrying transactions. Almost all relay nodes will relay this transaction, using up relay bandwidth. But at some point in the future, the attacker can give Ocean a much smaller transaction spending one of that large, low fee-rate, transaction’s inputs. It will eventually be mined, creating a conflict that invalidates the large transaction, at a much lower cost than the total fees the large transaction was supposed to pay.</p> <p>Similarly, an attacker could broadcast a large, low fee-rate, transaction while simultaneously sending a small double-spend directly to a mining pool. With good timing, the super-majority of nodes will waste bandwidth broadcasting the large transaction, which is eventually removed from mempools when the small transaction is mined at low cost.</p> <p>How much is such an attacker paying? Interestingly, the worst case is made a bit worse worse if the <a href="https://github.com/instagibbs/bips/blob/7d79c5692bb745bf158f2d8f8e4979d80ad07e58/bip-ephemeralanchors.mediawiki">ephemeral anchors</a> proposal is implemented. So for the purpose of conservatively analyzing a worst case situation, we will assume the attacker makes use of the most efficient possible version of ephemeral anchors, a bare <code class="language-plaintext highlighter-rouge">scriptPubKey</code> spent by an <code class="language-plaintext highlighter-rouge">OP_True</code>. If ephemeral anchors is <em>not</em> implemented, all of the steps below can be done nearly as efficiently via P2SH outputs with the spending script <code class="language-plaintext highlighter-rouge">OP_True</code>.</p> <ol> <li>Attacker creates \(N\) ephemeral anchor outputs.<sup id="fnref:creating-ephemeral-anchors" role="doc-noteref"><a href="#fn:creating-ephemeral-anchors" class="footnote">4</a></sup></li> <li>Attacker broadcasts \(N\), \(404{\small,}000\mathrm{byte}\) transaction packages<sup id="fnref:transaction-package-limit" role="doc-noteref"><a href="#fn:transaction-package-limit" class="footnote">5</a></sup> with fee-rate low enough to not be mined any time soon, in such a way that the transactions is <em>not</em> accepted by some hash power. Each transaction spends an ephemeral anchor output.</li> <li>Attacker spends those \(N\) ephemeral anchor outputs in a transaction paying market fee-rates rates.</li> </ol> <p>Spending each ephemeral output requires an additional \(41\mathrm{vB}\) per output spent, and creating an ephemeral output, an additional \(9\mathrm{vB}\). Thus the attacker has broadcast \(404{\small,}000\mathrm{bytes}\) while paying for just \(50\mathrm{vB}\), a \(\frac{1}{8080}\) cost reduction<sup id="fnref:cost-reduction" role="doc-noteref"><a href="#fn:cost-reduction" class="footnote">6</a></sup> over the intended minimum relay fee.</p> <p>Remember, we are <em>not</em> analyzing replace-by-fee-rate here! We’re just looking at what is <em>already possible</em> with Bitcoin Core. Or at least, almost already possible, as <code class="language-plaintext highlighter-rouge">OP_True</code> P2SH outputs cost only a bit more.</p> <p>So why isn’t this attack happening? Let’s work out how much it costs, using the current Bitcoin price and current lower-bound mining fees:</p> \[\frac{50\mathrm{vB}}{404{\small,}000\mathrm{B}} \times \frac{30\mathrm{sat}}{\mathrm{vB}} \times \frac{40{\small,}000 \mathrm{USD}}{100{\small,}000{\small,}000\mathrm{sats}} \approx \frac{1485 \mathrm{USD}}{\mathrm{GB}}\] <p>Even Digital Ocean charges just \(0.01\frac{\mathrm{USD}}{\mathrm{GB}}\)<sup id="fnref:digital-ocean-bandwidth-cost" role="doc-noteref"><a href="#fn:digital-ocean-bandwidth-cost" class="footnote">7</a></sup>. So if you wanted to DoS attack all ~20,000 publicly reachable nodes, you’d be spending only \(200\frac{\mathrm{USD}}{\mathrm{GB}}\). This isn’t an entirely fair comparison, as relaying transactions also uses up bandwidth on non-public nodes. But it is an indication that there are probably cheaper and more effective ways to attack Bitcoin.</p> <h4 id="conflicting-versions">Conflicting Versions</h4> <p>Attackers can further multiply the bandwidth usage of their attack by simultaneously broadcasting multiple conflicting versions of the large transaction to different nodes, where each conflict pays the same fee/fee-rate. At the points in the node network graph where the conflicts “meet”, nodes will end up downloading multiple versions from their peers, again increasing bandwidth usage by the number of conflicts each node sees.</p> <p>Analyzing this case is more difficult, as the impact depends on network topology, and the attacker has to use more of their own bandwidth broadcasting the conflicting transactions. But in a perfectly executed attack, a node might receive one conflicting version per peer; public nodes have, by default, up to 125 connections, and non-public nodes have, by default, 8 outgoing transaction relaying peers.</p> <p>Even in the 125x public node case it would probably be cheaper to try to DoS attack all publicly accessible nodes via an unsophisticated packet flood.</p> <h4 id="re-using-third-party-outputs">Re-using Third Party Outputs</h4> <p>An attacker can make use of others’ transactions rather than creating their own transaction outputs to reduce cost. This of course <em>is</em> a transaction pinning attack! Doing this is possible against unsigned anchor outputs, as well as transactions signed with <code class="language-plaintext highlighter-rouge">SIGHASH_ANYONECANPAY</code>. However for the purpose of using up relay bandwidth this attack strategy is inherently limited by two factors:</p> <ol> <li>There usually aren’t that many suitable victim transactions being broadcast, limiting the total bandwidth that can be consumed.</li> <li>The attacker has to intercept the victim transactions prior to them being widely broadcast, and somehow get their “bloated” versions of those transactions widely broadcast first.</li> </ol> <h4 id="fill-and-dump-attack">Fill and Dump Attack</h4> <p>In addition to using up bandwidth an attacker could also use transaction invalidation to fill, and then empty, mempools at less cost than the full fees required to broadcast the “fill” transactions. In fact, any attack that tries to use up a significant amount of relay bandwidth by mining conflicting transactions will have this effect by default, as conflicts can only invalidate transactions when blocks are mined.</p> <p>Filling mempools requires access to large amounts of capital. Bitcoin Core implements the mempool size limit in terms of <em>RAM</em> usage, not serialized bytes, so exactly what the default \(300\mathrm{MB}\) limit means depends on CPU architecture. But for sake of argument, let’s say that the limit works out to approximately \(75\mathrm{MvB}\) worth of transactions, and the attacker is “filling” \(70\mathrm{MvB}\) worth, to avoid getting their transactions actually mined. Even at \(10\frac{\mathrm{sat}}{\mathrm{vB}}\) the attacker needs:</p> \[70\mathrm{MvB} \times \frac{10\mathrm{sat}}{\mathrm{vB}} \times \frac{40{\small,}000 \mathrm{USD}}{100{\small,}000{\small,}000\mathrm{sats}} = 280{\small,}000 \mathrm{USD}\] <p>An obvious question is, what exactly does this attack accomplish? Transactions that are outbid can simply be rebroadcast by anyone once mempools have space again; while the transactions are in mempools the attacker is legitimately outbidding those transactions, and they could hypothetically be mined. Arguably the transactions are driving up fees overall. But unless the attacker wants to bid high enough that their “fill” transactions actually get mined, the attacker isn’t having any direct impact on the higher fee part of mempools that is actually getting mined.</p> <h3 id="is-one-shot-replace-by-fee-rate-similar-to-the-status-quo">Is One Shot Replace-By-Fee-Rate Similar To The Status Quo?</h3> <p>Yes.</p> <p>As we have shown above, an attacker can already broadcast large transactions that are invalidated by smaller transactions that pay less total fees. With one-shot replace-by-fee-rate the attack becomes a little less challenging to pull off, as it can be done generically, rather than with a target mining pool. But either way, the real limiting factor to the attack is that it is <em>still</em> a very expensive way to use up bandwidth.</p> <p>With regard to the fill-and-dump attack, again the attacker is able to do fill-and-dump cycles more frequently than once per block with one-shot replace-by-fee-rate. But again, we have to ask what does the attacker get out of this other than bandwidth consumption, and possibly confusing some badly written fee estimation code?</p> <h3 id="pure-replace-by-fee-rate">Pure Replace-By-Fee-Rate</h3> <p>What if we don’t have the one-shot condition? Is a pure replace-by-fee-rate policy viable from a DoS attack perspective? This is an important question because:</p> <ol> <li>An initial prototype is easier to implement without the one-shot feature, and compatible with nodes/miners who choose to do something more sophisticated.</li> <li>Pure replace-by-fee-rate is simpler for users to understand.</li> <li>In a rising fee-rate environment, the one-shot policy may degrade to pure replace-by-fee-rate.</li> </ol> <p>Provided that the minimum fee-rate ratio, \(r\) is sufficiently high the total number of plausible replacements is limited. For example, even starting at just \(1\frac{\mathrm{sat}}{\mathrm{vB}}\), \(r = 1.25\) results in:</p> \[1\frac{\mathrm{sat}}{\mathrm{vB}} \times 1.25^{30} \approx 808\frac{\mathrm{sat}}{\mathrm{vB}}\] <p>That’s sufficient to get into the next block at any point in time in Bitcoin’s history, for a mere 30x theoretical increase in bandwidth, by an attacker who is going to have to tie up thousands of dollars worth of BTC just to broadcast a few megabytes worth of transactions. And that example is unrealistic, as minimum relay fees were never actually that low during Bitcoin’s high fee events.</p> <p>It’s probably worth trying out pure replace-by-fee-rate in a Bitcoin Core fork, especially if \(r\) is set to a more conservative value, e.g. \(r=2\).</p> <h2 id="impact-on-coinjoins">Impact on Coinjoins</h2> <p>Replace-by-fee-rate does introduce a new way to double-spend low fee-rate coinjoin transactions at lower cost than outbidding the entire fee paid by the coinjoin. This is most relevant to Wasabi, which typically creates coinjoin transactions with hundreds of inputs and outputs; other coinjoin implementations create much smaller transactions.</p> <p>However, double-spending is not a new attack. There are already other cheap ways to cause coinjoin rounds to fail, including other types of double-spend attacks, and cheapest of all, simply failing to complete the coinjoin protocol by failing to provide a signature where required. Wasabi deals with this by imposing a cost on the attacker, by blacklisting UTXO’s that fail to complete a coinjoin round for a period of time; the majority of Wasabi coinjoin rounds fail due to one of the parties failing to sign in time.</p> <p>Simply failing to sign is generally a cheaper attack than double-spending, as any type of double-spend requires fees to be paid per round disrupted. Thus replace-by-fee-rate is unlikely to pose a significant threat to coinjoin protocols.</p> <h2 id="footnotes">Footnotes</h2> <div class="footnotes" role="doc-endnotes"> <ol> <li id="fn:bip125-rule-5-pinning" role="doc-endnote"> <p>The other notable pinning attack against RBF is to cause BIP-125 Rule #5 to be exceeded. But that is easily solved by just rejecting transactions that would make transactions already in a mempool to be irreplaceable. <a href="#fnref:bip125-rule-5-pinning" class="reversefootnote" role="doc-backlink">&#8617;</a></p> </li> <li id="fn:mempool-consensus" role="doc-endnote"> <p>There is no such thing as <em>the</em> mempool: every miner (and node) has their own mempool, and there’s no mechanism to synchronize mempools beyond the best-effort broadcasting of transactions. The need for consensus is why we have the blockchain in the first place. <a href="#fnref:mempool-consensus" class="reversefootnote" role="doc-backlink">&#8617;</a></p> </li> <li id="fn:unconfirmed-parents" role="doc-endnote"> <p>For example, if transation \(a\) is spent by \(b\), and the fee-rate \(r_a \ge r_b\), then the fee-rate of \(a\) is the highest mineable replaced fee-rate. On the other hand, if \(r_a &lt; r_b\), then the highest minable replaced fee-rate is computed as the CPFP package of \(a\) and \(b\). We refer to this as a <em>mineable</em> fee-rate because while the fee-rate of \(b\) may be higher, a miner can’t obtain that fee-rate directly: \(a\) must also be mined. <a href="#fnref:unconfirmed-parents" class="reversefootnote" role="doc-backlink">&#8617;</a></p> </li> <li id="fn:creating-ephemeral-anchors" role="doc-endnote"> <p>This may require the cooperation of a mining pool willing to mine non-standard transactions. <a href="#fnref:creating-ephemeral-anchors" class="reversefootnote" role="doc-backlink">&#8617;</a></p> </li> <li id="fn:transaction-package-limit" role="doc-endnote"> <p>The relevant limit here is <em>not</em> the total size of a single transaction, because more than one transaction can be replaced at a time. Rather it’s the default descendant size limit, which is slightly higher than the maximum transaction size. Note that in reality our \(404{\small,}000\mathrm{byte}\) figure is a slight overestimate as the descendant size limit has units of virtual bytes rather than bytes. <a href="#fnref:transaction-package-limit" class="reversefootnote" role="doc-backlink">&#8617;</a></p> </li> <li id="fn:cost-reduction" role="doc-endnote"> <p>Assuming that the fee-rate paid by the spending and creation of the outputs was the same. This might not be the case as the attacker could setup the outputs to be spent in advance. <a href="#fnref:cost-reduction" class="reversefootnote" role="doc-backlink">&#8617;</a></p> </li> <li id="fn:digital-ocean-bandwidth-cost" role="doc-endnote"> <p><a href="https://docs.digitalocean.com/products/billing/bandwidth/">Bandwidth Billing</a>, accessed Jan 15th 2024. Specifically the <em>excess</em> bandwidth charge, ignoring the bandwidth included per month. There are many other hosting providers offering even cheaper bandwidth. <a href="#fnref:digital-ocean-bandwidth-cost" class="reversefootnote" role="doc-backlink">&#8617;</a></p> </li> </ol> </div> Thu, 18 Jan 2024 00:00:00 +0000 https://petertodd.org/2024/one-shot-replace-by-fee-rate https://petertodd.org/2024/one-shot-replace-by-fee-rate bitcoin rbf pinning V3 Transactions Review <p>V3 transactions is a proposed set of mempool policies with the aim of allowing transactions to use Child-Pays-For-Parent (CPFP), anchor outputs, and package relay as the primary method of paying for fees in contracting protocols such as Lightning. In this article we will go over how V3 transactions and anchor outputs are meant to work, their role in protocols such as Lightning. Finally we’ll show that their dependence on CPFP makes them significantly more expensive in terms of blockspace, and thus fees, than using Replace-by-Fee (RBF) techniques, increasing the cost of force-closes by approximately 2x in most cases. We’ll also explain how V3 transactions are a potential threat to mining decentralization due to the fact that out-of-band fee payment can be significantly cheaper than anchor outputs.</p> <p><em>Thanks goes to <a href="https://fulgur.ventures/">Fulgur Ventures</a> for sponsoring this research. They had no editorial control over the contents of this post and did not review it prior to publication.</em></p> <div class="post-toc"> <h1 class="no_toc" id="contents">Contents</h1> <ol id="markdown-toc"> <li><a href="#background" id="markdown-toc-background">Background</a> <ol> <li><a href="#anchor-channels" id="markdown-toc-anchor-channels">Anchor Channels</a></li> <li><a href="#package-relay" id="markdown-toc-package-relay">Package Relay</a></li> </ol> </li> <li><a href="#v3-transactions" id="markdown-toc-v3-transactions">V3 Transactions</a></li> <li><a href="#replace-by-fee" id="markdown-toc-replace-by-fee">Replace-by-Fee</a> <ol> <li><a href="#fee-allocation" id="markdown-toc-fee-allocation">Fee Allocation</a></li> <li><a href="#htlcs-and-replace-by-fee" id="markdown-toc-htlcs-and-replace-by-fee">HTLCs and Replace-by-Fee</a></li> <li><a href="#hybrid-replace-by-fee--anchors" id="markdown-toc-hybrid-replace-by-fee--anchors">Hybrid Replace-by-Fee + Anchors</a></li> <li><a href="#efficiency" id="markdown-toc-efficiency">Efficiency</a></li> <li><a href="#non-native-asset-protocols" id="markdown-toc-non-native-asset-protocols">Non-Native Asset Protocols</a></li> </ol> </li> <li><a href="#anchor-outputs-are-a-danger-to-mining-decentralization" id="markdown-toc-anchor-outputs-are-a-danger-to-mining-decentralization">Anchor Outputs Are a Danger to Mining Decentralization</a></li> <li><a href="#protocol-design" id="markdown-toc-protocol-design">Protocol Design</a></li> <li><a href="#recommendations" id="markdown-toc-recommendations">Recommendations</a></li> <li><a href="#footnotes" id="markdown-toc-footnotes">Footnotes</a></li> </ol> </div> <h2 id="background">Background</h2> <p>Lightning channels and similar protocols work by exchanging pre-signed transactions that are not meant to be mined except in exceptional circumstances. Namely, lack of agreement between the parties. In these exceptional circumstances — such as the other party to a channel going off-line — funds are recovered by signing and broadcasting the necessary transactions. For example, in a typical case without HTLCs pending, the parties to the channel would both have a commitment transaction corresponding to the latest state of the channel that spends the 2-of-2 multisig holding the channel funds, to pubkeys controlled by each party.</p> <p>The problem is that fee rates required for inclusion in a block change regularly, and dramatically. Secondly, Bitcoin Core currently requires that transaction meet a minimum fee rate to be considered for inclusion into the mempool of a node. This minimum fee rate varies depending on demand, as the total maximum size of a node’s mempool is fixed.</p> <p>While the Lightning protocol has a mechanism for peers to negotiate the fee-rate of the pre-signed transactions, this mechanism can not predict the future. Thus there frequently are circumstances where the fee-rates of pre-signed transactions are either too low for timely inclusion in a block, or higher than necessary, wasting funds on fees.</p> <p>In certain cases an unexpected increase in fees can even make resolving the channel state impossible, because the minimum fee necessary for inclusion into a mempool can increase beyond the fee-rate of the pre-signed transaction. This is particularly harmful if HTLCs are outstanding, as they can have a strict time window in which they must resolve, or funds can be lost.</p> <h3 id="anchor-channels">Anchor Channels</h3> <p>A partial solution that has been implemented in Lightning is Anchor Channels. These make use of two key technologies:</p> <ol> <li><a href="https://bitcoinops.org/en/topics/cpfp/">Child-Pays-For-Parent (CPFP)</a>: if a child transaction has a higher feerate than its unconfirmed parent, the fee for the child transaction effectively pays for the parent, making it worthwhile to mine the parent.</li> <li><a href="https://bitcoinops.org/en/topics/anchor-outputs/">Anchor Outputs</a>: zero or near-zero value outputs added to a transaction for the sole purpose of being spent by a CPFP fee-bumping transaction.</li> </ol> <p>With Anchor Channels, two anchor outputs of dust-sized value are added to commitment transactions for the purpose of allowing the local and/or remote end of the channel to use CPFP to increase the effective fee of the commitment transaction in the event that the fee chosen is too small to be mined in a reasonable amount of time.</p> <p>Both anchor outputs have a script of the form:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>&lt;local_funding_pubkey/remote_funding_pubkey&gt; OP_CHECKSIG OP_IFDUP OP_NOTIF OP_16 OP_CHECKSEQUENCEVERIFY OP_ENDIF </code></pre></div></div> <p>You might wonder why an output with essentially no value even has a <code class="language-plaintext highlighter-rouge">OP_CHECKSIG</code> operator. Why not use a bare-minimum <code class="language-plaintext highlighter-rouge">OP_TRUE</code> output? After all, if someone else spends the output, doesn’t that mean they are simply paying to get our transaction mined?</p> <p>Unfortunately, we have to deal with <a href="https://bitcoinops.org/en/topics/transaction-pinning/">transaction pinning attacks</a>: methods that make RBF fee bumping prohibitively expensive or even impossible. Basically, if the output was just an <code class="language-plaintext highlighter-rouge">OP_TRUE</code>, an attacker could broadcast a transaction using a pinning attack technique that spends the <code class="language-plaintext highlighter-rouge">OP_TRUE</code> anchor output in such a way that it is expensive or even impossible for us to use RBF to pay a high enough fee to get the commitment transaction mined in a reasonable amount of time.</p> <p>Thus the <code class="language-plaintext highlighter-rouge">OP_CHECKSIG</code> ensures that only the parties actually in the channel can spend the anchor outputs, preventing any pinning attacks. Equally, this is why there are two anchor outputs: we do not want one party to be able to use transaction pinning against the other party.</p> <p>In fact, the two anchor outputs are redundant: the <code class="language-plaintext highlighter-rouge">to_remote</code> output could have served as the <code class="language-plaintext highlighter-rouge">to_remote_anchor</code> output, as I discovered while writing this blog post. Only one anchor output is necessary.<sup id="fnref:redundant-remote-anchor" role="doc-noteref"><a href="#fn:redundant-remote-anchor" class="footnote">1</a></sup></p> <h3 id="package-relay">Package Relay</h3> <p>Currently, Bitcoin Core evaluates transactions for inclusion in the mempool in isolation, without taking into account any child transactions. Thus even with anchor channels it is possible for fee-rates to increase so much that the commitment transaction is ineligible for inclusion due to the mempool size limit. In this circumstance, anchor outputs can’t use the CPFP mechanism, as the parent transaction never got into the mempool to begin with.</p> <p><a href="https://bitcoinops.org/en/topics/package-relay/">Package Relay</a> aims to solve this problem by evaluating <em>packages</em> of transactions, as a whole. With package relay, even a zero feerate parent could be accepted into the mempool so long as the package contains a child that pays for the parent via CPFP.</p> <p>If package relay were implemented, anchor channels would work in all circumstances. They would still be inefficient compared to replace-by-fee — as we will discuss later — but they would at least work regardless of mempool conditions.</p> <h2 id="v3-transactions">V3 Transactions</h2> <p>The <a href="https://github.com/bitcoin/bitcoin/pull/28948">V3 Transactions</a> proposal combines package relay, ephemeral anchors, and new mempool acceptance rules in an attempt to improve on anchor channels and anchor outputs. Notably, the “V3” in “V3 Transactions” refers to a new <em>non-consensus</em> <code class="language-plaintext highlighter-rouge">nVersion</code> 3, which miners and nodes are expected to <em>altruistically</em> treat differently by preventing the outputs of V3 transactions from being spent in certain ways.</p> <p>Thus we have three parts to the V3 transaction proposal:</p> <ol> <li>Package Relay: Quite simply, V3 transactions assumes that package relay has been implemented. Though note that package relay is a separate feature, that by itself has nothing to do with V3 transactions.</li> <li><a href="https://github.com/instagibbs/bips/blob/7d79c5692bb745bf158f2d8f8e4979d80ad07e58/bip-ephemeralanchors.mediawiki">Ephemeral Anchors</a>: Anchor outputs with (potentially) zero value, and a simple <code class="language-plaintext highlighter-rouge">OP_TRUE</code> or equivalent script, along with mempool rules that allow the dust rule to be ignored in packages that both create and spend less than dust-valued transaction outputs in the same package. Notably, this keeps less than dust-valued outputs out of the UTXO set, as they are created and spent in the same block.</li> <li>Non-Consensus restrictions on spending the outputs of V3 transactions, intended to prevent pinning attacks. As we discussed above, <code class="language-plaintext highlighter-rouge">OP_TRUE</code> anchors are vulnerable to pinning attacks; the V3 spending restrictions are intended to prevent these attacks.</li> </ol> <p>By “non-consensus”, what we mean is that the actual block validity rules have not been changed. Rather, Bitcoin Core will reject transactions attempting to spend outputs of V3 transactions — even if they are valid and profitable for miners — if those transactions do not meet certain criteria, the main one being that transactions spending unconfirmed V3 outputs will be rejected unless they are less than \(1000\mathrm{vB}\) in size. This restriction prevents significant transaction pinning attacks, which in turn makes it possible for the anchor output to be a simple <code class="language-plaintext highlighter-rouge">OP_TRUE</code> that anyone can spend. Since the transaction spending that output can’t be pinned, if a 3rd party does spend it with a low-fee transaction, anyone can simply replace that transaction with a higher fee transaction.</p> <p>At least, that is the idea. Unfortunately, because the \(1000\mathrm{vB}\) limit is much bigger than a typical commitment transaction and ephemeral anchor spend, attackers can still do cheap and effective pinning attacks against third parties. Exactly how cheap and how effective depends on the mempool environment. But an attacker spending little to no money can <a href="/2023/v3-txs-pinning-vulnerability">increase the fees the victim pays for a Lightning channel force-close by a factor of ~1.5x</a>, with the maximum possible increase in a one-shot attack being ~3.7x.</p> <h2 id="replace-by-fee">Replace-by-Fee</h2> <p>One obvious solution to this problem is to simply pre-sign transactions at different fee rates. While at first glance this may seem inefficient, computers are fast and bandwidth is cheap: a (musig2) signing operation with secp256k1 typically takes on the order of \(100\mathrm{us}\) to complete per key<sup id="fnref:musig2-benchmark" role="doc-noteref"><a href="#fn:musig2-benchmark" class="footnote">2</a></sup><sup id="fnref:secp256k1-benchmark" role="doc-noteref"><a href="#fn:secp256k1-benchmark" class="footnote">3</a></sup>, and produces a 64 byte signature. Since transactions variants can be generated deterministically, only the parameters for the deterministic generation, and the signatures themselves, need to be exchanged. Not the full transactions. Lightning already uses this technique: the exact form of transactions is nailed down by the Lightning specification.</p> <p>How many fee variants are needed? According to <a href="https://mempool.space/graphs/mempool#all">mempool.space</a>’s data, over the past six years the fees required to get into the next block have ranged from about \(1\frac{\mathrm{sat}}{\mathrm{vB}}\) to \(500\frac{\mathrm{sat}}{\mathrm{vB}}\).</p> <p>If our range of fees is from \(a\) to \(b\), inclusive, with each increment being \(r\), we can compute how many increments \(N\) we need as follows:</p> \[b = ar^n \implies N = \left \lceil \frac{\ln \left( \frac{b}{a} \right)}{\ln \left(r \right)} \right \rceil + 1\] <p>For example, if you wanted to cover \(10\frac{\mathrm{sat}}{\mathrm{vB}}\) to \(1000\frac{\mathrm{sat}}{\mathrm{vB}}\), with \(10\%\) increments, you’d only need 50 fee variants, for a total size of 3200 bytes, taking just \(5\mathrm{ms}\) to sign (single core). Given the very good scalability of Lightning, this overhead is reasonable.</p> <p><em>Update: turns out AINCQ’s Phoenix wallet recently implemented a partial version of RBF for channels in the underlying <a href="https://github.com/ACINQ/lightning-kmp/pull/553">lightning-kmq</a> library.</em></p> <h3 id="fee-allocation">Fee Allocation</h3> <p>Existing Lightning channels actually need <em>two</em> commitment transactions, the remote commitment and the local commitment, as the commitment transaction for each side is slightly different; the above fee variants calculation refers to the number of variants on each side, not the total number. Each commitment transaction is signed by the other party, which introduces the ability to allocate fees to different sides. In most cases, it would make sense to take the fees from the side that broadcast the commitment transaction; each side is signing a transaction that gives the other side the ability to spend <em>their own</em> money to fees, if they choose to, by counter signing<sup id="fnref:counter-signing-and-musig" role="doc-noteref"><a href="#fn:counter-signing-and-musig" class="footnote">4</a></sup> the transaction and broadcasting it.</p> <p>If fees are allocated to the side that chooses to broadcast the commitment transaction, the maximum fee rate can be the entire value of the channel on that side; the counterparty can’t grief the other side by broadcasting a high-fee commitment, as the only commitment transactions they can broadcast spend <em>their</em> money to fees. This has the advantage of making it impossible to be in a situation where a sufficiently high fee-rate isn’t available: if more than the entire local balance of the channel needs to go to fees to get it mined, it is pointless for the local party to try to get the commitment transaction mined. They might as well wait for fees to decrease, or abandon the channel funds.</p> <p><em>Thanks goes to Antoine Poinsot for bringing up the need for this section to clearly explain this point.</em></p> <h3 id="htlcs-and-replace-by-fee">HTLCs and Replace-by-Fee</h3> <p>Lightning commitment transaction HTLC outputs can only be spent by pre-signed <a href="https://github.com/lightning/bolts/blob/8a64c6a1cef979b3f0cecb00ba7a48c2d28b3588/03-transactions.md#htlc-timeout-and-htlc-success-transactions">HTLC-Timeout or HTLC-Success transactions</a>. These separate transactions are required because the HTLC output may have been created by a revoked commitment, and we need to give the other side a chance to use the revocation pubkey. In anchor channels, these HTLC transactions are <a href="https://github.com/lightning/bolts/blob/8a64c6a1cef979b3f0cecb00ba7a48c2d28b3588/05-onchain.md#generation-of-htlc-transactions">pre-signed with <code class="language-plaintext highlighter-rouge">SIGHASH_SINGLE|SIGHASH_ANYONECANPAY</code></a>, allowing the local side to fee-bump these transactions by adding additional inputs and outputs.</p> <p>Since additional inputs and outputs can be added the minimum relay fee is <em>not</em> a problem: we can always add a sufficiently large input/output to meet the minimum. Thus one way to use replace-by-fee commitment transactions is to simply pre-sign HTLC timeout/success transactions for each variant, and continue using the “add an input” mechanism. This simply increases the work done per HTLC by a factor of \(N\), and again, because these transactions are made deterministically, this is cheap and easy.</p> <p>Signing multiple fee variants for the HTLC timeout/success transactions is also possible. While at worst this requires on the order of \(N^2\) total work, a reduction is possible by recognizing that usually the HTLC transactions will usually need fees close to that of the commitment transactions. Note how fee variants are the preferable option for end-user wallets such as Phoenix, which try to have a single UTXO per user, and thus don’t have any spare UTXO’s to add to HTLC outputs.</p> <p>Finally <a href="https://github.com/bitcoin/bips/blob/deae64bfd31f6938253c05392aa355bf6d7e7605/bip-0118.mediawiki"><code class="language-plaintext highlighter-rouge">SIGHASH_ANYPREVOUT</code></a> would fix the \(N^2\) problem by allowing any HTLC fee variant to spend any commitment transaction fee variant.</p> <h3 id="hybrid-replace-by-fee--anchors">Hybrid Replace-by-Fee + Anchors</h3> <p>A hybrid approach is also possible. Fee variants can be used for part of the fee range, with an anchor-output containing variant being signed for the highest fee variant.</p> <h3 id="efficiency">Efficiency</h3> <p>Replace-by-fee is significantly more efficient than anchor outputs because it only requires a single transaction. A typical V3-using Lightning channel commitment transaction is \(163\mathrm{vB}\) in size<sup id="fnref:commitment-tx-size" role="doc-noteref"><a href="#fn:commitment-tx-size" class="footnote">5</a></sup>, and requires a \(152\mathrm{vB}\) ephemeral output transaction<sup id="fnref:ephemeral-spend-tx-size" role="doc-noteref"><a href="#fn:ephemeral-spend-tx-size" class="footnote">6</a></sup> to pay for fees, \(315\mathrm{vB}\) in total.</p> <p>Since a RBF-using commitment transaction doesn’t need an anchor output, it’s just \(154\mathrm{vB}\) in size, with no second transaction needed. V3 transactions are <em>at least</em> twice the size, and thus twice the cost, as using RBF.</p> <p>But it gets worse: V3 transactions require extra outputs to be kept around purely for the purpose of fee bumping. Maintaining these extra outputs is difficult and expensive for many Lightning nodes, in particular, smaller nodes/wallets. It’s difficult to decide what % of total funds to allocate to these outputs, and of course, blockspace has to be used up creating them.</p> <p>Most analysis’s of Bitcoin’s ultimate scaling capacity ignore this: with anchor outputs, each Lightning user needs at least <em>two</em> UTXO’s to be created, not just one, cutting the total possible number of global users who can be on-boarded to Lightning by approximately half.</p> <p>A particularly bad example of this problem is seen in user-oriented wallets like Phoenix<sup id="fnref:phoenix" role="doc-noteref"><a href="#fn:phoenix" class="footnote">7</a></sup> that aim to keep all user funds in a single Lightning channel, using splice-ins and splice-outs to add and withdraw on-chain funds.</p> <h3 id="non-native-asset-protocols">Non-Native Asset Protocols</h3> <p>Protocols such as RGB Lightning channels and LND’s taproot assets that aim to use Lightning-style channels with non-Bitcoin assets may be forced to tie up more BTC than desired to use RBF techniques, as the assets they are actually trying to trade can’t be directly used to pay fees. For large channels this is probably not a problem, as the BTC value will be small in comparison to the channel value. But smaller channels may need to use other techniques.</p> <p>For example, <a href="https://github.com/bitcoin/bips/blob/deae64bfd31f6938253c05392aa355bf6d7e7605/bip-0118.mediawiki"><code class="language-plaintext highlighter-rouge">SIGHASH_ANYPREVOUT</code></a> could allow commitment transactions to be signed with <code class="language-plaintext highlighter-rouge">SIGHASH_ANYONECANPAY</code>, allowing RBF fee bumping by adding additional inputs if needed. Of course, this potentially invites problems such as transaction pinning.</p> <p><em>Thanks goes to Brandon Black for <a href="https://twitter.com/reardencode/status/1741875451273077135">pointing out</a> this issue.</em></p> <h2 id="anchor-outputs-are-a-danger-to-mining-decentralization">Anchor Outputs Are a Danger to Mining Decentralization</h2> <p>Since Anchor Outputs are so much less efficient than RBF — about 2x the cost — they pose a significant danger to mining decentralization because of out-of-band fee payment. The problem is that if you have an anchor-using transaction that you need to get mined, it costs twice as much blockspace to get the transaction mined via the intended mechanism — the anchor output — as it does by getting a miner to include the transaction without the anchor output spend.</p> <p>Some large miners are already accepting out-of-band payments for transactions, allowing you to pay them directly to get your transaction mined; <em>only</em> large miners can reasonably offer this service, as only large miners find blocks sufficiently frequently to make out-of-band fee payments worthwhile. Decentralized mining pools such as P2Pool and Braidpool have absolutely no hope of being able to offer out-of-band fee payments at all.</p> <p>Since a typical anchor-output using Lightning channel takes 2x more block space, a large miner could easily offer out-of-band fee payments at, say, a 25% discount, giving them a substantial 25% premium over their smaller competitors. Given that mining pool fees are highly competitive, on the order of 1% or 2%, being able to earn a 25% premium over your competitors is an enormous advantage. With Lightning, offering this as a service in an automated, convenient, way would be quite easy to implement.</p> <p>We <strong>must not</strong> build protocols that put decentralized mining at a disadvantage. On this basis alone, there is a good argument that V3 transactions and ephemeral anchor outputs should not be implemented.</p> <h2 id="protocol-design">Protocol Design</h2> <p>We as a community should ask how such an inefficient proposal, with significant potential harm to mining decentralization, has managed to progress as far as it has. The <a href="https://github.com/bitcoin/bitcoin/pull/28948">V3 transactions pull-reqs</a> have been around in various forms for over a year now without a BIP or any real design documents. In particular, the author recently admitted<sup id="fnref:gz-bitcoin-dev" role="doc-noteref"><a href="#fn:gz-bitcoin-dev" class="footnote">8</a></sup> that their understanding of the size of a typical Lightning commitment transaction was dramatically wrong, leading to the <a href="/2023/v3-txs-pinning-vulnerability">V3 transaction pinning</a> problem mentioned above.</p> <p>With complex protocol decisions such as this, we should not rush into implementing code. We should identify actual use-cases and work through the efficiency and implications of these use-cases. The documentation around V3 transactions accessible via the pull-req simply does not have that kind of analysis at the moment; as far as I’m aware, I’m the first person to properly compare it to other solutions.</p> <h2 id="recommendations">Recommendations</h2> <ol> <li>Package relay should probably be added to Bitcoin Core. CPFP is useful outside of contracting protocols, for example, to bump the fees of payments sent to you. The alternative in those cases is to either get the sender to bump fees — not always practical — or use out-of-band fee payment. Secondly, Lightning has already shipped anchor channels, which would benefit immediately from CPFP.</li> <li>Existing usage of anchor outputs should be phased out due to the above-mentioned miner decentralization risks; new anchor output support should not be added to new protocols or Bitcoin Core.</li> <li>V3 transactions should not be be shipped at the moment. It has no compelling use-cases right now without ephemeral outputs, which should be discouraged, and in its current form is still vulnerable to transaction pinning.</li> </ol> <h2 id="footnotes">Footnotes</h2> <div class="footnotes" role="doc-endnotes"> <ol> <li id="fn:redundant-remote-anchor" role="doc-endnote"> <p><a href="https://lists.linuxfoundation.org/pipermail/lightning-dev/2023-December/004246.html">[Lightning-dev] The remote anchor of anchor channels is redundant</a>, Peter Todd, lightning-dev mailing list, 2023-12-13 <a href="#fnref:redundant-remote-anchor" class="reversefootnote" role="doc-backlink">&#8617;</a></p> </li> <li id="fn:musig2-benchmark" role="doc-endnote"> <p><a href="https://github.com/jonasnick/musig-benchmark">https://github.com/jonasnick/musig-benchmark</a> <a href="#fnref:musig2-benchmark" class="reversefootnote" role="doc-backlink">&#8617;</a></p> </li> <li id="fn:secp256k1-benchmark" role="doc-endnote"> <p><a href="https://github.com/tarcieri/rust-secp256k1-ecdsa-bench">https://github.com/tarcieri/rust-secp256k1-ecdsa-bench</a> <a href="#fnref:secp256k1-benchmark" class="reversefootnote" role="doc-backlink">&#8617;</a></p> </li> <li id="fn:counter-signing-and-musig" role="doc-endnote"> <p>In the case of interactive joint signature protocols like <a href="https://github.com/bitcoin/bips/blob/master/bip-0327.mediawiki">MuSig2</a>, remember that “counter signing” simply means completing the last step of the signing process. <a href="#fnref:counter-signing-and-musig" class="reversefootnote" role="doc-backlink">&#8617;</a></p> </li> <li id="fn:commitment-tx-size" role="doc-endnote"> <p>Assuming 1 taproot input (musig), 2 taproot outputs, and one ephemeral anchor output. <a href="#fnref:commitment-tx-size" class="reversefootnote" role="doc-backlink">&#8617;</a></p> </li> <li id="fn:ephemeral-spend-tx-size" role="doc-endnote"> <p>Assuming 1 ephemeral anchor spend, 1 taproot input, and 1 taproot output. <a href="#fnref:ephemeral-spend-tx-size" class="reversefootnote" role="doc-backlink">&#8617;</a></p> </li> <li id="fn:phoenix" role="doc-endnote"> <p><a href="https://acinq.co/blog/phoenix-splicing-update">Introducing the new Phoenix: a 3rd generation self-custodial Lightning wallet</a> <a href="#fnref:phoenix" class="reversefootnote" role="doc-backlink">&#8617;</a></p> </li> <li id="fn:gz-bitcoin-dev" role="doc-endnote"> <p><a href="https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2023-December/022216.html">“Let’s say N is 1000vB. AFAIK commitment transactions aren’t usually smaller than this”</a> <a href="#fnref:gz-bitcoin-dev" class="reversefootnote" role="doc-backlink">&#8617;</a></p> </li> </ol> </div> Sun, 31 Dec 2023 00:00:00 +0000 https://petertodd.org/2023/v3-transactions-review https://petertodd.org/2023/v3-transactions-review bitcoin V3 Transactions Are Still Vulnerable To Transaction Pinning <p>V3 Transactions<sup id="fnref:v3-transactions" role="doc-noteref"><a href="#fn:v3-transactions" class="footnote">1</a></sup> is a set of transaction relay policies intended to aim L2/contracting protocols, namely Lightning. The main aim of V3 transactions is to solve Rule 3 transaction pinning<sup id="fnref:rule-3-pinning" role="doc-noteref"><a href="#fn:rule-3-pinning" class="footnote">2</a></sup>, allowing the use of ephemeral anchors<sup id="fnref:ephemeral-anchors" role="doc-noteref"><a href="#fn:ephemeral-anchors" class="footnote">3</a></sup> that do not contain a signature check; anchor outputs that <em>do</em> contain a signature check are not vulnerable to pinning attacks, as only the intended party is able to spend them while unconfirmed.</p> <p>The main way that V3 transactions aims to mitigate transaction pinning is with the following rule:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>A V3 transaction that has an unconfirmed V3 ancestor cannot be larger than 1000 virtual bytes. </code></pre></div></div> <p>Unfortunately, this rule — and thus V3 transactions — is insufficient to substantially mitigate transaction pinning attacks because \(1000\mathrm{vB}\) is still much larger than a typical commitment transaction and ephemeral anchor spend.</p> <p><em>This was <a href="https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2023-December/022211.html">originally published</a> to the Bitcoin Development mailing list, and is published here with corrections <a href="https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2023-December/022216.html">suggested by Gloria Zhao</a>.</em></p> <div class="post-toc"> <h1 class="no_toc" id="contents">Contents</h1> <ol id="markdown-toc"> <li><a href="#the-scenario" id="markdown-toc-the-scenario">The Scenario</a></li> <li><a href="#the-attack" id="markdown-toc-the-attack">The Attack</a> <ol> <li><a href="#multi-party-attack" id="markdown-toc-multi-party-attack">Multi-Party Attack</a></li> </ol> </li> <li><a href="#solutions" id="markdown-toc-solutions">Solutions</a> <ol> <li><a href="#replace-by-feerate" id="markdown-toc-replace-by-feerate">Replace-by-Feerate</a></li> <li><a href="#restrict-v3-children-even-further" id="markdown-toc-restrict-v3-children-even-further">Restrict V3 Children Even Further</a></li> </ol> </li> <li><a href="#footnotes" id="markdown-toc-footnotes">Footnotes</a></li> </ol> </div> <h2 id="the-scenario">The Scenario</h2> <p>To understand why, let’s consider the following scenario: Alice has a Lightning channel with Bob, who has become unresponsive. Alice is using a Lightning protocol where using V3 commitment transactions with a single <code class="language-plaintext highlighter-rouge">OP_TRUE</code> ephemeral anchor of zero value. The commitment transaction must be broadcast in a package, containing both the commitment transaction, and a transaction spending the anchor output; regardless of the fee of the commitment transaction, this is a hard requirement, as the zero-valued output is considered non-standard by V3 rules unless spent in the same package.</p> <p>To pay for the transaction fee of the commitment transaction, \(163\mathrm{vB}\) in size<sup id="fnref:commitment-tx-size" role="doc-noteref"><a href="#fn:commitment-tx-size" class="footnote">4</a></sup>, Alice spends the ephemeral output in transaction, \(152\mathrm{vB}\) in size<sup id="fnref:ephemeral-spend-tx-size" role="doc-noteref"><a href="#fn:ephemeral-spend-tx-size" class="footnote">5</a></sup>, with sufficient feerate \(R_a\) to get the transaction mined in what Alice considers to be a reasonable amount of time. In total, Alice must pay sufficient fees to get \(152\mathrm{vB} + 163\mathrm{vB} = 315\mathrm{vB}\) mined.</p> <h2 id="the-attack">The Attack</h2> <p>Enter Mallory. His goal is to grief Alice by forcing her to spend more money than she intended, at minimum cost. He also maintains well connected nodes, giving him the opportunity to both learn about new transactions, and quickly broadcast transactions to a large number of nodes at once.</p> <p>When Mallory learns about Alice’s commitment+anchor spend package, he signs a replacement anchor spend transaction, \(1000\mathrm{vB}\) in size, with a lower feerate \(R_m\) such that the total fee of Alice’s anchor spend is &lt;= Mallory’s anchor spend (in fact, the total fee can be even less due to BIP-125 RBF Rule #4, but for sake of a simple argument we’ll ignore this). Next, Mallory broadcast’s that package widely, using his well-connected nodes.</p> <p>Due to Rule #3, Alice’s higher feerate transaction package does not replace Mallory’s lower fee rate, higher absolute fee, transaction package. Alice’s options are now:</p> <ol> <li>Wait for Mallory’s low feerate transaction to be mined (mempool expiration does not help here, as Mallory can rebroadcast it indefinitely).</li> <li>Hope her transaction got to a miner, and wait for it to get mined.</li> <li>Replace it with an even higher fee transaction, spending at least as much money as Mallory allocated.</li> </ol> <p>In option #1 and #3, Mallory paid no transaction fees to do the attack.</p> <p>Unfortunately for Alice, feerates are often quite stable. For example, as I write this, the feerate required to get into the next block is \(162\frac{\mathrm{sat}}{\mathrm{vB}}\), while the <em>lowest</em> feerate transaction to get mined in the past 24 hours is approximately \(80\frac{\mathrm{sat}}{\mathrm{vB}}\), a difference of just 2x.</p> <p>Suppose that in this circumstance Alice needs to get her commitment transaction mined within 24 hours. If Mallory used a feerate of 1/2.5th that of Alice, Mallory’s transaction would not have gotten mined in the 24 hour period, with a reasonable safety margin. The ratio of total fee of Mallory’s package compared to Alice’s would have been:</p> \[\frac{163\mathrm{vB} + 1000\mathrm{vB}}{163\mathrm{vB} + 152\mathrm{vB}} * \frac{1}{2.5} \approx 1.48\] <p>Thus to get her transaction mined prior to her deadline, Alice would have had to pay at least a 1.48x higher fee than expected.</p> <h3 id="multi-party-attack">Multi-Party Attack</h3> <p>Mallory can improve the efficiency of his griefing attack by attacking multiple targets at once. Assuming Mallory uses 1 taproot input and 1 taproot output for his own funds, he can spend 21 ephemeral anchors in a single 1000vB transaction.</p> <p>Provided that the RBF Rule #4 feerate delta is negligible relative to current feerates, Mallory can build up the attack against multiple targets by broadcasting replacements with slightly higher feerates as needed to add and remove Alice’s.</p> <p>The cost of the attack to Mallory is estimating fees incorrectly, and using a sufficiently high feerate that his transaction does in fact get mined. In that circumstance, if he’s attacking multiple targets, it is likely that all his transactions would get mined at once. Thus having only a single attack transaction reduces that worst case cost. Since Mallory can adding and remove Alice’s, he can still force multiple Alice’s to spend funds bumping their transactions.</p> <h2 id="solutions">Solutions</h2> <h3 id="replace-by-feerate">Replace-by-Feerate</h3> <p>Obviously, this attack does not work if Rule #3 is removed for small transactions, allowing Alice’s transaction to replace Mallory via replace-by-feerate. In the common situation where mempools are deep, this is arguably miner incentive compatible as other transactions at essentially the same feerate will simply replace the “space” taken up by the griefing transaction.</p> <h3 id="restrict-v3-children-even-further">Restrict V3 Children Even Further</h3> <p>If V3 children are restricted to, say, 200vB, the attack is much less effective as the ratio of Alice vs Mallory size is so small. Of course, this has the disadvantage of making it more difficult in some cases to find sufficient UTXO’s to pay for fees, and increasing the number of UTXO’s needed to fee bump large numbers of transactions.</p> <h2 id="footnotes">Footnotes</h2> <div class="footnotes" role="doc-endnotes"> <ol> <li id="fn:v3-transactions" role="doc-endnote"> <p><a href="https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2022-September/020937.html">“[bitcoin-dev] New transaction policies (nVersion=3) for contracting protocols”</a>, Gloria Zhao, Sep 23 2022 <a href="#fnref:v3-transactions" class="reversefootnote" role="doc-backlink">&#8617;</a></p> </li> <li id="fn:rule-3-pinning" role="doc-endnote"> <p><a href="https://github.com/bitcoin/bips/blob/master/bip-0125.mediawiki#implementation-details">BIP-125</a>, “The replacement transaction pays an absolute fee of at least the sum paid by the original transactions.” <a href="#fnref:rule-3-pinning" class="reversefootnote" role="doc-backlink">&#8617;</a></p> </li> <li id="fn:ephemeral-anchors" role="doc-endnote"> <p><a href="https://github.com/instagibbs/bips/blob/7d79c5692bb745bf158f2d8f8e4979d80ad07e58/bip-ephemeralanchors.mediawiki">BIP Ephemeral Anchors</a>, Gregory Sanders, 2023-01-11 <a href="#fnref:ephemeral-anchors" class="reversefootnote" role="doc-backlink">&#8617;</a></p> </li> <li id="fn:commitment-tx-size" role="doc-endnote"> <p>Assuming 1 taproot input (musig), 2 taproot outputs, and one ephemeral anchor output. <a href="#fnref:commitment-tx-size" class="reversefootnote" role="doc-backlink">&#8617;</a></p> </li> <li id="fn:ephemeral-spend-tx-size" role="doc-endnote"> <p>Assuming 1 ephemeral anchor spend, 1 taproot input, and 1 taproot output. <a href="#fnref:ephemeral-spend-tx-size" class="reversefootnote" role="doc-backlink">&#8617;</a></p> </li> </ol> </div> Wed, 27 Dec 2023 00:00:00 +0000 https://petertodd.org/2023/v3-txs-pinning-vulnerability https://petertodd.org/2023/v3-txs-pinning-vulnerability bitcoin