Merge bitcoin/bitcoin#33172: test: p2p block malleability

d0e1bbad01 test: repeat block malleability test with relayable block over P2P (Musa Haruna)

Pull request description:

  This PR adds a functional test to repeat the existing malleability check for oversized coinbase witness nonce size using a block that is small enough to be relayed over the P2P network.

  This addresses the TODO in test_block_malleability by ensuring behavior is consistent between submitblock RPC and P2P relay.

ACKs for top commit:
  maflcko:
    lgtm ACK d0e1bbad01
  janb84:
    re ACK d0e1bbad01
  glozow:
    utACK d0e1bbad01

Tree-SHA512: 05aec4fade5af8043f40274a8d2f3cf3f540acd038138975bdefbbbc81e105792d6d2588256a2ee5ddb1e05b37fe2d0b3d287160d2dbe86e1aac7cfa9cc02116
This commit is contained in:
merge-script
2025-10-23 05:58:45 -04:00

View File

@@ -82,6 +82,7 @@ from test_framework.script_util import (
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
assert_not_equal,
assert_greater_than_or_equal,
assert_equal,
assert_raises_rpc_error,
ensure_for,
@@ -822,7 +823,6 @@ class SegWitTest(BitcoinTestFramework):
assert block.get_weight() > MAX_BLOCK_WEIGHT
# We can't send over the p2p network, because this is too big to relay
# TODO: repeat this test with a block that can be relayed
assert_equal('bad-witness-nonce-size', self.nodes[0].submitblock(block.serialize().hex()))
assert_not_equal(self.nodes[0].getbestblockhash(), block.hash_hex)
@@ -833,6 +833,36 @@ class SegWitTest(BitcoinTestFramework):
assert self.nodes[0].getbestblockhash() == block.hash_hex
# Build a relayable-but-invalid block
relayable_block = self.build_next_block()
add_witness_commitment(relayable_block)
relayable_block.solve()
# Append extra witness data to the coinbase input that triggers the
# same validation rejection but keeps the block under the weight limit
# so it can be sent via P2P.
relayable_block.vtx[0].wit.vtxinwit[0].scriptWitness.stack.append(b'a' * 100_000)
# Ensure it's relayable by weight
assert_greater_than_or_equal(MAX_BLOCK_WEIGHT, relayable_block.get_weight())
# Send over P2P and expect rejection for the same reason
test_witness_block(self.nodes[0], self.test_node, relayable_block,
accepted=False, reason='bad-witness-nonce-size')
# Node should still be on the previous tip
assert_not_equal(self.nodes[0].getbestblockhash(), relayable_block.hash_hex)
# Now fix the block by removing the extra witness data
relayable_block.vtx[0].wit.vtxinwit[0].scriptWitness.stack.pop()
# Confirm the block is still relayable by weight
assert relayable_block.get_weight() <= MAX_BLOCK_WEIGHT
# Send the corrected block and expect acceptance
test_witness_block(self.nodes[0], self.test_node, relayable_block, accepted=True)
assert_equal(self.nodes[0].getbestblockhash(), relayable_block.hash_hex)
# Now make sure that malleating the witness reserved value doesn't
# result in a block permanently marked bad.
block = self.build_next_block()