Peter Todd
https://petertodd.org/
Tue, 04 Nov 2025 11:29:18 +0000Tue, 04 Nov 2025 11:29:18 +0000Jekyll v3.9.0OpenTimestamps 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 <real pubkey> <fake pubkey> 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">↩</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">↩</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">↩</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">↩</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">↩</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-oceanbitcoinopentimestampsknotsoceanHow 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&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 &= 1397 \\
1448113 - 100420 - 1347800 &= -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>— 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 & 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">↩</a> <a href="#fnref:kogman-post:1" class="reversefootnote" role="doc-backlink">↩<sup>2</sup></a> <a href="#fnref:kogman-post:2" class="reversefootnote" role="doc-backlink">↩<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">↩</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">↩</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">↩</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">↩</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">↩</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">↩</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">↩</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">↩</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">↩</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">↩</a></p>
</li>
</ol>
</div>
Thu, 31 Jul 2025 00:00:00 +0000
https://petertodd.org/2025/coinjoin-comparison
https://petertodd.org/2025/coinjoin-comparisonbitcoincoinjoinprivacyFake 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-lightningbitcoinlightningrgbclient-side-validationtaproot-assetsKeeping 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 &= \epsilon \sigma T^4 \\
M &= 5.67 \times 10^{-8} \frac{W}{m^2 K^4} (33K)^4 \\
M &= 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 &= A M = A \epsilon \sigma T^4 \\
T &= \left( \frac{P + A_E E}{A \epsilon \sigma} \right)^{\frac{1}{4}} \\
&= \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}} \\
&= 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 &= 2 \epsilon \sigma T^4 \\
T &= \left( \frac{E}{2 \epsilon \sigma} \right)^{\frac{1}{4}} \\
&= \left( \frac{1380\frac{W}{m^2}}{2 \times 5.67 \times 10^{-8} \frac{W}{m^2 K^4}} \right)^{\frac{1}{4}} \\
&= 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 &= 2M \\
\cos(\theta) E &= 2 \epsilon \sigma T^4 \\
T &= \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 &= 2 \sigma T^4 \\
T &= \left( \frac{E}{2 \epsilon \sigma} \right)^{\frac{1}{4}} \\
&= \left( \frac{110\frac{kW}{m^2}}{2 \times 5.67 \times 10^{-8} \frac{W}{m^2 K^4}} \right)^{\frac{1}{4}} \\
&= 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 &= tr \\
P(N = 0) &= \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">↩</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">↩</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&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">↩</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-spacebitcoinspacephysicsSoft-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">↩</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">↩</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">↩</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">↩</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">↩</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">↩</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">↩</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">↩</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">↩</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">↩</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">↩</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">↩</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">↩</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">↩</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">↩</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">↩</a> <a href="#fnref:altruistic-rebroadcasting:1" class="reversefootnote" role="doc-backlink">↩<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">↩</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">↩</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">↩</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">↩</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">↩</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">↩</a></p>
</li>
<li id="fn:flood-and-loot" role="doc-endnote">
<p><a href="https://arxiv.org/abs/2006.08513">“Flood & 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">↩</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">↩</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-reviewbitcoinlayer2convanantsOver 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-ratebitcoinrbfrbfrOne-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">↩</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">↩</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 < 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">↩</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">↩</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">↩</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">↩</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">↩</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-ratebitcoinrbfpinningV3 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><local_funding_pubkey/remote_funding_pubkey> 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">↩</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">↩</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">↩</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">↩</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">↩</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">↩</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">↩</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">↩</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-reviewbitcoinV3 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 <= 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">↩</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">↩</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">↩</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">↩</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">↩</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-vulnerabilitybitcoin