diff options
author | MarcoFalke <falke.marco@gmail.com> | 2020-04-07 00:59:40 +0800 |
---|---|---|
committer | MarcoFalke <falke.marco@gmail.com> | 2020-04-07 00:59:48 +0800 |
commit | c0b389b33516fb3eaaad7c30bd11dba768882a7e (patch) | |
tree | d8d72b8435b3b16a4703bfdc27af34bc38504886 | |
parent | 425a7f900ed824caa5d4a93991542c70171539fe (diff) | |
parent | cd3b1569d9ad8e24d3a222aff74e0c254baadf79 (diff) | |
download | bitcoin-c0b389b33516fb3eaaad7c30bd11dba768882a7e.tar.xz |
Merge #18484: rpc: Correctly compute redeemScript from witnessScript for signrawtransaction
cd3b1569d9ad8e24d3a222aff74e0c254baadf79 Correctly compute redeemScript from witnessScript for signrawtransaction (Andrew Chow)
Pull request description:
`ParsePrevouts` uses `GetScriptForWitness` on the given witnessScript to find the corresponding redeemScript. This is incorrect when the witnessScript is either a P2PK or P2PKH script as it returns the corresponding P2WPK script instead of turning the witnessScript into a P2WSH script. Instead this should make the script a `WitnessV0ScriptHash` destination and get the script for that.
Test cases are also added. These will fail on master with a `redeemScript does not correspond to witnessScript`
Reported on [Bitcointalk](https://bitcointalk.org/index.php?topic=5236818.0)
ACKs for top commit:
MarcoFalke:
weak ACK cd3b1569d9, only checked that the test fails without the code change 🚰
instagibbs:
utACK https://github.com/bitcoin/bitcoin/pull/18484/commits/cd3b1569d9ad8e24d3a222aff74e0c254baadf79
Tree-SHA512: afac671dbb52ce88bfb4a9ca3dd6065427ad52c9778d0549ad40e9286778f308adad24fb3b3c3089545d7f88c57c53d41224fd7a4bb207550eff2fe06600118f
-rw-r--r-- | src/rpc/rawtransaction_util.cpp | 2 | ||||
-rwxr-xr-x | test/functional/rpc_signrawtransaction.py | 43 |
2 files changed, 42 insertions, 3 deletions
diff --git a/src/rpc/rawtransaction_util.cpp b/src/rpc/rawtransaction_util.cpp index 54baec6c6f..7b701a2bbe 100644 --- a/src/rpc/rawtransaction_util.cpp +++ b/src/rpc/rawtransaction_util.cpp @@ -216,7 +216,7 @@ void ParsePrevouts(const UniValue& prevTxsUnival, FillableSigningProvider* keyst keystore->AddCScript(script); // Automatically also add the P2WSH wrapped version of the script (to deal with P2SH-P2WSH). // This is done for redeemScript only for compatibility, it is encouraged to use the explicit witnessScript field instead. - CScript witness_output_script{GetScriptForWitness(script)}; + CScript witness_output_script{GetScriptForDestination(WitnessV0ScriptHash(script))}; keystore->AddCScript(witness_output_script); if (!ws.isNull() && !rs.isNull()) { diff --git a/test/functional/rpc_signrawtransaction.py b/test/functional/rpc_signrawtransaction.py index 780758e219..a34abbd41b 100755 --- a/test/functional/rpc_signrawtransaction.py +++ b/test/functional/rpc_signrawtransaction.py @@ -4,10 +4,11 @@ # file COPYING or http://www.opensource.org/licenses/mit-license.php. """Test transaction signing using the signrawtransaction* RPCs.""" +from test_framework.address import check_script, script_to_p2sh from test_framework.test_framework import BitcoinTestFramework -from test_framework.util import assert_equal, assert_raises_rpc_error, hex_str_to_bytes +from test_framework.util import assert_equal, assert_raises_rpc_error, find_vout_for_address, hex_str_to_bytes from test_framework.messages import sha256 -from test_framework.script import CScript, OP_0 +from test_framework.script import CScript, OP_0, OP_CHECKSIG from decimal import Decimal @@ -168,6 +169,44 @@ class SignRawTransactionsTest(BitcoinTestFramework): assert 'complete' in spending_tx_signed assert_equal(spending_tx_signed['complete'], True) + # Now try with a P2PKH script as the witnessScript + embedded_addr_info = self.nodes[1].getaddressinfo(self.nodes[1].getnewaddress('', 'legacy')) + embedded_privkey = self.nodes[1].dumpprivkey(embedded_addr_info['address']) + witness_script = embedded_addr_info['scriptPubKey'] + redeem_script = CScript([OP_0, sha256(check_script(witness_script))]).hex() + addr = script_to_p2sh(redeem_script) + script_pub_key = self.nodes[1].validateaddress(addr)['scriptPubKey'] + # Fund that address + txid = self.nodes[0].sendtoaddress(addr, 10) + vout = find_vout_for_address(self.nodes[0], txid, addr) + self.nodes[0].generate(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}], {self.nodes[1].getnewaddress(): 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}]) + # Check the signing completed successfully + assert 'complete' in spending_tx_signed + assert_equal(spending_tx_signed['complete'], True) + self.nodes[1].sendrawtransaction(spending_tx_signed['hex']) + + # Now try with a P2PK script as the witnessScript + embedded_addr_info = self.nodes[1].getaddressinfo(self.nodes[1].getnewaddress('', 'legacy')) + embedded_privkey = self.nodes[1].dumpprivkey(embedded_addr_info['address']) + witness_script = CScript([hex_str_to_bytes(embedded_addr_info['pubkey']), OP_CHECKSIG]).hex() + redeem_script = CScript([OP_0, sha256(check_script(witness_script))]).hex() + addr = script_to_p2sh(redeem_script) + script_pub_key = self.nodes[1].validateaddress(addr)['scriptPubKey'] + # Fund that address + txid = self.nodes[0].sendtoaddress(addr, 10) + vout = find_vout_for_address(self.nodes[0], txid, addr) + self.nodes[0].generate(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}], {self.nodes[1].getnewaddress(): 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}]) + # Check the signing completed successfully + assert 'complete' in spending_tx_signed + assert_equal(spending_tx_signed['complete'], True) + self.nodes[1].sendrawtransaction(spending_tx_signed['hex']) + def run_test(self): self.successful_signing_test() self.script_verification_error_test() |