Skip to content

Commit c0b389b

Browse files
author
MarcoFalke
committed
Merge #18484: rpc: Correctly compute redeemScript from witnessScript for signrawtransaction
cd3b156 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 cd3b156, only checked that the test fails without the code change 🚰 instagibbs: utACK bitcoin/bitcoin@cd3b156 Tree-SHA512: afac671dbb52ce88bfb4a9ca3dd6065427ad52c9778d0549ad40e9286778f308adad24fb3b3c3089545d7f88c57c53d41224fd7a4bb207550eff2fe06600118f
2 parents 425a7f9 + cd3b156 commit c0b389b

File tree

2 files changed

+42
-3
lines changed

2 files changed

+42
-3
lines changed

src/rpc/rawtransaction_util.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,7 @@ void ParsePrevouts(const UniValue& prevTxsUnival, FillableSigningProvider* keyst
216216
keystore->AddCScript(script);
217217
// Automatically also add the P2WSH wrapped version of the script (to deal with P2SH-P2WSH).
218218
// This is done for redeemScript only for compatibility, it is encouraged to use the explicit witnessScript field instead.
219-
CScript witness_output_script{GetScriptForWitness(script)};
219+
CScript witness_output_script{GetScriptForDestination(WitnessV0ScriptHash(script))};
220220
keystore->AddCScript(witness_output_script);
221221

222222
if (!ws.isNull() && !rs.isNull()) {

test/functional/rpc_signrawtransaction.py

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,11 @@
44
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
55
"""Test transaction signing using the signrawtransaction* RPCs."""
66

7+
from test_framework.address import check_script, script_to_p2sh
78
from test_framework.test_framework import BitcoinTestFramework
8-
from test_framework.util import assert_equal, assert_raises_rpc_error, hex_str_to_bytes
9+
from test_framework.util import assert_equal, assert_raises_rpc_error, find_vout_for_address, hex_str_to_bytes
910
from test_framework.messages import sha256
10-
from test_framework.script import CScript, OP_0
11+
from test_framework.script import CScript, OP_0, OP_CHECKSIG
1112

1213
from decimal import Decimal
1314

@@ -168,6 +169,44 @@ def witness_script_test(self):
168169
assert 'complete' in spending_tx_signed
169170
assert_equal(spending_tx_signed['complete'], True)
170171

172+
# Now try with a P2PKH script as the witnessScript
173+
embedded_addr_info = self.nodes[1].getaddressinfo(self.nodes[1].getnewaddress('', 'legacy'))
174+
embedded_privkey = self.nodes[1].dumpprivkey(embedded_addr_info['address'])
175+
witness_script = embedded_addr_info['scriptPubKey']
176+
redeem_script = CScript([OP_0, sha256(check_script(witness_script))]).hex()
177+
addr = script_to_p2sh(redeem_script)
178+
script_pub_key = self.nodes[1].validateaddress(addr)['scriptPubKey']
179+
# Fund that address
180+
txid = self.nodes[0].sendtoaddress(addr, 10)
181+
vout = find_vout_for_address(self.nodes[0], txid, addr)
182+
self.nodes[0].generate(1)
183+
# Now create and sign a transaction spending that output on node[0], which doesn't know the scripts or keys
184+
spending_tx = self.nodes[0].createrawtransaction([{'txid': txid, 'vout': vout}], {self.nodes[1].getnewaddress(): Decimal("9.999")})
185+
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}])
186+
# Check the signing completed successfully
187+
assert 'complete' in spending_tx_signed
188+
assert_equal(spending_tx_signed['complete'], True)
189+
self.nodes[1].sendrawtransaction(spending_tx_signed['hex'])
190+
191+
# Now try with a P2PK script as the witnessScript
192+
embedded_addr_info = self.nodes[1].getaddressinfo(self.nodes[1].getnewaddress('', 'legacy'))
193+
embedded_privkey = self.nodes[1].dumpprivkey(embedded_addr_info['address'])
194+
witness_script = CScript([hex_str_to_bytes(embedded_addr_info['pubkey']), OP_CHECKSIG]).hex()
195+
redeem_script = CScript([OP_0, sha256(check_script(witness_script))]).hex()
196+
addr = script_to_p2sh(redeem_script)
197+
script_pub_key = self.nodes[1].validateaddress(addr)['scriptPubKey']
198+
# Fund that address
199+
txid = self.nodes[0].sendtoaddress(addr, 10)
200+
vout = find_vout_for_address(self.nodes[0], txid, addr)
201+
self.nodes[0].generate(1)
202+
# Now create and sign a transaction spending that output on node[0], which doesn't know the scripts or keys
203+
spending_tx = self.nodes[0].createrawtransaction([{'txid': txid, 'vout': vout}], {self.nodes[1].getnewaddress(): Decimal("9.999")})
204+
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}])
205+
# Check the signing completed successfully
206+
assert 'complete' in spending_tx_signed
207+
assert_equal(spending_tx_signed['complete'], True)
208+
self.nodes[1].sendrawtransaction(spending_tx_signed['hex'])
209+
171210
def run_test(self):
172211
self.successful_signing_test()
173212
self.script_verification_error_test()

0 commit comments

Comments
 (0)