Repository: bitcoin/bitcoin
File: test/functional/rpc_signrawtransactionwithkey.py (Python)

Code before:

        # Now test with P2PKH and P2PK scripts as the witnessScript
        for tx_type in ['P2PKH', 'P2PK']:  # these tests are order-independent
            self.verify_txn_with_witness_script(tx_type)

    def keyless_signing_test(self):
        self.log.info("Test that keyless 'signing' of pay-to-anchor input succeeds")
        funding_txid = self.send_to_address(p2a(), 49.999)
        spending_tx = self.nodes[0].createrawtransaction(
            [{"txid": funding_txid, "vout": 0}],
            [{getnewdestination()[2]: Decimal("49.998")}])
        spending_tx_signed = self.nodes[0].signrawtransactionwithkey(spending_tx, [], [])
        self.assert_signing_completed_successfully(spending_tx_signed)
        assert self.nodes[0].testmempoolaccept([spending_tx_signed["hex"]])[0]["allowed"]
        # 'signing' a P2A prevout is a no-op, so signed and unsigned txs shouldn't differ
        assert_equal(spending_tx, spending_tx_signed["hex"])

    def verify_txn_with_witness_script(self, tx_type):
        self.log.info("Test with a {} script as the witnessScript".format(tx_type))
        embedded_privkey, embedded_pubkey = generate_keypair(wif=True)
        witness_script = {
            'P2PKH': key_to_p2pkh_script(embedded_pubkey).hex(),
            'P2PK': key_to_p2pk_script(embedded_pubkey).hex()
        }.get(tx_type, "Invalid tx_type")
        redeem_script = script_to_p2wsh_script(witness_script).hex()
        addr = script_to_p2sh(redeem_script)
        script_pub_key = address_to_scriptpubkey(addr).hex()
        # Fund that address
        txid = self.send_to_address(addr, 10)
        vout = find_vout_for_address(self.nodes[0], txid, addr)
        self.generate(self.nodes[0], 1)
        # Now create and sign a transaction spending that output on node[0], which doesn't know the scripts or keys
        spending_tx = self.nodes[0].createrawtransaction([{'txid': txid, 'vout': vout}], {getnewdestination()[2]: Decimal("9.999")})
        spending_tx_signed = self.nodes[0].signrawtransactionwithkey(spending_tx, [embedded_privkey], [{'txid': txid, 'vout': vout, 'scriptPubKey': script_pub_key, 'redeemScript': redeem_script, 'witnessScript': witness_script, 'amount': 10}])
        self.assert_signing_completed_successfully(spending_tx_signed)
        self.nodes[0].sendrawtransaction(spending_tx_signed['hex'])

    def invalid_sighashtype_test(self):
        self.log.info("Test signing transaction with invalid sighashtype")
        tx = self.nodes[0].createrawtransaction(INPUTS, OUTPUTS)
        privkeys = [self.nodes[0].get_deterministic_priv_key().key]
        assert_raises_rpc_error(-8, "'all' is not a valid sighash parameter.", self.nodes[0].signrawtransactionwithkey, tx, privkeys, sighashtype="all")

    def invalid_private_key_and_tx(self):
        self.log.info("Test signing transaction with an invalid private key")
        tx = self.nodes[0].createrawtransaction(INPUTS, OUTPUTS)
        privkeys = ["123"]
        assert_raises_rpc_error(-5, "Invalid private key", self.nodes[0].signrawtransactionwithkey, tx, privkeys)
        self.log.info("Test signing transaction with an invalid tx hex")
        privkeys = [self.nodes[0].get_deterministic_priv_key().key]
        assert_raises_rpc_error(-22, "TX decode failed. Make sure the tx has at least one input.", self.nodes[0].signrawtransactionwithkey, tx + "00", privkeys)

Review comment (refactor):
could use the `vout` result from `send_to_address` also here, so the `find_vout_for_address` helper isn't needed anymore

Code after:
        self.log.info("Test that keyless 'signing' of pay-to-anchor input succeeds")
        [txid, vout] = self.send_to_address(p2a(), 49.999)
        spending_tx = self.nodes[0].createrawtransaction(
            [{"txid": txid, "vout": vout}],
            [{getnewdestination()[2]: Decimal("49.998")}])
        spending_tx_signed = self.nodes[0].signrawtransactionwithkey(spending_tx, [], [])
        self.assert_signing_completed_successfully(spending_tx_signed)
        assert self.nodes[0].testmempoolaccept([spending_tx_signed["hex"]])[0]["allowed"]
        # 'signing' a P2A prevout is a no-op, so signed and unsigned txs shouldn't differ
        assert_equal(spending_tx, spending_tx_signed["hex"])

    def verify_txn_with_witness_script(self, tx_type):
        self.log.info("Test with a {} script as the witnessScript".format(tx_type))
        embedded_privkey, embedded_pubkey = generate_keypair(wif=True)
        witness_script = {
            'P2PKH': key_to_p2pkh_script(embedded_pubkey).hex(),
            'P2PK': key_to_p2pk_script(embedded_pubkey).hex()
        }.get(tx_type, "Invalid tx_type")
        redeem_script = script_to_p2wsh_script(witness_script).hex()
        addr = script_to_p2sh(redeem_script)
        script_pub_key = address_to_scriptpubkey(addr).hex()
        # Fund that address
        [txid, vout] = self.send_to_address(addr, 10)
        # Now create and sign a transaction spending that output on node[0], which doesn't know the scripts or keys
        spending_tx = self.nodes[0].createrawtransaction([{'txid': txid, 'vout': vout}], {getnewdestination()[2]: Decimal("9.999")})
        spending_tx_signed = self.nodes[0].signrawtransactionwithkey(spending_tx, [embedded_privkey], [{'txid': txid, 'vout': vout, 'scriptPubKey': script_pub_key, 'redeemScript': redeem_script, 'witnessScript': witness_script, 'amount': 10}])
        self.assert_signing_completed_successfully(spending_tx_signed)
        self.nodes[0].sendrawtransaction(spending_tx_signed['hex'])

    def invalid_sighashtype_test(self):
        self.log.info("Test signing transaction with invalid sighashtype")
        tx = self.nodes[0].createrawtransaction(INPUTS, OUTPUTS)
        privkeys = [self.nodes[0].get_deterministic_priv_key().key]
        assert_raises_rpc_error(-8, "'all' is not a valid sighash parameter.", self.nodes[0].signrawtransactionwithkey, tx, privkeys, sighashtype="all")

    def invalid_private_key_and_tx(self):
        self.log.info("Test signing transaction with an invalid private key")
        tx = self.nodes[0].createrawtransaction(INPUTS, OUTPUTS)
        privkeys = ["123"]
        assert_raises_rpc_error(-5, "Invalid private key", self.nodes[0].signrawtransactionwithkey, tx, privkeys)
        self.log.info("Test signing transaction with an invalid tx hex")
        privkeys = [self.nodes[0].get_deterministic_priv_key().key]
        assert_raises_rpc_error(-22, "TX decode failed. Make sure the tx has at least one input.", self.nodes[0].signrawtransactionwithkey, tx + "00", privkeys)

    def run_test(self):
        self.wallet = MiniWallet(self.nodes[0])
        self.successful_signing_test()
        self.witness_script_test()
        self.keyless_signing_test()
        self.invalid_sighashtype_test()
        self.invalid_private_key_and_tx()