From 6e60c362bc1e373a284911381e2a513f57f5f26b Mon Sep 17 00:00:00 2001 From: Musa Haruna Date: Fri, 24 Jul 2026 15:35:44 +0100 Subject: [PATCH 1/2] test: add P2SH sigop counting coverage MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Implement the TODO in `test_witness_sigops()` by adding coverage for sigop accounting in P2SH spends. Co-authored-by: Lőrinc --- test/functional/p2p_segwit.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/test/functional/p2p_segwit.py b/test/functional/p2p_segwit.py index 92ebe21ad7d..92b69e49970 100755 --- a/test/functional/p2p_segwit.py +++ b/test/functional/p2p_segwit.py @@ -29,6 +29,7 @@ from test_framework.messages import ( MSG_WTX, NODE_NETWORK, NODE_WITNESS, + WITNESS_SCALE_FACTOR, msg_no_witness_block, msg_getdata, msg_headers, @@ -1868,6 +1869,7 @@ class SegWitTest(BitcoinTestFramework): # sig ops outputs = (MAX_SIGOP_COST // sigops_per_script) + 2 extra_sigops_available = MAX_SIGOP_COST % sigops_per_script + p2sh_outputs = MAX_SIGOP_COST // (sigops_per_script * WITNESS_SCALE_FACTOR) + 1 # We chose the number of checkmultisigs/checksigs to make this work: assert extra_sigops_available < 100 # steer clear of MAX_OPS_PER_SCRIPT @@ -1891,6 +1893,7 @@ class SegWitTest(BitcoinTestFramework): tx.vout.append(CTxOut(split_value, script_pubkey)) tx.vout[-2].scriptPubKey = script_pubkey_toomany tx.vout[-1].scriptPubKey = script_pubkey_justright + tx.vout += [CTxOut(0, script_to_p2sh_script(witness_script)) for _ in range(p2sh_outputs)] block_1 = self.build_next_block() self.update_witness_block_with_transactions(block_1, [tx]) @@ -1919,7 +1922,7 @@ class SegWitTest(BitcoinTestFramework): tx2.vout.append(CTxOut(0, script_pubkey_checksigs)) tx2.vin.pop() tx2.wit.vtxinwit.pop() - tx2.vout[0].nValue -= tx.vout[-2].nValue + tx2.vout[0].nValue -= tx.vout[outputs - 2].nValue block_3 = self.build_next_block() self.update_witness_block_with_transactions(block_3, [tx2]) test_witness_block(self.nodes[0], self.test_node, block_3, accepted=False, reason='bad-blk-sigops') @@ -1945,7 +1948,12 @@ class SegWitTest(BitcoinTestFramework): self.update_witness_block_with_transactions(block_5, [tx2]) test_witness_block(self.nodes[0], self.test_node, block_5, accepted=True) - # TODO: test p2sh sigop counting + p2sh_tx = CTransaction() + p2sh_tx.vin = [CTxIn(COutPoint(tx.txid_int, outputs + i), CScript([witness_script])) for i in range(p2sh_outputs)] + p2sh_tx.vout.append(CTxOut(0, CScript([OP_TRUE]))) + block_6 = self.build_next_block() + self.update_witness_block_with_transactions(block_6, [p2sh_tx]) + test_witness_block(self.nodes[0], self.test_node, block_6, accepted=False, reason='bad-blk-sigops') # Cleanup and prep for next test self.utxo.pop(0) From d180b891a2904fb787ac5fa1ed66f56c98496698 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C5=91rinc?= Date: Thu, 23 Jul 2026 19:06:18 -0700 Subject: [PATCH 2/2] test: add mixed P2SH/witness sigop accounting Add test covering transactions containing both P2SH and witness inputs when enforcing the block sigop limit. --- test/functional/p2p_segwit.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test/functional/p2p_segwit.py b/test/functional/p2p_segwit.py index 92b69e49970..0917e1dc2a7 100755 --- a/test/functional/p2p_segwit.py +++ b/test/functional/p2p_segwit.py @@ -1955,6 +1955,14 @@ class SegWitTest(BitcoinTestFramework): self.update_witness_block_with_transactions(block_6, [p2sh_tx]) test_witness_block(self.nodes[0], self.test_node, block_6, accepted=False, reason='bad-blk-sigops') + # Add witness data to verify that the transaction's P2SH sigops are still counted. + p2sh_tx.vin.append(CTxIn(COutPoint(tx.txid_int, outputs - 2), b"")) + p2sh_tx.wit.vtxinwit = [CTxInWitness() for _ in p2sh_tx.vin] + p2sh_tx.wit.vtxinwit[-1].scriptWitness.stack = [witness_script_toomany] + block_7 = self.build_next_block() + self.update_witness_block_with_transactions(block_7, [p2sh_tx]) + test_witness_block(self.nodes[0], self.test_node, block_7, accepted=False, reason='bad-blk-sigops') + # Cleanup and prep for next test self.utxo.pop(0) self.utxo.append(UTXO(tx2.txid_int, 0, tx2.vout[0].nValue))