From 83d7cfd5429b0be7755bc48145032956f5f56dae Mon Sep 17 00:00:00 2001 From: Sebastian Falbesoner Date: Tue, 25 Jul 2023 22:15:56 +0200 Subject: [PATCH] test: refactor: deduplicate segwitv0 ECDSA signing for tx inputs Follow-up for #28025. --- test/functional/p2p_segwit.py | 20 +++++++++----------- test/functional/test_framework/script.py | 9 +++++++++ 2 files changed, 18 insertions(+), 11 deletions(-) diff --git a/test/functional/p2p_segwit.py b/test/functional/p2p_segwit.py index 1e7bc95a63e..51ec0fc8e7f 100755 --- a/test/functional/p2p_segwit.py +++ b/test/functional/p2p_segwit.py @@ -70,9 +70,9 @@ from test_framework.script import ( SIGHASH_ANYONECANPAY, SIGHASH_NONE, SIGHASH_SINGLE, - SegwitV0SignatureHash, hash160, sign_input_legacy, + sign_input_segwitv0, ) from test_framework.script_util import ( key_to_p2pk_script, @@ -121,10 +121,8 @@ def subtest(func): def sign_p2pk_witness_input(script, tx_to, in_idx, hashtype, value, key): """Add signature for a P2PK witness script.""" - tx_hash = SegwitV0SignatureHash(script, tx_to, in_idx, hashtype, value) - signature = key.sign_ecdsa(tx_hash) + chr(hashtype).encode('latin-1') - tx_to.wit.vtxinwit[in_idx].scriptWitness.stack = [signature, script] - tx_to.rehash() + tx_to.wit.vtxinwit[in_idx].scriptWitness.stack = [script] + sign_input_segwitv0(tx_to, in_idx, script, value, key, hashtype) def test_transaction_acceptance(node, p2p, tx, with_witness, accepted, reason=None): """Send a transaction to the node and check that it's accepted to the mempool @@ -1476,11 +1474,9 @@ class SegWitTest(BitcoinTestFramework): tx2.vin.append(CTxIn(COutPoint(tx.sha256, 0), b"")) tx2.vout.append(CTxOut(tx.vout[0].nValue - 1000, script_wsh)) script = keyhash_to_p2pkh_script(pubkeyhash) - sig_hash = SegwitV0SignatureHash(script, tx2, 0, SIGHASH_ALL, tx.vout[0].nValue) - signature = key.sign_ecdsa(sig_hash) + b'\x01' # 0x1 is SIGHASH_ALL tx2.wit.vtxinwit.append(CTxInWitness()) - tx2.wit.vtxinwit[0].scriptWitness.stack = [signature, pubkey] - tx2.rehash() + tx2.wit.vtxinwit[0].scriptWitness.stack = [pubkey] + sign_input_segwitv0(tx2, 0, script, tx.vout[0].nValue, key) # Should fail policy test. test_transaction_acceptance(self.nodes[0], self.test_node, tx2, True, False, 'non-mandatory-script-verify-flag (Using non-compressed keys in segwit)') @@ -1676,11 +1672,13 @@ class SegWitTest(BitcoinTestFramework): tx2.vout.append(CTxOut(tx.vout[0].nValue, CScript([OP_TRUE]))) script = keyhash_to_p2pkh_script(pubkeyhash) - sig_hash = SegwitV0SignatureHash(script, tx2, 0, SIGHASH_ALL, tx.vout[0].nValue) - signature = key.sign_ecdsa(sig_hash) + b'\x01' # 0x1 is SIGHASH_ALL + tx2.wit.vtxinwit.append(CTxInWitness()) + sign_input_segwitv0(tx2, 0, script, tx.vout[0].nValue, key) + signature = tx2.wit.vtxinwit[0].scriptWitness.stack.pop() # Check that we can't have a scriptSig tx2.vin[0].scriptSig = CScript([signature, pubkey]) + tx2.rehash() block = self.build_next_block() self.update_witness_block_with_transactions(block, [tx, tx2]) test_witness_block(self.nodes[0], self.test_node, block, accepted=False, diff --git a/test/functional/test_framework/script.py b/test/functional/test_framework/script.py index 78f58cf11fc..17a954cb22c 100644 --- a/test/functional/test_framework/script.py +++ b/test/functional/test_framework/script.py @@ -699,6 +699,15 @@ def sign_input_legacy(tx, input_index, input_scriptpubkey, privkey, sighash_type tx.vin[input_index].scriptSig = bytes(CScript([der_sig + bytes([sighash_type])])) + tx.vin[input_index].scriptSig tx.rehash() +def sign_input_segwitv0(tx, input_index, input_scriptpubkey, input_amount, privkey, sighash_type=SIGHASH_ALL): + """Add segwitv0 ECDSA signature for a given transaction input. Note that the signature + is inserted at the bottom of the witness stack, i.e. additional witness data + needed (e.g. pubkey for P2WPKH) can already be set before.""" + sighash = SegwitV0SignatureHash(input_scriptpubkey, tx, input_index, sighash_type, input_amount) + der_sig = privkey.sign_ecdsa(sighash) + tx.wit.vtxinwit[input_index].scriptWitness.stack.insert(0, der_sig + bytes([sighash_type])) + tx.rehash() + # TODO: Allow cached hashPrevouts/hashSequence/hashOutputs to be provided. # Performance optimization probably not necessary for python tests, however. # Note that this corresponds to sigversion == 1 in EvalScript, which is used