From: Peter Todd <pete@petertodd•org>
To: Murch <murch@murch•one>,
Bitcoin Protocol Discussion
<bitcoin-dev@lists•linuxfoundation.org>
Subject: Re: [bitcoin-dev] One-Shot Replace-By-Fee-Rate
Date: Sat, 27 Jan 2024 07:19:22 +0000 [thread overview]
Message-ID: <ZbSueoReTvEmm1s9@petertodd.org> (raw)
In-Reply-To: <9a89eca8-61fd-4156-825d-c9b718dc3034@murch.one>
[-- Attachment #1: Type: text/plain, Size: 5030 bytes --]
On Mon, Jan 22, 2024 at 01:12:45PM -0500, Murch via bitcoin-dev wrote:
> Hi Peter,
>
> On 1/18/24 13:23, Peter Todd via bitcoin-dev wrote:
> > Reposting this blog post here for discussion:
> >
> > https://petertodd.org/2024/one-shot-replace-by-fee-rate
>
> I saw your proposal mentioned on Stacker News and read it with interest. In
> response, I described a replacement cycle that can be used to broadcast the
> same five transactions repeatedly:
>
> https://stacker.news/items/393182
>
> The gist is that by using two confirmed inputs and five transactions, you
> can use RBFr to reduce the absolute fee while raising the feerate to top
> block levels, then immediately use the current RBF rules to introduce a
> high-feerate transaction that beats the RBFr transaction but is hampered by
> a low-feerate parent and not attractive for mining, then use RBF to replace
> its low-feerate parent, then use the RBFr transaction again to reduce the
> absolute feerate. Due to the asymmetric replacements, the same transactions
> can replace each other in that order in every cycle. Please refer to the
> linked write-up for details, I’ve included weights, fees, and a transaction
> graph to make my example comprehensible.
>
> Among those five transactions, the only transaction attractive for block
> inclusion would be the small RBFr transaction with a
> bottom-of-the-next-block feerate. Today, if it were mined it would amount to
> fees of around 4000 sats every few blocks to make the entire network relay
> transactions of more than 205,000 vB every few seconds. Given that my
> example is minimal, it should be possible to further increase bandwidth
> cost.
>
> Assuming that I did not make a mistake, i.e. all the replacements are viable
> and my scenario is compatible with your proposal, the described One-Shot
> Replace-By-Fee-Rate proposal would not be safe for deployment on the
> network.
I actually tried this attack out, and it fails at step #4 due to the Rule #6,
PaysMoreThanConflicts, check.
While on stacker.news you stated that:
tx_HS has 5000 vB and pays 21 s/vB, but since it spends an output from a
low-feerate parent, it’s mining score is only 1.95 s/vB.
and
You RBF tx_LL and tx_HS with tx_LM that has 100,000 vB and pays 3.05 s/vB (fee:
305,000 s) by spending the outputs C1 and C2. This is permitted, since only
tx_LL is a direct conflict, so the feerate of tx_HS does not have to be beat
directly.
tx_HS _is_ considered to be a direct conflict, and its raw fee-rate _does_ have
to be beat directly. While ts_HS does spend an unconfirmed output, it appears
that the fee-rate PaysMoreThanConflicts uses to calculate if ts_HS can be
beaten is ts_HS's raw fee-rate. So looks like your understanding was incorrect
on these two points.
FYI here is the actual test script I used to test this attack. You can run it
using Bitcoin v26.0 with the -acceptnonstdtxn -mempoolfullrbf=1 command line
arguments, with python-bitcoinlib v0.12.2 installed.
#!/usr/bin/env python3
import bitcoin
bitcoin.SelectParams('regtest')
import bitcoin.rpc
import sys
from bitcoin.core import *
from bitcoin.core.script import *
from bitcoin.wallet import *
proxy = bitcoin.rpc.Proxy()
my_addr = proxy.getnewaddress().to_scriptPubKey()
coins = proxy.listunspent(1)
print(coins[0:2])
txo1 = coins[0]['outpoint']
txo1_amount = coins[0]['amount']
txo2 = coins[1]['outpoint']
txo2_amount = coins[1]['amount']
print(txo1)
print(txo2)
for i in range(0, 1):
# Step 2
tx_ll = CTransaction(
[CTxIn(txo1)],
[CTxOut(txo1_amount - 100000, my_addr),
CTxOut(0, CScript([OP_RETURN, b'x' * 90000]))])
r = proxy.signrawtransactionwithwallet(tx_ll)
assert(r['complete'])
tx_ll_signed = r['tx']
print('tx_ll = %s' % b2lx(proxy.sendrawtransaction(tx_ll_signed)))
tx_ls = CTransaction(
[CTxIn(COutPoint(tx_ll.GetTxid(), 0))],
[CTxOut(txo1_amount - 100000 - 300, my_addr)])
r = proxy.signrawtransactionwithwallet(tx_ls)
assert(r['complete'])
tx_ls_signed = r['tx']
print('tx_ls = %s' % b2lx(proxy.sendrawtransaction(tx_ls_signed)))
# Step 3
tx_hs = CTransaction(
[CTxIn(COutPoint(tx_ll.GetTxid(), 0)),
CTxIn(txo2)],
[CTxOut((txo1_amount - 100000) + txo2_amount - 4000, my_addr)])
r = proxy.signrawtransactionwithwallet(tx_hs)
assert(r['complete'])
tx_hs_signed = r['tx']
print('tx_hs = %s ' % b2lx(proxy.sendrawtransaction(tx_hs_signed)))
# Step 4
tx_lm = CTransaction(
[CTxIn(txo1),
CTxIn(txo2)],
[CTxOut(txo1_amount + txo2_amount - 300000, my_addr),
CTxOut(0, CScript([OP_RETURN, b'x' * 90000]))])
r = proxy.signrawtransactionwithwallet(tx_lm)
assert(r['complete'])
tx_lm_signed = r['tx']
print('tx_lm = %s' % b2lx(proxy.sendrawtransaction(tx_lm_signed)))
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]
next prev parent reply other threads:[~2024-01-27 7:26 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-01-18 18:23 Peter Todd
2024-01-22 18:12 ` Murch
2024-01-22 22:52 ` Peter Todd
2024-01-24 4:44 ` Peter Todd
2024-01-25 21:25 ` Murch
2024-01-27 7:19 ` Peter Todd [this message]
2024-01-28 17:27 ` Murch
2024-01-31 8:40 ` 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=ZbSueoReTvEmm1s9@petertodd.org \
--to=pete@petertodd$(echo .)org \
--cc=bitcoin-dev@lists$(echo .)linuxfoundation.org \
--cc=murch@murch$(echo .)one \
/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