Skip to content

Commit 49e40f5

Browse files
author
MarcoFalke
committed
Merge bitcoin/bitcoin#22711: test: check for specific block reject reasons in p2p_segwit.py
45827fd test: check for block reject reasons in p2p_segwit.py [2/2] (Sebastian Falbesoner) 4eb532f test: check for block reject reasons in p2p_segwit.py [1/2] (Sebastian Falbesoner) b1488c4 test: fix reference to block processing test in p2p_segwit.py (Sebastian Falbesoner) Pull request description: In the test `p2p_segwit.py`, there are many instances where we send a segwit block to a node with the expectation that it is rejected. For this purpose, the helper function `test_witness_block` exists which allows also to check for a specific reject `reason` that is asserted in the debug log: https://github.com/bitcoin/bitcoin/blob/502d22ceed1f90ed41336260f8eb428d3acaf514/test/functional/p2p_segwit.py#L119-L120 This PR aims to increase the precision of the tests by adding the expected reject reasons to all `test_witness_block` call instances (found via `grep`ing after `test_witness_block(.*accepted=False`). For some blocks that are rejected due to failed script verification, the exact reason is only shown in the debug log if parallel script verification is disabled. For this reason, the addition of the reasons is split up in two commits: * first, all instances are tackled that are not subject to script verification, i.e. it doesn't matter whether parallel script verification is enabled or not (e.g. `bad-blk-weight`, `bad-witness-merkle-match`...) * then, we explicitely set `-par=1` to only use one script thread, and add the remaining reasons (`non-mandatory-script-verify-flag` with the more specific reason in parantheses) ACKs for top commit: stratospher: tested ACK 45827fd. Tree-SHA512: 00f31867f11d48b38a42b1e79a1303bda1c797ccf3d8c73e6107d70b062604d51ee2a3f2251e7f068dfafdaf09469d27dfee438d9bc9ebaef7febc4b6ef90a95
2 parents b9cf505 + 45827fd commit 49e40f5

File tree

1 file changed

+39
-21
lines changed

1 file changed

+39
-21
lines changed

test/functional/p2p_segwit.py

Lines changed: 39 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,12 @@
88
import struct
99
import time
1010

11-
from test_framework.blocktools import create_block, create_coinbase, add_witness_commitment, WITNESS_COMMITMENT_HEADER
11+
from test_framework.blocktools import (
12+
WITNESS_COMMITMENT_HEADER,
13+
add_witness_commitment,
14+
create_block,
15+
create_coinbase,
16+
)
1217
from test_framework.key import ECKey
1318
from test_framework.messages import (
1419
BIP125_SEQUENCE_NUMBER,
@@ -194,7 +199,7 @@ def set_test_params(self):
194199
self.num_nodes = 2
195200
# This test tests SegWit both pre and post-activation, so use the normal BIP9 activation.
196201
self.extra_args = [
197-
["-acceptnonstdtxn=1", f"-testactivationheight=segwit@{SEGWIT_HEIGHT}", "[email protected]"],
202+
["-acceptnonstdtxn=1", f"-testactivationheight=segwit@{SEGWIT_HEIGHT}", "[email protected]", "-par=1"],
198203
["-acceptnonstdtxn=0", f"-testactivationheight=segwit@{SEGWIT_HEIGHT}"],
199204
]
200205
self.supports_cli = False
@@ -505,8 +510,8 @@ def test_v0_outputs_arent_spendable(self):
505510
# 'block-validation-failed' (if script check threads > 1) or
506511
# 'non-mandatory-script-verify-flag (Witness program was passed an
507512
# empty witness)' (otherwise).
508-
# TODO: support multiple acceptable reject reasons.
509-
test_witness_block(self.nodes[0], self.test_node, block, accepted=False, with_witness=False)
513+
test_witness_block(self.nodes[0], self.test_node, block, accepted=False, with_witness=False,
514+
reason='non-mandatory-script-verify-flag (Witness program was passed an empty witness)')
510515

511516
self.utxo.pop(0)
512517
self.utxo.append(UTXO(txid, 2, value))
@@ -786,7 +791,7 @@ def test_witness_commitments(self):
786791
block_3.rehash()
787792
block_3.solve()
788793

789-
test_witness_block(self.nodes[0], self.test_node, block_3, accepted=False)
794+
test_witness_block(self.nodes[0], self.test_node, block_3, accepted=False, reason='bad-witness-merkle-match')
790795

791796
# Add a different commitment with different nonce, but in the
792797
# right location, and with some funds burned(!).
@@ -852,7 +857,7 @@ def test_block_malleability(self):
852857
# Change the nonce -- should not cause the block to be permanently
853858
# failed
854859
block.vtx[0].wit.vtxinwit[0].scriptWitness.stack = [ser_uint256(1)]
855-
test_witness_block(self.nodes[0], self.test_node, block, accepted=False)
860+
test_witness_block(self.nodes[0], self.test_node, block, accepted=False, reason='bad-witness-merkle-match')
856861

857862
# Changing the witness reserved value doesn't change the block hash
858863
block.vtx[0].wit.vtxinwit[0].scriptWitness.stack = [ser_uint256(0)]
@@ -861,7 +866,7 @@ def test_block_malleability(self):
861866
@subtest # type: ignore
862867
def test_witness_block_size(self):
863868
# TODO: Test that non-witness carrying blocks can't exceed 1MB
864-
# Skipping this test for now; this is covered in p2p-fullblocktest.py
869+
# Skipping this test for now; this is covered in feature_block.py
865870

866871
# Test that witness-bearing blocks are limited at ceil(base + wit/4) <= 1MB.
867872
block = self.build_next_block()
@@ -917,7 +922,7 @@ def test_witness_block_size(self):
917922
# limit
918923
assert len(block.serialize()) > 2 * 1024 * 1024
919924

920-
test_witness_block(self.nodes[0], self.test_node, block, accepted=False)
925+
test_witness_block(self.nodes[0], self.test_node, block, accepted=False, reason='bad-blk-weight')
921926

922927
# Now resize the second transaction to make the block fit.
923928
cur_length = len(block.vtx[-1].wit.vtxinwit[0].scriptWitness.stack[0])
@@ -989,7 +994,8 @@ def test_extra_witness_data(self):
989994
self.update_witness_block_with_transactions(block, [tx])
990995

991996
# Extra witness data should not be allowed.
992-
test_witness_block(self.nodes[0], self.test_node, block, accepted=False)
997+
test_witness_block(self.nodes[0], self.test_node, block, accepted=False,
998+
reason='non-mandatory-script-verify-flag (Witness provided for non-witness script)')
993999

9941000
# Try extra signature data. Ok if we're not spending a witness output.
9951001
block.vtx[1].wit.vtxinwit = []
@@ -1014,7 +1020,8 @@ def test_extra_witness_data(self):
10141020
self.update_witness_block_with_transactions(block, [tx2])
10151021

10161022
# This has extra witness data, so it should fail.
1017-
test_witness_block(self.nodes[0], self.test_node, block, accepted=False)
1023+
test_witness_block(self.nodes[0], self.test_node, block, accepted=False,
1024+
reason='non-mandatory-script-verify-flag (Stack size must be exactly one after execution)')
10181025

10191026
# Now get rid of the extra witness, but add extra scriptSig data
10201027
tx2.vin[0].scriptSig = CScript([OP_TRUE])
@@ -1026,7 +1033,8 @@ def test_extra_witness_data(self):
10261033
block.solve()
10271034

10281035
# This has extra signature data for a witness input, so it should fail.
1029-
test_witness_block(self.nodes[0], self.test_node, block, accepted=False)
1036+
test_witness_block(self.nodes[0], self.test_node, block, accepted=False,
1037+
reason='non-mandatory-script-verify-flag (Witness requires empty scriptSig)')
10301038

10311039
# Now get rid of the extra scriptsig on the witness input, and verify
10321040
# success (even with extra scriptsig data in the non-witness input)
@@ -1064,7 +1072,8 @@ def test_max_witness_push_length(self):
10641072
tx2.rehash()
10651073

10661074
self.update_witness_block_with_transactions(block, [tx, tx2])
1067-
test_witness_block(self.nodes[0], self.test_node, block, accepted=False)
1075+
test_witness_block(self.nodes[0], self.test_node, block, accepted=False,
1076+
reason='non-mandatory-script-verify-flag (Push value size limit exceeded)')
10681077

10691078
# Now reduce the length of the stack element
10701079
tx2.wit.vtxinwit[0].scriptWitness.stack[0] = b'a' * (MAX_SCRIPT_ELEMENT_SIZE)
@@ -1104,7 +1113,8 @@ def test_max_witness_script_length(self):
11041113

11051114
self.update_witness_block_with_transactions(block, [tx, tx2])
11061115

1107-
test_witness_block(self.nodes[0], self.test_node, block, accepted=False)
1116+
test_witness_block(self.nodes[0], self.test_node, block, accepted=False,
1117+
reason='non-mandatory-script-verify-flag (Script is too big)')
11081118

11091119
# Try again with one less byte in the witness script
11101120
witness_script = CScript([b'a' * MAX_SCRIPT_ELEMENT_SIZE] * 19 + [OP_DROP] * 62 + [OP_TRUE])
@@ -1176,14 +1186,16 @@ def serialize_with_witness(self):
11761186

11771187
block = self.build_next_block()
11781188
self.update_witness_block_with_transactions(block, [tx2])
1179-
test_witness_block(self.nodes[0], self.test_node, block, accepted=False)
1189+
test_witness_block(self.nodes[0], self.test_node, block, accepted=False, reason='bad-txnmrklroot')
11801190

11811191
# Now try using a too short vtxinwit
11821192
tx2.wit.vtxinwit.pop()
11831193
tx2.wit.vtxinwit.pop()
11841194

11851195
block.vtx = [block.vtx[0]]
11861196
self.update_witness_block_with_transactions(block, [tx2])
1197+
# This block doesn't result in a specific reject reason, but an iostream exception:
1198+
# "Exception 'CDataStream::read(): end of data: unspecified iostream_category error' (...) caught"
11871199
test_witness_block(self.nodes[0], self.test_node, block, accepted=False)
11881200

11891201
# Now make one of the intermediate witnesses be incorrect
@@ -1193,7 +1205,8 @@ def serialize_with_witness(self):
11931205

11941206
block.vtx = [block.vtx[0]]
11951207
self.update_witness_block_with_transactions(block, [tx2])
1196-
test_witness_block(self.nodes[0], self.test_node, block, accepted=False)
1208+
test_witness_block(self.nodes[0], self.test_node, block, accepted=False,
1209+
reason='non-mandatory-script-verify-flag (Operation not valid with the current stack size)')
11971210

11981211
# Fix the broken witness and the block should be accepted.
11991212
tx2.wit.vtxinwit[5].scriptWitness.stack = [b'a', witness_script]
@@ -1415,7 +1428,7 @@ def test_premature_coinbase_witness_spend(self):
14151428
self.sync_blocks()
14161429
block2 = self.build_next_block()
14171430
self.update_witness_block_with_transactions(block2, [spend_tx])
1418-
test_witness_block(self.nodes[0], self.test_node, block2, accepted=False)
1431+
test_witness_block(self.nodes[0], self.test_node, block2, accepted=False, reason='bad-txns-premature-spend-of-coinbase')
14191432

14201433
# Advancing one more block should allow the spend.
14211434
self.generate(self.nodes[0], 1)
@@ -1564,13 +1577,17 @@ def test_signature_version_1(self):
15641577
# Too-large input value
15651578
sign_p2pk_witness_input(witness_script, tx, 0, hashtype, prev_utxo.nValue + 1, key)
15661579
self.update_witness_block_with_transactions(block, [tx])
1567-
test_witness_block(self.nodes[0], self.test_node, block, accepted=False)
1580+
test_witness_block(self.nodes[0], self.test_node, block, accepted=False,
1581+
reason='non-mandatory-script-verify-flag (Script evaluated without error '
1582+
'but finished with a false/empty top stack element')
15681583

15691584
# Too-small input value
15701585
sign_p2pk_witness_input(witness_script, tx, 0, hashtype, prev_utxo.nValue - 1, key)
15711586
block.vtx.pop() # remove last tx
15721587
self.update_witness_block_with_transactions(block, [tx])
1573-
test_witness_block(self.nodes[0], self.test_node, block, accepted=False)
1588+
test_witness_block(self.nodes[0], self.test_node, block, accepted=False,
1589+
reason='non-mandatory-script-verify-flag (Script evaluated without error '
1590+
'but finished with a false/empty top stack element')
15741591

15751592
# Now try correct value
15761593
sign_p2pk_witness_input(witness_script, tx, 0, hashtype, prev_utxo.nValue, key)
@@ -1672,7 +1689,8 @@ def test_signature_version_1(self):
16721689
tx2.vin[0].scriptSig = CScript([signature, pubkey])
16731690
block = self.build_next_block()
16741691
self.update_witness_block_with_transactions(block, [tx, tx2])
1675-
test_witness_block(self.nodes[0], self.test_node, block, accepted=False)
1692+
test_witness_block(self.nodes[0], self.test_node, block, accepted=False,
1693+
reason='non-mandatory-script-verify-flag (Witness requires empty scriptSig)')
16761694

16771695
# Move the signature to the witness.
16781696
block.vtx.pop()
@@ -1918,7 +1936,7 @@ def test_witness_sigops(self):
19181936

19191937
block_2 = self.build_next_block()
19201938
self.update_witness_block_with_transactions(block_2, [tx2])
1921-
test_witness_block(self.nodes[0], self.test_node, block_2, accepted=False)
1939+
test_witness_block(self.nodes[0], self.test_node, block_2, accepted=False, reason='bad-blk-sigops')
19221940

19231941
# Try dropping the last input in tx2, and add an output that has
19241942
# too many sigops (contributing to legacy sigop count).
@@ -1931,7 +1949,7 @@ def test_witness_sigops(self):
19311949
tx2.rehash()
19321950
block_3 = self.build_next_block()
19331951
self.update_witness_block_with_transactions(block_3, [tx2])
1934-
test_witness_block(self.nodes[0], self.test_node, block_3, accepted=False)
1952+
test_witness_block(self.nodes[0], self.test_node, block_3, accepted=False, reason='bad-blk-sigops')
19351953

19361954
# If we drop the last checksig in this output, the tx should succeed.
19371955
block_4 = self.build_next_block()

0 commit comments

Comments
 (0)