Relax MIN_STANDARD_TX_NONWITNESS_SIZE to 65 non-witness bytes (
tx fees and policy, mempool) Oct 26, 2022
The PR branch HEAD was e5adc1a284a9292362e75501adc9f71ac6ecdf6e at the time of this review club meeting.
that transactions be at least 82 bytes (non-witness size). This rule was introduced in PR
The original justification given was “A transaction with 1 segwit input and 1 P2WPKH output has
non-witness size of 82 bytes. Transactions smaller than this are not relayed to reduce unnecessary
The true motivation was later documented as
CVE-2017-12842 and PR
#16885; a 64-byte
transaction could be used to trick SPV
While 64-byte transactions are nonstandard in Bitcoin Core, it is still possible to create one
that is consensus-valid. It has been
proposed in PR
#15482 to disallow transactions smaller than 65 bytes in consensus. This proposal has not been accepted.
#26265 relaxes the policy rule from 82-byte
minimum to 65-byte minimum. Another approach could be to simply disallow 64-byte transactions.
The author also
this proposal to the mailing list, adding that a 65-byte minimum would allow
transactions with 1 input, 1 OP_RETURN output to be standard. Optech newsletters
discussed this topic. Questions
Did you review the PR?
Concept ACK, approach ACK, tested ACK, or
Why was the minimum transaction size 82 bytes? Can you describe the attack? Why does setting this
policy help prevent the attack? Does it eliminate the attack vector entirely?
What does “non-witness size” mean, and why do we care about the “non-witness” distinction?
Why might we want to change the minimum transaction size to 65 bytes, apart from the fact that we
no longer need to try to obfuscate the CVE outlined in the notes?
Between disallowing sizes less than 65 bytes and sizes equal to 64 bytes, which approach do you
think is better and why? What are the different implications of both approaches?
What is “OP_RETURN padding”? What do 10, 9, and 41 represent in the calculation of
What does the “tiny transaction” created
here consist of?
What is the tiny transaction’s size serialized
with witness (Hint: see
1 17:00 <glozow> #startmeeting
6 17:00 <glozow> hi instagibbs! thanks for coming
8 17:00 <inauman> hello everyone
11 17:01 <instagibbs> my pleasure
12 17:01 <hernanmarino> Hi !
14 17:01 <pablomartin> hello!
15 17:01 <glozow> have y'all had a chance to review the PR and/or look at the notes?
16 17:02 <LarryRuane> some .. 0.45y
17 17:02 <hernanmarino> yes
18 17:02 <instagibbs> maybe
20 17:03 <stickies-v> y for notes - but I mostly spent time reading about the vulnerability instead of the code :(
21 17:03 <LarryRuane> I rabbit-holed a bit looking at how merkle blocks work
22 17:03 <glozow> LarryRuane: hernanmarino: lightlike: stickies-v: excellent, would any of you like to summarize what this PR is doing?
23 17:03 <b_101> partially
24 17:04 <LarryRuane> I think it's loosening a standardness rule, so that smaller transactions would now be considered standard, all the way down to 65 bytes
25 17:04 <hernanmarino> It reduces the standard transaction size to 65 bytes, from previous value of 82
26 17:05 <LarryRuane> that's a question I had on the notes, actually .. the nodes mention the current min tx size is 85, but is it 82?
27 17:05 <LarryRuane> *notes
28 17:05 <hernanmarino> i believe it s a typo
29 17:05 <LarryRuane> (i'm so used to typing the word "nodes" haha)
30 17:05 <glozow> oh oops, where did I get 85 from 🤔 my bad
31 17:05 <hernanmarino> :)
32 17:05 <stickies-v> interesting that the only non-test code change is changing an int from 82 to 65
33 17:06 <glozow> stickies-v: yes, sometimes the codebase is quite clean eh?
34 17:07 <b_101> stickies: +1
35 17:07 <glozow> Can someone tell us why the minimum used to be 82?
37 17:08 <hernanmarino> Because it mitigated an attack regarding SPV wallets. Also it was believed to be the minimum size of a valid transaction , i.e. transactions with 1 input and 1 output.
38 17:08 <inauman> I think min 82 was because one segwit input and one p2wpkh was around that size
39 17:08 <LarryRuane> I think the answer is given in the comment (that's being removed): "(1 segwit input + 1 P2WPKH output = 82 bytes)"
40 17:08 <LarryRuane> (but i didn't confirm that with murch :) )
41 17:09 <stickies-v> and that was the smallest standard transaction possible at the time
42 17:09 <glozow> hernanmarino has given the real reason
43 17:10 <LarryRuane> so was it not reduced to 65 at that time because doing so would create a clue about the existence of the vulnerability?
44 17:10 <glozow> I don't think anyone believed that was the minimum size of a valid transaction, but yes it would effectively be the smallest standard payment, so this rule was disguised as a little exit early condition
45 17:10 <LarryRuane> hernanmarino: "believed to be ..." -- but was it actually the min size?
46 17:11 <glozow> LarryRuane: I believe so yes. hidden bug fix. was also grouped with a few other standardness rules.
47 17:11 <hernanmarino> LarryRuane: Well, there are now valid transactions smaller than that, but they are not valid spends
48 17:12 <Murch> 82 might stem from the size of a stripped native segwit transaction
49 17:12 <LarryRuane> was part of the disguise also that this was part of a pretty large PR? (17 files changed)
50 17:12 <hernanmarino> i.e OP_RETURNs and other valid use cases
51 17:12 <glozow> hernanmarino: hm, I think you might be using the word "valid" with 2 different meanings
52 17:12 <Murch> The stripped size of a P2WPKH input is 41 B, 31 B for the output, and 10 B for the header = 82 B
53 17:13 <hernanmarino> glozow: yes i was trying to type fast :)
54 17:13 <Murch> With an OP_RETURN output, I think we could get 41+10+10 = 61 B though
55 17:13 <stickies-v> OP_RETURN was made standard in 0.9.0 it seems (released in March 2014), so it seems that smaller standard txs were indeed possible prior to #11423 (May 2018) ?
56 17:14 <LarryRuane> Murch: what does "stripped size" mean? no witness?
57 17:14 <instagibbs> stickies-v, ah good historical digging
60 17:14 <glozow> stickies-v: good dig. yes, hence standard *payment* heh
61 17:15 <Murch> Oh, that's significantly before segwit, never mind.
62 17:15 <glozow> What does “non-witness size” mean, and why do we care about the “non-witness” distinction?
64 17:16 <hernanmarino> glozow: It means the size of transactions not including witnesses / signatures. But I'm not sure about your second question
65 17:16 <LarryRuane> glozow: is it because BIP31 (bloom filter) is always only txid, not wtxid?
66 17:16 <lightlike> given that the attack was costly ($1M) according to https://github.com/advisories/GHSA-v55p-4chq-6grj and that it seems unlikely that people would use SPV clients for payments that are that large, was it really necessary to fix this covertly?
67 17:17 <LarryRuane> sorry I think that's the wrong bip number
68 17:17 <LarryRuane> bip 37
69 17:18 <glozow> lightlike: idk!
70 17:18 <stickies-v> we care about the non-witness distinction because (as part of the segwit upgrade) witness data is excluded from calculation of the merkle root
72 17:18 <instagibbs> lightlike, what would happen if your intuition was wrong?
73 17:18 <LarryRuane> lightlike: good q, I was wondering that exact thing too
74 17:19 <LarryRuane> Murch: thank you!
76 17:19 <stickies-v> and since the attack requires the malicious transaction to be 64 bytes in the merkle root construction (so it looks like inner nodes), we need to exclude witness data from it
77 17:20 <hernanmarino> Murch: cool ! Thanks
78 17:20 <LarryRuane> stickies-v: right because the merkle block stuff is based on txid (stripped tx), not wtxid
79 17:21 <glozow> stickies-v: ye I think that's right!
80 17:21 <LarryRuane> I'm wondering, is BIP 37 still used today? I know most node configurations don't enable bloom filters. Can SPV clients use the newer block filters?
81 17:22 <glozow> er, I don't think we're talking about bloom filters here. just merkle proofs. SPV clients might use both, but they're different things
82 17:22 <hernanmarino> stickies-v: LarryRuane: thanks, that seems like the reason
83 17:22 <LarryRuane> oh ok, i mistakenly thought merkle proofs were only used in conjunction with bloom filters (bip37)
84 17:23 <glozow> Why does setting this policy help prevent the attack? Does it eliminate the attack vector entirely?
85 17:25 <LarryRuane> because inner merkle tree nodes can only be exactly 64 bytes? so requiring tx size to never be 64 prevents a tx from being interpreted as an inner node? I think it does eliminate the attack entirely (but not sure)
86 17:25 <stickies-v> LarryRuane: good point, I think merkle proofs are not inherent to bloom filters but I don't know where Bitcoin Core would provide merkle proofs elsewhere, since indeed I think they're not used with compact block filters
87 17:26 <glozow> LarryRuane: correct for the first part. It does not eliminate the attack entirely.
88 17:26 <LarryRuane> stickies-v: yes if you search the code base for `CMerkleBlock`, you'll see it's only used with `IsMsgFilteredBlk`
89 17:26 <inauman> Because the nodes in merkle tree are used in pairs (32+32) and a transactions can also be of 64 bytes, an attacker can masquerade a node with a transaction..by increasing it to 65, this attack can be eliminated
90 17:27 <hernanmarino> It mitigates this risk beacuse the attack requires exactly 64 byte transactions. Regarding the last question I understand it eliminates the attack completely, but I have a hunch telling me this is not the right answer : )
91 17:27 <andrewtoth_> it prevents the attacking tx from being relayed to miners, but it doesn't prevent it from being mined so it can still be included in a block
92 17:27 <stickies-v> this is only about standardness/relay right, so a miner could still pull this attack off
93 17:27 <stickies-v> or direct submission to miners, but yeah like andrewtoth_ said
94 17:27 <glozow> andrewtoth_: stickies-v: bingo
95 17:27 <lightlike> it's just policy, so if you manage to get the tx to a favourable miners somehow, you can still be successful
96 17:27 <hernanmarino> stickies-v: they can, I think
97 17:28 <LarryRuane> stickies-v: andrewtoth_: +1
98 17:28 <glozow> yes, the attack is possible if it's mined in a block. relaying through Bitcoin Core nodes is not the only way to achieve that.
99 17:28 <hernanmarino> glozow: Ohh, it was so obvious ! :)
100 17:28 <glozow> Why might we want to change the minimum transaction size to 65 bytes, apart from the fact that it's unnecessary to try to obfuscate the CVE outlined in the notes?
102 17:29 <LarryRuane> glozow: I'm not sure, but is it because there are legit transactions with sizes between 65 and 82?
103 17:29 <hernanmarino> Because there are use cases of transactions of this size, and lower than 82
104 17:30 <andrewtoth_> I believe this is part of a proposal to get OP_TRUE payments standardized, which would allow anyone to CPFP the tx. But first the size of such an output must be allowed to be relayed?
105 17:30 <andrewtoth_> *size of such a tx including that output
106 17:31 <lightlike> according to Peter Todd on the ML, one legit use case is to burn dust in order to reduce the UTXO set. Is there another one?
107 17:31 <LarryRuane> higher level question prompted by glozow's comment (about Bitcoin Core): for something like this, would we expect the maintainers of other bitcoin clients to make the analogous changes? I would imagine they follow the ML?
108 17:32 <glozow> andrewtoth_: yes, OP_TRUE for anyone to CPFP is a potential use
109 17:32 <_aj_> if you're going to burn dust, you could supply an ANYONECANPAY|NONE signature, and then once you've got two dust outputs to combine, you're tx is already >72 bytes stripped just to reference the input utxos
110 17:33 <_aj_> (>90 bytes counting version, locktime, counts, and output amount too, whatever)
111 17:34 <LarryRuane> _aj_: just so I understand, you're saying that burning dust isn't a reason to allow < 82 byte transactions?
112 17:35 <glozow> oh wait is OP_TRUE no longer reasoning? "I went down the rabbit hole with naked OP_TRUE, forgetting that wsh(OP_TRUE) is standard for making and spending... will remove"
113 17:36 <_aj_> LarryRuane: if you've got a lot of dust to burn, then better to combine it all into a single tx (saving 10B tx overhead and 10B output overhead)
114 17:36 <LarryRuane> _aj_: +1 thanks
115 17:36 <andrewtoth_> glozow: interesting...link?
116 17:37 <instagibbs> glozow, that was for test environment, not use
119 17:37 <instagibbs> naked op_true spends arent standard, I was trying to mine those outputs, ended up not helping make an actual test
120 17:37 <instagibbs> I forgot that stripped size is all that matters while writing
121 17:38 <_aj_> the only use i came up with that felt like it made sense was if you wanted to CPFP by burning an entire output to fees; which is plausible but seems kind of rare (better than forcing you to add another utxo as input just so you add a change output, and then not even be able to claim all your extra input back as change)
122 17:40 <glozow> _aj_: seems plausible.
123 17:40 <instagibbs> _aj_, I agree that;s the use case that drove this PR, after talking to tbast, where he wanted exactly this
124 17:40 <glozow> Between disallowing sizes less than 65 bytes and sizes equal to 64 bytes, which approach do you think is better and why? What are the different implications of both approaches?
126 17:42 <glozow> so one question we might ask is "is there a use case for a transaction that's 63 bytes?"
127 17:44 <LarryRuane> or even if we can't think of one, maybe one will arise in the future?
128 17:45 <theStack> not sure if this would count as "legit use case", but what about txs with 1 segwit input and 1 null data (OP_RETURN) output? didn't those have to have a minimum size of 20 bytes nulldata to pass the check?
129 17:46 <amovfx_> There is one mentioned in the comments that a psbt can be 63B
130 17:46 <glozow> theStack: yeah I think that's 63B
131 17:47 <instagibbs> should be 62?
132 17:47 — glozow waves hand
133 17:47 <_aj_> instagibbs: an empty scriptPubKey/scriptSig gives 60B minimum, yes/no?
134 17:48 <instagibbs> let me read my excellent tests /joke
135 17:48 <instagibbs> yes, 60, sorry, so 61 is minimum unspendable(standard) output
138 17:50 <Murch> stripped native segwit input is 41 B + 10 B header + 8 B value, 1 B SPK length + 1 B OP_TRUE/OP_RETURN = 61 B
139 17:51 <Murch> _aj_: Can SPK be completely empty?
140 17:51 <instagibbs> Murch, yes
141 17:51 <Murch> I don't think that would evaluate to true?
142 17:51 <instagibbs> scriptsig of OP_TRUE
143 17:51 <_aj_> Murch: you'd supply "1" as scriptSig to spend
144 17:52 <Murch> okay, then I think it would be 60 B?
145 17:52 <glozow> ah wow. what would we call this output? P2MT?
146 17:52 <instagibbs> its non-standard, I think we'd call this "bare script"
147 17:52 <glozow> why isn't it standard?
148 17:53 <instagibbs> if an output scriptpubkey doesn't match a known template, it's considered non-standard. It was never given one. very much into the rabbit hold now...
149 17:53 <Murch> I asked the Pieterpedia, he agrees that SPK can be empty and 60 B is minimum tx size ^^
150 17:54 <Murch> The Rabbithold sounds like the fortress of the Taproot proponents.
152 17:55 <hernanmarino> haha
154 17:57 <glozow> Next question. What is the tiny transaction’s size serialized with witness?
155 17:58 <glozow> theStack: the minimum 20 bytes nulldata was in order to meet the previous minimum size of 82. so they're both decreased.
156 17:58 <glozow> (assuming I interpreted your question correctly)
157 17:59 <Murch> Since this transaction doesn't have any witness, the same size
158 18:00 <glozow> witness 0 is a OP_TRUE?
159 18:00 <glozow> Seems we have reached the end of the hour
160 18:00 <glozow> #endmeeting
161 18:01 <sipa> An empty output would be spent with a ␝scriptSig␏ of OP_TRUE.
162 18:01 <Murch> Putting the OP_TRUE into the witness would be bigger than just putting it into the scriptSig
163 18:01 <sipa> Not a witness. This isn't a segwit output.
164 18:01 <andrewtoth_> thanks glozow!
165 18:01 <Murch> Also you'd require a witness program in the output then
166 18:01 <theStack> glozow: yeah, i was trying to find out whether users could now relay 1-segwit-input 1-nulldata-outputs with smaller nulldata payload than before (though i'm not sure why anyone would need that)