(copied from a gist)
In transaction relay we are trying to avoid “free relay” which is roughly defined as:
(total_sats_in_mempool + total_sats_mined) / total_bytes_relayed < minrelay
Did the sum total of bytes we’ve been accepting to our mempool and propagating across
the network pay for the “bandwidth” to do so, dubbed
minrelay which is a static value
at 1 sat/vbyte?
Therefore, if we for example remove bip125 rule#3 in a naive fashion, this can be violated simply by filling the bottom of the mempool with 1 sat/vbyte junk, then double-spending all of with minimum sized transactions at slightly higher rates, e.g., 2 sat/vbyte.
This can be problematic in adversarial and time-sensitive scenarios such as Lightning Network tranasctions, both “commitment” and “HTLC” transactions which each have timelines to be mined safely. The counter-party can intentionally slow down mining of these transactions, and not pay for the privelage to do so, by putting these rule#3 pins at the bottom of the mempool that can become evicted.
Instead of working around rule#3 directly, we can instead allow wallets to add “prior restraint” to features of the transaction that may mitigate these issues.
The “V3” transaction type is proposed specifically as this kind of policy. If nVersion==3, this means the topology for this transaction in the mempool is highly restricted. The tx may have up to one ancestor and one descendant total, which implies a strict upper-bound parent-child relationship of size two. The child transaction is additionally restricted to 1 kvB. This is deemed large enough that a child can bring reasonable amounts of funds to do package RBF, but two orders of magnitude smaller than the upper-bound possible (101kvB) in packages. This reduces the pin effect by roughly 250-500 times, making pins hopefully impractical.
Very importantly, the parent transaction size is unrestricted.
This transaction type works well specifically for things such as commitment transactions, in which utxos are locked into smart contracts between only the authorized spending parties, and no ANYONECANPAY like behavior is allowed. This precludes its usage in today’s LN HTLC transactions, without a significant rewrite of how they work to include (Ephemeral?) anchors, and the resulting additional vbytes in the commone non-pinning case.
Ephemeral anchors additionally allow:
- 0-value anchors
- “sibling eviction”, which allows other outputs of transactions to not require “1 CSV” hacks that are common in things such as LN BOLTs to avoid package limit pinning. This saves bytes, and allows these outputs to be directly spent immdaitely as fees. But relies on “V3” for its topological restrictions to ensure (2).
See more discussion on Ephemeral anchors and its relation to SIGHASH_GROUP fore more background: https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2023-January/021334.html
With the cluster mempool, we have the ability to efficiently order the entire mempool, both in eviction and the mining. This can be efficiently updated incrementally for each transaction added and removed from the mempool. Since the mempool is completely ordered for mining at each step, we can efficiently simulate mining N blocks, and give the necessary “mining scores” required for each chunk to be included in that range of the mempool.
Once you have a mapping from chunk mining score to “top N blocks”, the system is fairly straight forward.
Users commit to the “N” in their transaction input(?). The proposed transaction is relayed, a node simulates adding the transaction to the cluster, runs linearization algorithm, has the resulting mining score, checks that the “N” computed is higher than any committed to in the transaction. If so, it’s let into the mempool. If not, it’s simply rejected.
Subsequent descendants to that tranasaction must also conform to the most restrictive ancestor’s “top N block” chunk restriction, or they will be rejected. Therefore both “ancestor junk” and “descendant junk” are prevented.
The downside to this method is if the pinner somehow gets lucky when the mempool is empty, adds their top-of-mempool tx that is “too large”, the mempool fills, then the initial transaction is now a pin. f the attacker can predict when a mempool will naturally fill, they could perhaps time this, but they risk getting mined, which defeats the purpose of the attack. I think in practice this is not a realistic concern, but requires further consideration.
Prior restraint via “V3” like means don’t have the same issue, but the “V3” topological restrictions are also more weakly motivated from a wallet usage perspective, so it’s something that has to be weighed.
Don’t forget that lack of topological restrictions means batch CPFP is back on the table.
“V3” by itself may be subsumed by priority transactions, but in conjunction with Ephemeral Anchors still can make a lot of sense for:
- sibling eviction usage when the base transaction cannot be directly conflicted
- and when signers are committing to multiple “state” outputs and don’t want to “sap” value from the smart contract itself (mixing funds and fees).
This method seems to naturally slot into SIGHASH_GROUP anti-pinning. A transaction input commits to the “top N blocks” policy, and the rest of the constructed transaction is otherwise unrestricted.
Alternatively, restricting based on “max size of cluster” means you’re putting prior restraint on yourself with respect to BYOF, batched bumps, etc. Similar to V3 constraints.
Thought experiment: Are “V3” and Epehemeral anchors use-cases entirely subsumed by SIGHASH_GROUP + priority?