Subject: [bitcoin-dev] Using Full-RBF to fix BIP-125 Rule #3 Pinning with nLockTime

From: Peter Todd <[email-masked]>
Date: Mon, 7 Nov 2022 16:17:50 -0500

On Mon, Nov 07, 2022 at 03:17:29PM -0500, Peter Todd via bitcoin-dev wrote:
> tl;dr: We can remove the problem of Rule #5 pinning by ensuring that all
> transactions in the mempool are always replaceable.

With Rule #5 solved, let's look at the other pinning attack on multi-party
transactions: BIP-125 Rule #3

tl;dr: In conjunction with full-RBF, nLockTime'd, pre-signed, transactions can
ensure that one party is not forced to pay for all the cost of a rule #3
replacement.

# What is the problem?

When a transaction contains inputs from multiple parties, each party can lock
up funds from the other party by spending their input with a transaction that
is difficult/expensive to replace. Obviously, the clearest example of "difficult to
replace" is a non-BIP-125 (Opt-in-RBF) transaction. But here, we'll assume that
full-rbf is implemented and all transactions are replaceable.

BIP-125 Rule #3 states that:

    The replacement transaction pays an absolute fee of at least the sum paid
    by the original transactions.

The attack is that the malicious party, who we'll call Mallory, broadcasts a
transaction spending their input(s) with a low fee rate transaction that's
potentially quite large, during a time of high mempool demand. Due to the low
fee rate this transaction will take a significant amount of time to mine. The
other parties to the transaction - who we'll collectively call Alice - are now
unable to spend their inputs unless they broadcast a transaction "paying for"
Mallory's.

This attack works because Mallory doesn't expect the conflicting tx to actually
get mined: he assumes it'll either expire, or Alice will get frustrated and
have to double spend it. By simple tying up money, Mallory has caused Alice to
actually lose money.

# Fixing the problem with nLockTime

Conversely, in the case of an honest multi-party transaction, whose parties
we'll call Alice and Bob, the parties genuinely intend for one of two outcomes:

1) The multi-party transaction to get mined within N blocks.
2) The transaction to be cancelled (most likely by spending one of the inputs).

We can ensure with high probability that the transaction can be cancelled/mined
at some point after N blocks by pre-signing a transaction, with nLockTime set
sufficiently far into the future, spending one or more inputs of the
transaction with a sufficiently high fee that it would replace transaction(s)
attempting to exploit Rule #3 pinning (note how the package limits in Bitcoin
Core help here).

There's a few different ways to implement this, and exactly which one makes
sense will depend on the specifics of the multi-party protocol. But the general
approach is to defeat the attack by ensuring that Mallory will have to pay the
cost of getting the multi-party transaction unstuck, at some point in the
future.

For example, in a two party transaction where there's a clearly more reputable
party (Alice), and an untrusted party (Mallory), Alice could simply require
Mallory to provide a nLockTime'd transaction spending only his input to fees,
multiple days into the future. In the unlikely event that Mallory holds up the
protocol, he will be severely punished. Meanwhile, Alice can always cancel at
no cost.

In a many party transaction where both parties are equally (un)trustworthy the
protocol could simply have both parties sign a series of transactions,
nLockTimed at decreasingly far into a future, paying a decreasingly amount of
fees. If either party holds up the transaction intentionally, they'll both pay
a high cost. But again, at some point Mallory will have paid the full price for
his attack. This approach also has the beneficial side effect of implementing
fee discovery with rbf. This approach is easier as the number of parties
increases, eg the Wasabi/Joinmarket transactions with hundreds of inputs and
outputs: they collectively already have to pay a significant fee to get the
transaction mined, making the extra poential cost needed to defeat pinning
minimal.

# Coordinator Spent Bonds with Package Relay/Replacement

For schemes with a central semi-trusted coordinator, such as Wasabi coinjoins,
with package relay/replacement we can use a two party punishment transaction
consisting of:

    tx1 - spends Mallory's input to a txout spendable by:
           IF
               <coordinator> CheckSig
           Else
               <delay> CheckSequenceVerify
               <mallory> CheckSig
           EndIf

    tx2 - spends tx1 output to as much fees as needed

Whether or not Mallory cheated with a double-spend is provable to third
parties; the second transaction ensures that Mallory can't simply release tx1
on their own to frame the coordinator. The use of CheckSequenceVerify ensures
that if mallory did try to frame the coordinator, they don't have to do
anything to return the funds to Mallory.

-- 
https://petertodd.org 'peter'[:-1]@petertodd.org