mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-02-09 10:43:19 -05:00
Correctly compute redeemScript from witnessScript for signrawtransaction
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.
This commit is contained in:
parent
d52ba21dff
commit
cd3b1569d9
2 changed files with 42 additions and 3 deletions
|
@ -216,7 +216,7 @@ void ParsePrevouts(const UniValue& prevTxsUnival, FillableSigningProvider* keyst
|
||||||
keystore->AddCScript(script);
|
keystore->AddCScript(script);
|
||||||
// Automatically also add the P2WSH wrapped version of the script (to deal with P2SH-P2WSH).
|
// 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.
|
// 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);
|
keystore->AddCScript(witness_output_script);
|
||||||
|
|
||||||
if (!ws.isNull() && !rs.isNull()) {
|
if (!ws.isNull() && !rs.isNull()) {
|
||||||
|
|
|
@ -4,10 +4,11 @@
|
||||||
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||||
"""Test transaction signing using the signrawtransaction* RPCs."""
|
"""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.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.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
|
from decimal import Decimal
|
||||||
|
|
||||||
|
@ -168,6 +169,44 @@ class SignRawTransactionsTest(BitcoinTestFramework):
|
||||||
assert 'complete' in spending_tx_signed
|
assert 'complete' in spending_tx_signed
|
||||||
assert_equal(spending_tx_signed['complete'], True)
|
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):
|
def run_test(self):
|
||||||
self.successful_signing_test()
|
self.successful_signing_test()
|
||||||
self.script_verification_error_test()
|
self.script_verification_error_test()
|
||||||
|
|
Loading…
Add table
Reference in a new issue