Skip to content

Commit fe03f7a

Browse files
author
MarcoFalke
committed
Merge bitcoin/bitcoin#23540: test: add decodescript RPC test for P2TR output script
83f6c0f test: add decodescript RPC test for P2TR output type (Sebastian Falbesoner) 099c695 test: check for decodescript RPC 'type' results (Sebastian Falbesoner) 0d43525 test: add logging to rpc_decodescript.py (Sebastian Falbesoner) Pull request description: This PR adds a functional sub-test for calling `decodescript` with a P2TR / segwit v1 output script (`OP_1 <32-bytes push>`), expecting to return "witness_v1_taproot" as `type` result. In the first two commits, the test `rpc_decodescript.py` is also improved by adding logging (plus getting rid of the enumerations) and also adding missing checks `type` result checks for all other output script types. ACKs for top commit: MarcoFalke: ACK 83f6c0f Tree-SHA512: 5fbfa693f711f55022edbc26109b076610ba248bef5282822656f5a2289636a5da6e2c1a4d8ab16a599af5701dafb3452e8be653d0e5f09e59ed87b8144d46ef
2 parents 606e306 + 83f6c0f commit fe03f7a

File tree

1 file changed

+46
-19
lines changed

1 file changed

+46
-19
lines changed

test/functional/rpc_decodescript.py

+46-19
Original file line numberDiff line numberDiff line change
@@ -27,29 +27,29 @@ def decodescript_script_sig(self):
2727

2828
# below are test cases for all of the standard transaction types
2929

30-
# 1) P2PK scriptSig
30+
self.log.info("- P2PK")
3131
# the scriptSig of a public key scriptPubKey simply pushes a signature onto the stack
3232
rpc_result = self.nodes[0].decodescript(push_signature)
3333
assert_equal(signature, rpc_result['asm'])
3434

35-
# 2) P2PKH scriptSig
35+
self.log.info("- P2PKH")
3636
rpc_result = self.nodes[0].decodescript(push_signature + push_public_key)
3737
assert_equal(signature + ' ' + public_key, rpc_result['asm'])
3838

39-
# 3) multisig scriptSig
39+
self.log.info("- multisig")
4040
# this also tests the leading portion of a P2SH multisig scriptSig
4141
# OP_0 <A sig> <B sig>
4242
rpc_result = self.nodes[0].decodescript('00' + push_signature + push_signature)
4343
assert_equal('0 ' + signature + ' ' + signature, rpc_result['asm'])
4444

45-
# 4) P2SH scriptSig
45+
self.log.info("- P2SH")
4646
# an empty P2SH redeemScript is valid and makes for a very simple test case.
4747
# thus, such a spending scriptSig would just need to pass the outer redeemScript
4848
# hash test and leave true on the top of the stack.
4949
rpc_result = self.nodes[0].decodescript('5100')
5050
assert_equal('1 0', rpc_result['asm'])
5151

52-
# 5) null data scriptSig - no such thing because null data scripts can not be spent.
52+
# null data scriptSig - no such thing because null data scripts can not be spent.
5353
# thus, no test case for that standard transaction type is here.
5454

5555
def decodescript_script_pub_key(self):
@@ -63,50 +63,58 @@ def decodescript_script_pub_key(self):
6363

6464
# below are test cases for all of the standard transaction types
6565

66-
# 1) P2PK scriptPubKey
66+
self.log.info("- P2PK")
6767
# <pubkey> OP_CHECKSIG
6868
rpc_result = self.nodes[0].decodescript(push_public_key + 'ac')
6969
assert_equal(public_key + ' OP_CHECKSIG', rpc_result['asm'])
70+
assert_equal('pubkey', rpc_result['type'])
7071
# P2PK is translated to P2WPKH
7172
assert_equal('0 ' + public_key_hash, rpc_result['segwit']['asm'])
7273

73-
# 2) P2PKH scriptPubKey
74+
self.log.info("- P2PKH")
7475
# OP_DUP OP_HASH160 <PubKeyHash> OP_EQUALVERIFY OP_CHECKSIG
7576
rpc_result = self.nodes[0].decodescript('76a9' + push_public_key_hash + '88ac')
77+
assert_equal('pubkeyhash', rpc_result['type'])
7678
assert_equal('OP_DUP OP_HASH160 ' + public_key_hash + ' OP_EQUALVERIFY OP_CHECKSIG', rpc_result['asm'])
7779
# P2PKH is translated to P2WPKH
80+
assert_equal('witness_v0_keyhash', rpc_result['segwit']['type'])
7881
assert_equal('0 ' + public_key_hash, rpc_result['segwit']['asm'])
7982

80-
# 3) multisig scriptPubKey
83+
self.log.info("- multisig")
8184
# <m> <A pubkey> <B pubkey> <C pubkey> <n> OP_CHECKMULTISIG
8285
# just imagine that the pub keys used below are different.
8386
# for our purposes here it does not matter that they are the same even though it is unrealistic.
8487
multisig_script = '52' + push_public_key + push_public_key + push_public_key + '53ae'
8588
rpc_result = self.nodes[0].decodescript(multisig_script)
89+
assert_equal('multisig', rpc_result['type'])
8690
assert_equal('2 ' + public_key + ' ' + public_key + ' ' + public_key + ' 3 OP_CHECKMULTISIG', rpc_result['asm'])
8791
# multisig in P2WSH
8892
multisig_script_hash = sha256(bytes.fromhex(multisig_script)).hex()
93+
assert_equal('witness_v0_scripthash', rpc_result['segwit']['type'])
8994
assert_equal('0 ' + multisig_script_hash, rpc_result['segwit']['asm'])
9095

91-
# 4) P2SH scriptPubKey
96+
self.log.info ("- P2SH")
9297
# OP_HASH160 <Hash160(redeemScript)> OP_EQUAL.
9398
# push_public_key_hash here should actually be the hash of a redeem script.
9499
# but this works the same for purposes of this test.
95100
rpc_result = self.nodes[0].decodescript('a9' + push_public_key_hash + '87')
101+
assert_equal('scripthash', rpc_result['type'])
96102
assert_equal('OP_HASH160 ' + public_key_hash + ' OP_EQUAL', rpc_result['asm'])
97103
# P2SH does not work in segwit secripts. decodescript should not return a result for it.
98104
assert 'segwit' not in rpc_result
99105

100-
# 5) null data scriptPubKey
106+
self.log.info("- null data")
101107
# use a signature look-alike here to make sure that we do not decode random data as a signature.
102108
# this matters if/when signature sighash decoding comes along.
103109
# would want to make sure that no such decoding takes place in this case.
104110
signature_imposter = '48304502207fa7a6d1e0ee81132a269ad84e68d695483745cde8b541e3bf630749894e342a022100c1f7ab20e13e22fb95281a870f3dcf38d782e53023ee313d741ad0cfbc0c509001'
105111
# OP_RETURN <data>
106112
rpc_result = self.nodes[0].decodescript('6a' + signature_imposter)
113+
assert_equal('nulldata', rpc_result['type'])
107114
assert_equal('OP_RETURN ' + signature_imposter[2:], rpc_result['asm'])
108115

109-
# 6) a CLTV redeem script. redeem scripts are in-effect scriptPubKey scripts, so adding a test here.
116+
self.log.info("- CLTV redeem script")
117+
# redeem scripts are in-effect scriptPubKey scripts, so adding a test here.
110118
# OP_NOP2 is also known as OP_CHECKLOCKTIMEVERIFY.
111119
# just imagine that the pub keys used below are different.
112120
# for our purposes here it does not matter that they are the same even though it is unrealistic.
@@ -121,55 +129,69 @@ def decodescript_script_pub_key(self):
121129
# lock until block 500,000
122130
cltv_script = '63' + push_public_key + 'ad670320a107b17568' + push_public_key + 'ac'
123131
rpc_result = self.nodes[0].decodescript(cltv_script)
132+
assert_equal('nonstandard', rpc_result['type'])
124133
assert_equal('OP_IF ' + public_key + ' OP_CHECKSIGVERIFY OP_ELSE 500000 OP_CHECKLOCKTIMEVERIFY OP_DROP OP_ENDIF ' + public_key + ' OP_CHECKSIG', rpc_result['asm'])
125134
# CLTV script in P2WSH
126135
cltv_script_hash = sha256(bytes.fromhex(cltv_script)).hex()
127136
assert_equal('0 ' + cltv_script_hash, rpc_result['segwit']['asm'])
128137

129-
# 7) P2PK scriptPubKey
138+
self.log.info("- P2PK with uncompressed pubkey")
130139
# <pubkey> OP_CHECKSIG
131140
rpc_result = self.nodes[0].decodescript(push_uncompressed_public_key + 'ac')
141+
assert_equal('pubkey', rpc_result['type'])
132142
assert_equal(uncompressed_public_key + ' OP_CHECKSIG', rpc_result['asm'])
133143
# uncompressed pubkeys are invalid for checksigs in segwit scripts.
134144
# decodescript should not return a P2WPKH equivalent.
135145
assert 'segwit' not in rpc_result
136146

137-
# 8) multisig scriptPubKey with an uncompressed pubkey
147+
self.log.info("- multisig with uncompressed pubkey")
138148
# <m> <A pubkey> <B pubkey> <n> OP_CHECKMULTISIG
139149
# just imagine that the pub keys used below are different.
140150
# the purpose of this test is to check that a segwit script is not returned for bare multisig scripts
141151
# with an uncompressed pubkey in them.
142152
rpc_result = self.nodes[0].decodescript('52' + push_public_key + push_uncompressed_public_key +'52ae')
153+
assert_equal('multisig', rpc_result['type'])
143154
assert_equal('2 ' + public_key + ' ' + uncompressed_public_key + ' 2 OP_CHECKMULTISIG', rpc_result['asm'])
144155
# uncompressed pubkeys are invalid for checksigs in segwit scripts.
145156
# decodescript should not return a P2WPKH equivalent.
146157
assert 'segwit' not in rpc_result
147158

148-
# 9) P2WPKH scriptpubkey
159+
self.log.info("- P2WPKH")
149160
# 0 <PubKeyHash>
150161
rpc_result = self.nodes[0].decodescript('00' + push_public_key_hash)
162+
assert_equal('witness_v0_keyhash', rpc_result['type'])
151163
assert_equal('0 ' + public_key_hash, rpc_result['asm'])
152164
# segwit scripts do not work nested into each other.
153165
# a nested segwit script should not be returned in the results.
154166
assert 'segwit' not in rpc_result
155167

156-
# 10) P2WSH scriptpubkey
168+
self.log.info("- P2WSH")
157169
# 0 <ScriptHash>
158170
# even though this hash is of a P2PK script which is better used as bare P2WPKH, it should not matter
159171
# for the purpose of this test.
160172
rpc_result = self.nodes[0].decodescript('0020' + p2wsh_p2pk_script_hash)
173+
assert_equal('witness_v0_scripthash', rpc_result['type'])
161174
assert_equal('0 ' + p2wsh_p2pk_script_hash, rpc_result['asm'])
162175
# segwit scripts do not work nested into each other.
163176
# a nested segwit script should not be returned in the results.
164177
assert 'segwit' not in rpc_result
165178

179+
self.log.info("- P2TR")
180+
# 1 <x-only pubkey>
181+
xonly_public_key = '01'*32 # first ever P2TR output on mainnet
182+
rpc_result = self.nodes[0].decodescript('5120' + xonly_public_key)
183+
assert_equal('witness_v1_taproot', rpc_result['type'])
184+
assert_equal('1 ' + xonly_public_key, rpc_result['asm'])
185+
assert 'segwit' not in rpc_result
186+
166187
def decoderawtransaction_asm_sighashtype(self):
167188
"""Test decoding scripts via RPC command "decoderawtransaction".
168189
169190
This test is in with the "decodescript" tests because they are testing the same "asm" script decodes.
170191
"""
171192

172-
# this test case uses a random plain vanilla mainnet transaction with a single P2PKH input and output
193+
self.log.info("- various mainnet txs")
194+
# this test case uses a mainnet transaction that has a P2SH input and both P2PKH and P2SH outputs.
173195
tx = '0100000001696a20784a2c70143f634e95227dbdfdf0ecd51647052e70854512235f5986ca010000008a47304402207174775824bec6c2700023309a168231ec80b82c6069282f5133e6f11cbb04460220570edc55c7c5da2ca687ebd0372d3546ebc3f810516a002350cac72dfe192dfb014104d3f898e6487787910a690410b7a917ef198905c27fb9d3b0a42da12aceae0544fc7088d239d9a48f2828a15a09e84043001f27cc80d162cb95404e1210161536ffffffff0100e1f505000000001976a914eb6c6e0cdb2d256a32d97b8df1fc75d1920d9bca88ac00000000'
174196
rpc_result = self.nodes[0].decoderawtransaction(tx)
175197
assert_equal('304402207174775824bec6c2700023309a168231ec80b82c6069282f5133e6f11cbb04460220570edc55c7c5da2ca687ebd0372d3546ebc3f810516a002350cac72dfe192dfb[ALL] 04d3f898e6487787910a690410b7a917ef198905c27fb9d3b0a42da12aceae0544fc7088d239d9a48f2828a15a09e84043001f27cc80d162cb95404e1210161536', rpc_result['vin'][0]['scriptSig']['asm'])
@@ -185,11 +207,13 @@ def decoderawtransaction_asm_sighashtype(self):
185207
assert_equal('OP_HASH160 2a5edea39971049a540474c6a99edf0aa4074c58 OP_EQUAL', rpc_result['vout'][1]['scriptPubKey']['asm'])
186208
txSave = tx_from_hex(tx)
187209

210+
self.log.info("- tx not passing DER signature checks")
188211
# make sure that a specifically crafted op_return value will not pass all the IsDERSignature checks and then get decoded as a sighash type
189212
tx = '01000000015ded05872fdbda629c7d3d02b194763ce3b9b1535ea884e3c8e765d42e316724020000006b48304502204c10d4064885c42638cbff3585915b322de33762598321145ba033fc796971e2022100bb153ad3baa8b757e30a2175bd32852d2e1cb9080f84d7e32fcdfd667934ef1b012103163c0ff73511ea1743fb5b98384a2ff09dd06949488028fd819f4d83f56264efffffffff0200000000000000000b6a0930060201000201000180380100000000001976a9141cabd296e753837c086da7a45a6c2fe0d49d7b7b88ac00000000'
190213
rpc_result = self.nodes[0].decoderawtransaction(tx)
191214
assert_equal('OP_RETURN 300602010002010001', rpc_result['vout'][0]['scriptPubKey']['asm'])
192215

216+
self.log.info("- tx passing DER signature checks")
193217
# verify that we have not altered scriptPubKey processing even of a specially crafted P2PKH pubkeyhash and P2SH redeem script hash that is made to pass the der signature checks
194218
tx = '01000000018d1f5635abd06e2c7e2ddf58dc85b3de111e4ad6e0ab51bb0dcf5e84126d927300000000fdfe0000483045022100ae3b4e589dfc9d48cb82d41008dc5fa6a86f94d5c54f9935531924602730ab8002202f88cf464414c4ed9fa11b773c5ee944f66e9b05cc1e51d97abc22ce098937ea01483045022100b44883be035600e9328a01b66c7d8439b74db64187e76b99a68f7893b701d5380220225bf286493e4c4adcf928c40f785422572eb232f84a0b83b0dea823c3a19c75014c695221020743d44be989540d27b1b4bbbcfd17721c337cb6bc9af20eb8a32520b393532f2102c0120a1dda9e51a938d39ddd9fe0ebc45ea97e1d27a7cbd671d5431416d3dd87210213820eb3d5f509d7438c9eeecb4157b2f595105e7cd564b3cdbb9ead3da41eed53aeffffffff02611e0000000000001976a914301102070101010101010102060101010101010188acee2a02000000000017a91430110207010101010101010206010101010101018700000000'
195219
rpc_result = self.nodes[0].decoderawtransaction(tx)
@@ -207,7 +231,7 @@ def decoderawtransaction_asm_sighashtype(self):
207231
push_signature_2 = '48' + signature_2
208232
signature_2_sighash_decoded = der_signature + '[NONE|ANYONECANPAY]'
209233

210-
# 1) P2PK scriptSig
234+
self.log.info("- P2PK scriptSig")
211235
txSave.vin[0].scriptSig = bytes.fromhex(push_signature)
212236
rpc_result = self.nodes[0].decoderawtransaction(txSave.serialize().hex())
213237
assert_equal(signature_sighash_decoded, rpc_result['vin'][0]['scriptSig']['asm'])
@@ -217,20 +241,23 @@ def decoderawtransaction_asm_sighashtype(self):
217241
rpc_result = self.nodes[0].decoderawtransaction(txSave.serialize().hex())
218242
assert_equal(signature_2_sighash_decoded, rpc_result['vin'][0]['scriptSig']['asm'])
219243

220-
# 2) multisig scriptSig
244+
self.log.info("- multisig scriptSig")
221245
txSave.vin[0].scriptSig = bytes.fromhex('00' + push_signature + push_signature_2)
222246
rpc_result = self.nodes[0].decoderawtransaction(txSave.serialize().hex())
223247
assert_equal('0 ' + signature_sighash_decoded + ' ' + signature_2_sighash_decoded, rpc_result['vin'][0]['scriptSig']['asm'])
224248

225-
# 3) test a scriptSig that contains more than push operations.
249+
self.log.info("- scriptSig that contains more than push operations")
226250
# in fact, it contains an OP_RETURN with data specially crafted to cause improper decode if the code does not catch it.
227251
txSave.vin[0].scriptSig = bytes.fromhex('6a143011020701010101010101020601010101010101')
228252
rpc_result = self.nodes[0].decoderawtransaction(txSave.serialize().hex())
229253
assert_equal('OP_RETURN 3011020701010101010101020601010101010101', rpc_result['vin'][0]['scriptSig']['asm'])
230254

231255
def run_test(self):
256+
self.log.info("Test decoding of standard input scripts [scriptSig]")
232257
self.decodescript_script_sig()
258+
self.log.info("Test decoding of standard output scripts [scriptPubKey]")
233259
self.decodescript_script_pub_key()
260+
self.log.info("Test 'asm' script decoding of transactions")
234261
self.decoderawtransaction_asm_sighashtype()
235262

236263
if __name__ == '__main__':

0 commit comments

Comments
 (0)