Skip to content

Commit eac067a

Browse files
committed
Merge #12321: p2wsh and p2sh-p2wsh address in decodescript
41ff967 list the types of scripts we should consider for a witness program (fivepiece) 4f933b3 p2wpkh, p2wsh and p2sh-nested scripts in decodescript (fivepiece) Pull request description: Attempts to address #12244 . `p2wsh` addresses are returned only for scripts that are neither `p2sh` nor any witness program. Tree-SHA512: eb47f094c1a4c2ad2bcf27a8032307e43cf787d50bf739281aeb4101d97316a2f307b05118bf138298c937fa34e15f91436443a9b313f809fad2c43e94cd1831
2 parents 6f8b345 + 41ff967 commit eac067a

File tree

2 files changed

+89
-3
lines changed

2 files changed

+89
-3
lines changed

src/rpc/rawtransaction.cpp

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -614,6 +614,38 @@ UniValue decodescript(const JSONRPCRequest& request)
614614
// P2SH cannot be wrapped in a P2SH. If this script is already a P2SH,
615615
// don't return the address for a P2SH of the P2SH.
616616
r.pushKV("p2sh", EncodeDestination(CScriptID(script)));
617+
// P2SH and witness programs cannot be wrapped in P2WSH, if this script
618+
// is a witness program, don't return addresses for a segwit programs.
619+
if (type.get_str() == "pubkey" || type.get_str() == "pubkeyhash" || type.get_str() == "multisig" || type.get_str() == "nonstandard") {
620+
txnouttype which_type;
621+
std::vector<std::vector<unsigned char>> solutions_data;
622+
Solver(script, which_type, solutions_data);
623+
// Uncompressed pubkeys cannot be used with segwit checksigs.
624+
// If the script contains an uncompressed pubkey, skip encoding of a segwit program.
625+
if ((which_type == TX_PUBKEY) || (which_type == TX_MULTISIG)) {
626+
for (const auto& solution : solutions_data) {
627+
if ((solution.size() != 1) && !CPubKey(solution).IsCompressed()) {
628+
return r;
629+
}
630+
}
631+
}
632+
UniValue sr(UniValue::VOBJ);
633+
CScript segwitScr;
634+
if (which_type == TX_PUBKEY) {
635+
segwitScr = GetScriptForDestination(WitnessV0KeyHash(Hash160(solutions_data[0].begin(), solutions_data[0].end())));
636+
} else if (which_type == TX_PUBKEYHASH) {
637+
segwitScr = GetScriptForDestination(WitnessV0KeyHash(solutions_data[0]));
638+
} else {
639+
// Scripts that are not fit for P2WPKH are encoded as P2WSH.
640+
// Newer segwit program versions should be considered when then become available.
641+
uint256 scriptHash;
642+
CSHA256().Write(script.data(), script.size()).Finalize(scriptHash.begin());
643+
segwitScr = GetScriptForDestination(WitnessV0ScriptHash(scriptHash));
644+
}
645+
ScriptPubKeyToUniv(segwitScr, sr, true);
646+
sr.pushKV("p2sh-segwit", EncodeDestination(CScriptID(segwitScr)));
647+
r.pushKV("segwit", sr);
648+
}
617649
}
618650

619651
return r;

test/functional/rpc_decodescript.py

Lines changed: 57 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,34 +50,47 @@ def decodescript_script_sig(self):
5050
def decodescript_script_pub_key(self):
5151
public_key = '03b0da749730dc9b4b1f4a14d6902877a92541f5368778853d9c4a0cb7802dcfb2'
5252
push_public_key = '21' + public_key
53-
public_key_hash = '11695b6cd891484c2d49ec5aa738ec2b2f897777'
53+
public_key_hash = '5dd1d3a048119c27b28293056724d9522f26d945'
5454
push_public_key_hash = '14' + public_key_hash
55+
uncompressed_public_key = '04b0da749730dc9b4b1f4a14d6902877a92541f5368778853d9c4a0cb7802dcfb25e01fc8fde47c96c98a4f3a8123e33a38a50cf9025cc8c4494a518f991792bb7'
56+
push_uncompressed_public_key = '41' + uncompressed_public_key
57+
p2wsh_p2pk_script_hash = 'd8590cf8ea0674cf3d49fd7ca249b85ef7485dea62c138468bddeb20cd6519f7'
5558

5659
# below are test cases for all of the standard transaction types
5760

5861
# 1) P2PK scriptPubKey
5962
# <pubkey> OP_CHECKSIG
6063
rpc_result = self.nodes[0].decodescript(push_public_key + 'ac')
6164
assert_equal(public_key + ' OP_CHECKSIG', rpc_result['asm'])
65+
# P2PK is translated to P2WPKH
66+
assert_equal('0 ' + public_key_hash, rpc_result['segwit']['asm'])
6267

6368
# 2) P2PKH scriptPubKey
6469
# OP_DUP OP_HASH160 <PubKeyHash> OP_EQUALVERIFY OP_CHECKSIG
6570
rpc_result = self.nodes[0].decodescript('76a9' + push_public_key_hash + '88ac')
6671
assert_equal('OP_DUP OP_HASH160 ' + public_key_hash + ' OP_EQUALVERIFY OP_CHECKSIG', rpc_result['asm'])
72+
# P2PKH is translated to P2WPKH
73+
assert_equal('0 ' + public_key_hash, rpc_result['segwit']['asm'])
6774

6875
# 3) multisig scriptPubKey
6976
# <m> <A pubkey> <B pubkey> <C pubkey> <n> OP_CHECKMULTISIG
7077
# just imagine that the pub keys used below are different.
7178
# for our purposes here it does not matter that they are the same even though it is unrealistic.
72-
rpc_result = self.nodes[0].decodescript('52' + push_public_key + push_public_key + push_public_key + '53ae')
79+
multisig_script = '52' + push_public_key + push_public_key + push_public_key + '53ae'
80+
rpc_result = self.nodes[0].decodescript(multisig_script)
7381
assert_equal('2 ' + public_key + ' ' + public_key + ' ' + public_key + ' 3 OP_CHECKMULTISIG', rpc_result['asm'])
82+
# multisig in P2WSH
83+
multisig_script_hash = bytes_to_hex_str(sha256(hex_str_to_bytes(multisig_script)))
84+
assert_equal('0 ' + multisig_script_hash, rpc_result['segwit']['asm'])
7485

7586
# 4) P2SH scriptPubKey
7687
# OP_HASH160 <Hash160(redeemScript)> OP_EQUAL.
7788
# push_public_key_hash here should actually be the hash of a redeem script.
7889
# but this works the same for purposes of this test.
7990
rpc_result = self.nodes[0].decodescript('a9' + push_public_key_hash + '87')
8091
assert_equal('OP_HASH160 ' + public_key_hash + ' OP_EQUAL', rpc_result['asm'])
92+
# P2SH does not work in segwit secripts. decodescript should not return a result for it.
93+
assert 'segwit' not in rpc_result
8194

8295
# 5) null data scriptPubKey
8396
# use a signature look-alike here to make sure that we do not decode random data as a signature.
@@ -101,8 +114,49 @@ def decodescript_script_pub_key(self):
101114
# <sender-pubkey> OP_CHECKSIG
102115
#
103116
# lock until block 500,000
104-
rpc_result = self.nodes[0].decodescript('63' + push_public_key + 'ad670320a107b17568' + push_public_key + 'ac')
117+
cltv_script = '63' + push_public_key + 'ad670320a107b17568' + push_public_key + 'ac'
118+
rpc_result = self.nodes[0].decodescript(cltv_script)
105119
assert_equal('OP_IF ' + public_key + ' OP_CHECKSIGVERIFY OP_ELSE 500000 OP_CHECKLOCKTIMEVERIFY OP_DROP OP_ENDIF ' + public_key + ' OP_CHECKSIG', rpc_result['asm'])
120+
# CLTV script in P2WSH
121+
cltv_script_hash = bytes_to_hex_str(sha256(hex_str_to_bytes(cltv_script)))
122+
assert_equal('0 ' + cltv_script_hash, rpc_result['segwit']['asm'])
123+
124+
# 7) P2PK scriptPubKey
125+
# <pubkey> OP_CHECKSIG
126+
rpc_result = self.nodes[0].decodescript(push_uncompressed_public_key + 'ac')
127+
assert_equal(uncompressed_public_key + ' OP_CHECKSIG', rpc_result['asm'])
128+
# uncompressed pubkeys are invalid for checksigs in segwit scripts.
129+
# decodescript should not return a P2WPKH equivalent.
130+
assert 'segwit' not in rpc_result
131+
132+
# 8) multisig scriptPubKey with an uncompressed pubkey
133+
# <m> <A pubkey> <B pubkey> <n> OP_CHECKMULTISIG
134+
# just imagine that the pub keys used below are different.
135+
# the purpose of this test is to check that a segwit script is not returned for bare multisig scripts
136+
# with an uncompressed pubkey in them.
137+
rpc_result = self.nodes[0].decodescript('52' + push_public_key + push_uncompressed_public_key +'52ae')
138+
assert_equal('2 ' + public_key + ' ' + uncompressed_public_key + ' 2 OP_CHECKMULTISIG', rpc_result['asm'])
139+
# uncompressed pubkeys are invalid for checksigs in segwit scripts.
140+
# decodescript should not return a P2WPKH equivalent.
141+
assert 'segwit' not in rpc_result
142+
143+
# 9) P2WPKH scriptpubkey
144+
# 0 <PubKeyHash>
145+
rpc_result = self.nodes[0].decodescript('00' + push_public_key_hash)
146+
assert_equal('0 ' + public_key_hash, rpc_result['asm'])
147+
# segwit scripts do not work nested into each other.
148+
# a nested segwit script should not be returned in the results.
149+
assert 'segwit' not in rpc_result
150+
151+
# 10) P2WSH scriptpubkey
152+
# 0 <ScriptHash>
153+
# even though this hash is of a P2PK script which is better used as bare P2WPKH, it should not matter
154+
# for the purpose of this test.
155+
rpc_result = self.nodes[0].decodescript('0020' + p2wsh_p2pk_script_hash)
156+
assert_equal('0 ' + p2wsh_p2pk_script_hash, rpc_result['asm'])
157+
# segwit scripts do not work nested into each other.
158+
# a nested segwit script should not be returned in the results.
159+
assert 'segwit' not in rpc_result
106160

107161
def decoderawtransaction_asm_sighashtype(self):
108162
"""Test decoding scripts via RPC command "decoderawtransaction".

0 commit comments

Comments
 (0)