Merge bitcoin/bitcoin#29615: test: fix accurate multisig sigop count (BIP16), add unit test

3e9c736a26 test: fix accurate multisig sigop count (BIP16), add unit test (Sebastian Falbesoner)

Pull request description:

  In the course of reviewing #29589 I noticed the following buggy call-site of `CScriptOp.decode_op_n` in the CScript's `GetSigOpCount` method:
  4cc99df44a/test/functional/test_framework/script.py (L591-L593)
  This should be `lastOpcode` rather than `opcode`. The latter is either OP_CHECKMULTISIG or OP_CHECKMULTISIGVERIFY at this point, so `decode_op_n` would result in an error. Also, in `CScript.raw_iter`, we have to return the op as `CScriptOp` type instead of a bare integer, otherwise we can't call the decode method on it. To prevent this in the future, add some simple unit tests for `GetSigOpCount`.

  Note that this was unnoticed, as the code part was never hit so far in the test framework.

ACKs for top commit:
  achow101:
    ACK 3e9c736a26
  Christewart:
    ACK 3e9c736a26
  rkrux:
    tACK [3e9c736](3e9c736a26)
  hernanmarino:
    tACK 3e9c736a26

Tree-SHA512: 51647bb6d462fbd101effd851afdbd6ad198c0567888cd4fdcac389a9fb4bd3d7e648095c6944fd8875d36272107ebaabdc62d0e2423289055588c12294d05a7
This commit is contained in:
Ava Chow 2024-04-25 13:43:54 -04:00
commit 50b09e8173
No known key found for this signature in database
GPG Key ID: 17565732E08E5E41
1 changed files with 16 additions and 2 deletions

View File

@ -483,7 +483,7 @@ class CScript(bytes):
i = 0
while i < len(self):
sop_idx = i
opcode = self[i]
opcode = CScriptOp(self[i])
i += 1
if opcode > OP_PUSHDATA4:
@ -590,7 +590,7 @@ class CScript(bytes):
n += 1
elif opcode in (OP_CHECKMULTISIG, OP_CHECKMULTISIGVERIFY):
if fAccurate and (OP_1 <= lastOpcode <= OP_16):
n += opcode.decode_op_n()
n += lastOpcode.decode_op_n()
else:
n += 20
lastOpcode = opcode
@ -782,6 +782,20 @@ class TestFrameworkScript(unittest.TestCase):
for value in values:
self.assertEqual(CScriptNum.decode(CScriptNum.encode(CScriptNum(value))), value)
def test_legacy_sigopcount(self):
# test repeated single sig ops
for n_ops in range(1, 100, 10):
for singlesig_op in (OP_CHECKSIG, OP_CHECKSIGVERIFY):
singlesigs_script = CScript([singlesig_op]*n_ops)
self.assertEqual(singlesigs_script.GetSigOpCount(fAccurate=False), n_ops)
self.assertEqual(singlesigs_script.GetSigOpCount(fAccurate=True), n_ops)
# test multisig op (including accurate counting, i.e. BIP16)
for n in range(1, 16+1):
for multisig_op in (OP_CHECKMULTISIG, OP_CHECKMULTISIGVERIFY):
multisig_script = CScript([CScriptOp.encode_op_n(n), multisig_op])
self.assertEqual(multisig_script.GetSigOpCount(fAccurate=False), 20)
self.assertEqual(multisig_script.GetSigOpCount(fAccurate=True), n)
def BIP341_sha_prevouts(txTo):
return sha256(b"".join(i.prevout.serialize() for i in txTo.vin))