public inbox for bitcoindev@googlegroups.com
 help / color / mirror / Atom feed
From: Peter Todd <pete@petertodd•org>
To: Bitcoin Protocol Discussion <bitcoin-dev@lists•linuxfoundation.org>
Subject: [bitcoin-dev] Using Full-RBF to fix BIP-125 Rule #3 Pinning with nLockTime
Date: Mon, 7 Nov 2022 16:17:50 -0500	[thread overview]
Message-ID: <Y2l1/qXHxyctU9ir@petertodd.org> (raw)
In-Reply-To: <Y2ln2fJ+8+Q0qS0E@petertodd.org>

[-- Attachment #1: Type: text/plain, Size: 5001 bytes --]

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

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

  reply	other threads:[~2022-11-07 21:18 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-11-07 20:17 [bitcoin-dev] Removing BIP-125 Rule #5 Pinning with the Always-Replaceable Invariant Peter Todd
2022-11-07 21:17 ` Peter Todd [this message]
2022-11-07 22:55   ` [bitcoin-dev] Using Full-RBF to fix BIP-125 Rule #3 Pinning with nLockTime Antoine Riard
2022-11-09 12:41     ` Peter Todd
2022-11-11  3:00   ` David A. Harding
2022-11-07 21:21 ` [bitcoin-dev] Removing BIP-125 Rule #5 Pinning with the Always-Replaceable Invariant Suhas Daftuar
2022-11-07 21:27   ` Peter Todd

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=Y2l1/qXHxyctU9ir@petertodd.org \
    --to=pete@petertodd$(echo .)org \
    --cc=bitcoin-dev@lists$(echo .)linuxfoundation.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox