Skip to content

Commit 6c7da07

Browse files
author
MarcoFalke
committed
Merge #17108: test: fix "tx-size-small" errors after default address change
32d665c test: fix "tx-size-small" errors after default address change (Sebastian Falbesoner) Pull request description: Addresses #17043, affects RBF and BIP68 functional tests. The "tx-size-small" policy rule rejects transactions with a non-witness size of smaller than 82 bytes (see `src/validation.cpp:MemPoolAccept::PreChecks(...)`), which corresponds to a transaction with 1 segwit input and 1 P2WPKH output. Through the default address change, the created test transactions have segwit inputs now and sending to short scriptPubKeys might violate this rule. By bumping the dummy scriptPubKey size to 22 bytes (= the size of a P2WPKH scriptPubKey), on all occurences the problem is solved. The dummy scriptPubKey has the format: ```21 <21-byte-long string of 'a' or 1s>``` ACKs for top commit: instagibbs: reACK bitcoin/bitcoin@32d665c just s/Bytes/bytes/ MarcoFalke: ACK 32d665c Tree-SHA512: 80e0386ff3c3f462901ba5c1e5ef2cbf095d9c0a40c8c3cfeacd4a3ab676afe744aa95b9eed77b4b3eec88bed930b33aa718117ed0977f6374e858a2f3bd5c57
2 parents 556820e + 32d665c commit 6c7da07

File tree

3 files changed

+59
-36
lines changed

3 files changed

+59
-36
lines changed

test/functional/feature_bip68_sequence.py

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88

99
from test_framework.blocktools import create_block, create_coinbase, add_witness_commitment
1010
from test_framework.messages import COIN, COutPoint, CTransaction, CTxIn, CTxOut, FromHex, ToHex
11-
from test_framework.script import CScript
1211
from test_framework.test_framework import BitcoinTestFramework
1312
from test_framework.util import (
1413
assert_equal,
@@ -17,6 +16,7 @@
1716
satoshi_round,
1817
softfork_active,
1918
)
19+
from test_framework.script_util import DUMMY_P2WPKH_SCRIPT
2020

2121
SEQUENCE_LOCKTIME_DISABLE_FLAG = (1<<31)
2222
SEQUENCE_LOCKTIME_TYPE_FLAG = (1<<22) # this means use time (0 means height)
@@ -29,10 +29,9 @@
2929
class BIP68Test(BitcoinTestFramework):
3030
def set_test_params(self):
3131
self.num_nodes = 2
32-
# TODO remove output type argument and fix resulting "tx-size-small" errors
3332
self.extra_args = [
34-
["-acceptnonstdtxn=1", "-addresstype=p2sh-segwit"],
35-
["-acceptnonstdtxn=0", "-addresstype=p2sh-segwit"],
33+
["-acceptnonstdtxn=1"],
34+
["-acceptnonstdtxn=0"],
3635
]
3736

3837
def skip_test_if_missing_module(self):
@@ -85,7 +84,7 @@ def test_disable_flag(self):
8584
# input to mature.
8685
sequence_value = SEQUENCE_LOCKTIME_DISABLE_FLAG | 1
8786
tx1.vin = [CTxIn(COutPoint(int(utxo["txid"], 16), utxo["vout"]), nSequence=sequence_value)]
88-
tx1.vout = [CTxOut(value, CScript([b'a']))]
87+
tx1.vout = [CTxOut(value, DUMMY_P2WPKH_SCRIPT)]
8988

9089
tx1_signed = self.nodes[0].signrawtransactionwithwallet(ToHex(tx1))["hex"]
9190
tx1_id = self.nodes[0].sendrawtransaction(tx1_signed)
@@ -97,7 +96,7 @@ def test_disable_flag(self):
9796
tx2.nVersion = 2
9897
sequence_value = sequence_value & 0x7fffffff
9998
tx2.vin = [CTxIn(COutPoint(tx1_id, 0), nSequence=sequence_value)]
100-
tx2.vout = [CTxOut(int(value - self.relayfee * COIN), CScript([b'a' * 35]))]
99+
tx2.vout = [CTxOut(int(value - self.relayfee * COIN), DUMMY_P2WPKH_SCRIPT)]
101100
tx2.rehash()
102101

103102
assert_raises_rpc_error(-26, NOT_FINAL_ERROR, self.nodes[0].sendrawtransaction, ToHex(tx2))
@@ -192,7 +191,7 @@ def test_sequence_lock_confirmed_inputs(self):
192191
value += utxos[j]["amount"]*COIN
193192
# Overestimate the size of the tx - signatures should be less than 120 bytes, and leave 50 for the output
194193
tx_size = len(ToHex(tx))//2 + 120*num_inputs + 50
195-
tx.vout.append(CTxOut(int(value-self.relayfee*tx_size*COIN/1000), CScript([b'a'])))
194+
tx.vout.append(CTxOut(int(value-self.relayfee*tx_size*COIN/1000), DUMMY_P2WPKH_SCRIPT))
196195
rawtx = self.nodes[0].signrawtransactionwithwallet(ToHex(tx))["hex"]
197196

198197
if (using_sequence_locks and not should_pass):
@@ -221,7 +220,7 @@ def test_sequence_lock_unconfirmed_inputs(self):
221220
tx2 = CTransaction()
222221
tx2.nVersion = 2
223222
tx2.vin = [CTxIn(COutPoint(tx1.sha256, 0), nSequence=0)]
224-
tx2.vout = [CTxOut(int(tx1.vout[0].nValue - self.relayfee*COIN), CScript([b'a']))]
223+
tx2.vout = [CTxOut(int(tx1.vout[0].nValue - self.relayfee*COIN), DUMMY_P2WPKH_SCRIPT)]
225224
tx2_raw = self.nodes[0].signrawtransactionwithwallet(ToHex(tx2))["hex"]
226225
tx2 = FromHex(tx2, tx2_raw)
227226
tx2.rehash()
@@ -239,7 +238,7 @@ def test_nonzero_locks(orig_tx, node, relayfee, use_height_lock):
239238
tx = CTransaction()
240239
tx.nVersion = 2
241240
tx.vin = [CTxIn(COutPoint(orig_tx.sha256, 0), nSequence=sequence_value)]
242-
tx.vout = [CTxOut(int(orig_tx.vout[0].nValue - relayfee * COIN), CScript([b'a' * 35]))]
241+
tx.vout = [CTxOut(int(orig_tx.vout[0].nValue - relayfee * COIN), DUMMY_P2WPKH_SCRIPT)]
243242
tx.rehash()
244243

245244
if (orig_tx.hash in node.getrawmempool()):
@@ -352,7 +351,7 @@ def test_bip68_not_consensus(self):
352351
tx2 = CTransaction()
353352
tx2.nVersion = 1
354353
tx2.vin = [CTxIn(COutPoint(tx1.sha256, 0), nSequence=0)]
355-
tx2.vout = [CTxOut(int(tx1.vout[0].nValue - self.relayfee*COIN), CScript([b'a']))]
354+
tx2.vout = [CTxOut(int(tx1.vout[0].nValue - self.relayfee*COIN), DUMMY_P2WPKH_SCRIPT)]
356355

357356
# sign tx2
358357
tx2_raw = self.nodes[0].signrawtransactionwithwallet(ToHex(tx2))["hex"]
@@ -367,7 +366,7 @@ def test_bip68_not_consensus(self):
367366
tx3 = CTransaction()
368367
tx3.nVersion = 2
369368
tx3.vin = [CTxIn(COutPoint(tx2.sha256, 0), nSequence=sequence_value)]
370-
tx3.vout = [CTxOut(int(tx2.vout[0].nValue - self.relayfee * COIN), CScript([b'a' * 35]))]
369+
tx3.vout = [CTxOut(int(tx2.vout[0].nValue - self.relayfee * COIN), DUMMY_P2WPKH_SCRIPT)]
371370
tx3.rehash()
372371

373372
assert_raises_rpc_error(-26, NOT_FINAL_ERROR, self.nodes[0].sendrawtransaction, ToHex(tx3))

test/functional/feature_rbf.py

Lines changed: 24 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,14 @@
1010
from test_framework.script import CScript, OP_DROP
1111
from test_framework.test_framework import BitcoinTestFramework
1212
from test_framework.util import assert_equal, assert_raises_rpc_error, satoshi_round
13+
from test_framework.script_util import DUMMY_P2WPKH_SCRIPT
1314

1415
MAX_REPLACEMENT_LIMIT = 100
1516

1617
def txToHex(tx):
1718
return tx.serialize().hex()
1819

19-
def make_utxo(node, amount, confirmed=True, scriptPubKey=CScript([1])):
20+
def make_utxo(node, amount, confirmed=True, scriptPubKey=DUMMY_P2WPKH_SCRIPT):
2021
"""Create a txout with a given amount and scriptPubKey
2122
2223
Mines coins as needed.
@@ -65,7 +66,6 @@ def make_utxo(node, amount, confirmed=True, scriptPubKey=CScript([1])):
6566
class ReplaceByFeeTest(BitcoinTestFramework):
6667
def set_test_params(self):
6768
self.num_nodes = 1
68-
# TODO remove output type argument and fix resulting "tx-size-small" errors
6969
self.extra_args = [
7070
[
7171
"-acceptnonstdtxn=1",
@@ -74,7 +74,6 @@ def set_test_params(self):
7474
"-limitancestorsize=101",
7575
"-limitdescendantcount=200",
7676
"-limitdescendantsize=101",
77-
"-addresstype=p2sh-segwit",
7877
],
7978
]
8079

@@ -133,7 +132,7 @@ def test_simple_doublespend(self):
133132

134133
tx1a = CTransaction()
135134
tx1a.vin = [CTxIn(tx0_outpoint, nSequence=0)]
136-
tx1a.vout = [CTxOut(1 * COIN, CScript([b'a' * 35]))]
135+
tx1a.vout = [CTxOut(1 * COIN, DUMMY_P2WPKH_SCRIPT)]
137136
tx1a_hex = txToHex(tx1a)
138137
tx1a_txid = self.nodes[0].sendrawtransaction(tx1a_hex, 0)
139138

@@ -142,7 +141,7 @@ def test_simple_doublespend(self):
142141
# Should fail because we haven't changed the fee
143142
tx1b = CTransaction()
144143
tx1b.vin = [CTxIn(tx0_outpoint, nSequence=0)]
145-
tx1b.vout = [CTxOut(1 * COIN, CScript([b'b' * 35]))]
144+
tx1b.vout = [CTxOut(1 * COIN, DUMMY_P2WPKH_SCRIPT + b'a')]
146145
tx1b_hex = txToHex(tx1b)
147146

148147
# This will raise an exception due to insufficient fee
@@ -151,7 +150,7 @@ def test_simple_doublespend(self):
151150
# Extra 0.1 BTC fee
152151
tx1b = CTransaction()
153152
tx1b.vin = [CTxIn(tx0_outpoint, nSequence=0)]
154-
tx1b.vout = [CTxOut(int(0.9 * COIN), CScript([b'b' * 35]))]
153+
tx1b.vout = [CTxOut(int(0.9 * COIN), DUMMY_P2WPKH_SCRIPT)]
155154
tx1b_hex = txToHex(tx1b)
156155
# Works when enabled
157156
tx1b_txid = self.nodes[0].sendrawtransaction(tx1b_hex, 0)
@@ -186,7 +185,7 @@ def test_doublespend_chain(self):
186185
# child fees - 40 BTC - so this attempt is rejected.
187186
dbl_tx = CTransaction()
188187
dbl_tx.vin = [CTxIn(tx0_outpoint, nSequence=0)]
189-
dbl_tx.vout = [CTxOut(initial_nValue - 30 * COIN, CScript([1] * 35))]
188+
dbl_tx.vout = [CTxOut(initial_nValue - 30 * COIN, DUMMY_P2WPKH_SCRIPT)]
190189
dbl_tx_hex = txToHex(dbl_tx)
191190

192191
# This will raise an exception due to insufficient fee
@@ -195,7 +194,7 @@ def test_doublespend_chain(self):
195194
# Accepted with sufficient fee
196195
dbl_tx = CTransaction()
197196
dbl_tx.vin = [CTxIn(tx0_outpoint, nSequence=0)]
198-
dbl_tx.vout = [CTxOut(1 * COIN, CScript([1] * 35))]
197+
dbl_tx.vout = [CTxOut(1 * COIN, DUMMY_P2WPKH_SCRIPT)]
199198
dbl_tx_hex = txToHex(dbl_tx)
200199
self.nodes[0].sendrawtransaction(dbl_tx_hex, 0)
201200

@@ -248,15 +247,15 @@ def branch(prevout, initial_value, max_txs, tree_width=5, fee=0.0001*COIN, _tota
248247
# Attempt double-spend, will fail because too little fee paid
249248
dbl_tx = CTransaction()
250249
dbl_tx.vin = [CTxIn(tx0_outpoint, nSequence=0)]
251-
dbl_tx.vout = [CTxOut(initial_nValue - fee * n, CScript([1] * 35))]
250+
dbl_tx.vout = [CTxOut(initial_nValue - fee * n, DUMMY_P2WPKH_SCRIPT)]
252251
dbl_tx_hex = txToHex(dbl_tx)
253252
# This will raise an exception due to insufficient fee
254253
assert_raises_rpc_error(-26, "insufficient fee", self.nodes[0].sendrawtransaction, dbl_tx_hex, 0)
255254

256255
# 1 BTC fee is enough
257256
dbl_tx = CTransaction()
258257
dbl_tx.vin = [CTxIn(tx0_outpoint, nSequence=0)]
259-
dbl_tx.vout = [CTxOut(initial_nValue - fee * n - 1 * COIN, CScript([1] * 35))]
258+
dbl_tx.vout = [CTxOut(initial_nValue - fee * n - 1 * COIN, DUMMY_P2WPKH_SCRIPT)]
260259
dbl_tx_hex = txToHex(dbl_tx)
261260
self.nodes[0].sendrawtransaction(dbl_tx_hex, 0)
262261

@@ -276,7 +275,7 @@ def branch(prevout, initial_value, max_txs, tree_width=5, fee=0.0001*COIN, _tota
276275

277276
dbl_tx = CTransaction()
278277
dbl_tx.vin = [CTxIn(tx0_outpoint, nSequence=0)]
279-
dbl_tx.vout = [CTxOut(initial_nValue - 2 * fee * n, CScript([1] * 35))]
278+
dbl_tx.vout = [CTxOut(initial_nValue - 2 * fee * n, DUMMY_P2WPKH_SCRIPT)]
280279
dbl_tx_hex = txToHex(dbl_tx)
281280
# This will raise an exception
282281
assert_raises_rpc_error(-26, "too many potential replacements", self.nodes[0].sendrawtransaction, dbl_tx_hex, 0)
@@ -291,7 +290,7 @@ def test_replacement_feeperkb(self):
291290

292291
tx1a = CTransaction()
293292
tx1a.vin = [CTxIn(tx0_outpoint, nSequence=0)]
294-
tx1a.vout = [CTxOut(1 * COIN, CScript([b'a' * 35]))]
293+
tx1a.vout = [CTxOut(1 * COIN, DUMMY_P2WPKH_SCRIPT)]
295294
tx1a_hex = txToHex(tx1a)
296295
self.nodes[0].sendrawtransaction(tx1a_hex, 0)
297296

@@ -312,7 +311,7 @@ def test_spends_of_conflicting_outputs(self):
312311

313312
tx1a = CTransaction()
314313
tx1a.vin = [CTxIn(utxo1, nSequence=0)]
315-
tx1a.vout = [CTxOut(int(1.1 * COIN), CScript([b'a' * 35]))]
314+
tx1a.vout = [CTxOut(int(1.1 * COIN), DUMMY_P2WPKH_SCRIPT)]
316315
tx1a_hex = txToHex(tx1a)
317316
tx1a_txid = self.nodes[0].sendrawtransaction(tx1a_hex, 0)
318317

@@ -331,7 +330,7 @@ def test_spends_of_conflicting_outputs(self):
331330
# Spend tx1a's output to test the indirect case.
332331
tx1b = CTransaction()
333332
tx1b.vin = [CTxIn(COutPoint(tx1a_txid, 0), nSequence=0)]
334-
tx1b.vout = [CTxOut(1 * COIN, CScript([b'a' * 35]))]
333+
tx1b.vout = [CTxOut(1 * COIN, DUMMY_P2WPKH_SCRIPT)]
335334
tx1b_hex = txToHex(tx1b)
336335
tx1b_txid = self.nodes[0].sendrawtransaction(tx1b_hex, 0)
337336
tx1b_txid = int(tx1b_txid, 16)
@@ -352,7 +351,7 @@ def test_new_unconfirmed_inputs(self):
352351

353352
tx1 = CTransaction()
354353
tx1.vin = [CTxIn(confirmed_utxo)]
355-
tx1.vout = [CTxOut(1 * COIN, CScript([b'a' * 35]))]
354+
tx1.vout = [CTxOut(1 * COIN, DUMMY_P2WPKH_SCRIPT)]
356355
tx1_hex = txToHex(tx1)
357356
self.nodes[0].sendrawtransaction(tx1_hex, 0)
358357

@@ -391,7 +390,7 @@ def test_too_many_replacements(self):
391390
for i in range(MAX_REPLACEMENT_LIMIT+1):
392391
tx_i = CTransaction()
393392
tx_i.vin = [CTxIn(COutPoint(txid, i), nSequence=0)]
394-
tx_i.vout = [CTxOut(split_value - fee, CScript([b'a' * 35]))]
393+
tx_i.vout = [CTxOut(split_value - fee, DUMMY_P2WPKH_SCRIPT)]
395394
tx_i_hex = txToHex(tx_i)
396395
self.nodes[0].sendrawtransaction(tx_i_hex, 0)
397396

@@ -424,7 +423,7 @@ def test_opt_in(self):
424423
# Create a non-opting in transaction
425424
tx1a = CTransaction()
426425
tx1a.vin = [CTxIn(tx0_outpoint, nSequence=0xffffffff)]
427-
tx1a.vout = [CTxOut(1 * COIN, CScript([b'a' * 35]))]
426+
tx1a.vout = [CTxOut(1 * COIN, DUMMY_P2WPKH_SCRIPT)]
428427
tx1a_hex = txToHex(tx1a)
429428
tx1a_txid = self.nodes[0].sendrawtransaction(tx1a_hex, 0)
430429

@@ -434,7 +433,7 @@ def test_opt_in(self):
434433
# Shouldn't be able to double-spend
435434
tx1b = CTransaction()
436435
tx1b.vin = [CTxIn(tx0_outpoint, nSequence=0)]
437-
tx1b.vout = [CTxOut(int(0.9 * COIN), CScript([b'b' * 35]))]
436+
tx1b.vout = [CTxOut(int(0.9 * COIN), DUMMY_P2WPKH_SCRIPT)]
438437
tx1b_hex = txToHex(tx1b)
439438

440439
# This will raise an exception
@@ -445,14 +444,14 @@ def test_opt_in(self):
445444
# Create a different non-opting in transaction
446445
tx2a = CTransaction()
447446
tx2a.vin = [CTxIn(tx1_outpoint, nSequence=0xfffffffe)]
448-
tx2a.vout = [CTxOut(1 * COIN, CScript([b'a' * 35]))]
447+
tx2a.vout = [CTxOut(1 * COIN, DUMMY_P2WPKH_SCRIPT)]
449448
tx2a_hex = txToHex(tx2a)
450449
tx2a_txid = self.nodes[0].sendrawtransaction(tx2a_hex, 0)
451450

452451
# Still shouldn't be able to double-spend
453452
tx2b = CTransaction()
454453
tx2b.vin = [CTxIn(tx1_outpoint, nSequence=0)]
455-
tx2b.vout = [CTxOut(int(0.9 * COIN), CScript([b'b' * 35]))]
454+
tx2b.vout = [CTxOut(int(0.9 * COIN), DUMMY_P2WPKH_SCRIPT)]
456455
tx2b_hex = txToHex(tx2b)
457456

458457
# This will raise an exception
@@ -478,12 +477,12 @@ def test_opt_in(self):
478477

479478
tx3b = CTransaction()
480479
tx3b.vin = [CTxIn(COutPoint(tx1a_txid, 0), nSequence=0)]
481-
tx3b.vout = [CTxOut(int(0.5 * COIN), CScript([b'e' * 35]))]
480+
tx3b.vout = [CTxOut(int(0.5 * COIN), DUMMY_P2WPKH_SCRIPT)]
482481
tx3b_hex = txToHex(tx3b)
483482

484483
tx3c = CTransaction()
485484
tx3c.vin = [CTxIn(COutPoint(tx2a_txid, 0), nSequence=0)]
486-
tx3c.vout = [CTxOut(int(0.5 * COIN), CScript([b'f' * 35]))]
485+
tx3c.vout = [CTxOut(int(0.5 * COIN), DUMMY_P2WPKH_SCRIPT)]
487486
tx3c_hex = txToHex(tx3c)
488487

489488
self.nodes[0].sendrawtransaction(tx3b_hex, 0)
@@ -500,7 +499,7 @@ def test_prioritised_transactions(self):
500499

501500
tx1a = CTransaction()
502501
tx1a.vin = [CTxIn(tx0_outpoint, nSequence=0)]
503-
tx1a.vout = [CTxOut(1 * COIN, CScript([b'a' * 35]))]
502+
tx1a.vout = [CTxOut(1 * COIN, DUMMY_P2WPKH_SCRIPT)]
504503
tx1a_hex = txToHex(tx1a)
505504
tx1a_txid = self.nodes[0].sendrawtransaction(tx1a_hex, 0)
506505

@@ -526,14 +525,14 @@ def test_prioritised_transactions(self):
526525

527526
tx2a = CTransaction()
528527
tx2a.vin = [CTxIn(tx1_outpoint, nSequence=0)]
529-
tx2a.vout = [CTxOut(1 * COIN, CScript([b'a' * 35]))]
528+
tx2a.vout = [CTxOut(1 * COIN, DUMMY_P2WPKH_SCRIPT)]
530529
tx2a_hex = txToHex(tx2a)
531530
self.nodes[0].sendrawtransaction(tx2a_hex, 0)
532531

533532
# Lower fee, but we'll prioritise it
534533
tx2b = CTransaction()
535534
tx2b.vin = [CTxIn(tx1_outpoint, nSequence=0)]
536-
tx2b.vout = [CTxOut(int(1.01 * COIN), CScript([b'a' * 35]))]
535+
tx2b.vout = [CTxOut(int(1.01 * COIN), DUMMY_P2WPKH_SCRIPT)]
537536
tx2b.rehash()
538537
tx2b_hex = txToHex(tx2b)
539538

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
#!/usr/bin/env python3
2+
# Copyright (c) 2019 The Bitcoin Core developers
3+
# Distributed under the MIT software license, see the accompanying
4+
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
5+
"""Useful Script constants and utils."""
6+
from test_framework.script import CScript
7+
8+
# To prevent a "tx-size-small" policy rule error, a transaction has to have a
9+
# non-witness size of at least 82 bytes (MIN_STANDARD_TX_NONWITNESS_SIZE in
10+
# src/policy/policy.h). Considering a Tx with the smallest possible single
11+
# input (blank, empty scriptSig), and with an output omitting the scriptPubKey,
12+
# we get to a minimum size of 60 bytes:
13+
#
14+
# Tx Skeleton: 4 [Version] + 1 [InCount] + 1 [OutCount] + 4 [LockTime] = 10 bytes
15+
# Blank Input: 32 [PrevTxHash] + 4 [Index] + 1 [scriptSigLen] + 4 [SeqNo] = 41 bytes
16+
# Output: 8 [Amount] + 1 [scriptPubKeyLen] = 9 bytes
17+
#
18+
# Hence, the scriptPubKey of the single output has to have a size of at
19+
# least 22 bytes, which corresponds to the size of a P2WPKH scriptPubKey.
20+
# The following script constant consists of a single push of 21 bytes of 'a':
21+
# <PUSH_21> <21-bytes of 'a'>
22+
# resulting in a 22-byte size. It should be used whenever (small) fake
23+
# scriptPubKeys are needed, to guarantee that the minimum transaction size is
24+
# met.
25+
DUMMY_P2WPKH_SCRIPT = CScript([b'a' * 21])

0 commit comments

Comments
 (0)