|
5 | 5 |
|
6 | 6 | from test_framework.test_framework import BitcoinTestFramework |
7 | 7 | from test_framework.util import * |
| 8 | +from test_framework.mininode import * |
| 9 | +from binascii import hexlify, unhexlify |
| 10 | +from cStringIO import StringIO |
8 | 11 |
|
9 | 12 | class DecodeScriptTest(BitcoinTestFramework): |
10 | 13 | """Tests decoding scripts via RPC command "decodescript".""" |
@@ -107,10 +110,77 @@ def decodescript_script_pub_key(self): |
107 | 110 | rpc_result = self.nodes[0].decodescript('63' + push_public_key + 'ad670320a107b17568' + push_public_key + 'ac') |
108 | 111 | assert_equal('OP_IF ' + public_key + ' OP_CHECKSIGVERIFY OP_ELSE 500000 OP_NOP2 OP_DROP OP_ENDIF ' + public_key + ' OP_CHECKSIG', rpc_result['asm']) |
109 | 112 |
|
| 113 | + def decoderawtransaction_asm_sighashtype(self): |
| 114 | + """Tests decoding scripts via RPC command "decoderawtransaction". |
| 115 | +
|
| 116 | + This test is in with the "decodescript" tests because they are testing the same "asm" script decodes. |
| 117 | + """ |
| 118 | + |
| 119 | + # this test case uses a random plain vanilla mainnet transaction with a single P2PKH input and output |
| 120 | + tx = '0100000001696a20784a2c70143f634e95227dbdfdf0ecd51647052e70854512235f5986ca010000008a47304402207174775824bec6c2700023309a168231ec80b82c6069282f5133e6f11cbb04460220570edc55c7c5da2ca687ebd0372d3546ebc3f810516a002350cac72dfe192dfb014104d3f898e6487787910a690410b7a917ef198905c27fb9d3b0a42da12aceae0544fc7088d239d9a48f2828a15a09e84043001f27cc80d162cb95404e1210161536ffffffff0100e1f505000000001976a914eb6c6e0cdb2d256a32d97b8df1fc75d1920d9bca88ac00000000' |
| 121 | + rpc_result = self.nodes[0].decoderawtransaction(tx) |
| 122 | + assert_equal('304402207174775824bec6c2700023309a168231ec80b82c6069282f5133e6f11cbb04460220570edc55c7c5da2ca687ebd0372d3546ebc3f810516a002350cac72dfe192dfb[ALL] 04d3f898e6487787910a690410b7a917ef198905c27fb9d3b0a42da12aceae0544fc7088d239d9a48f2828a15a09e84043001f27cc80d162cb95404e1210161536', rpc_result['vin'][0]['scriptSig']['asm']) |
| 123 | + |
| 124 | + # this test case uses a mainnet transaction that has a P2SH input and both P2PKH and P2SH outputs. |
| 125 | + # it's from James D'Angelo's awesome introductory videos about multisig: https://www.youtube.com/watch?v=zIbUSaZBJgU and https://www.youtube.com/watch?v=OSA1pwlaypc |
| 126 | + # verify that we have not altered scriptPubKey decoding. |
| 127 | + tx = '01000000018d1f5635abd06e2c7e2ddf58dc85b3de111e4ad6e0ab51bb0dcf5e84126d927300000000fdfe0000483045022100ae3b4e589dfc9d48cb82d41008dc5fa6a86f94d5c54f9935531924602730ab8002202f88cf464414c4ed9fa11b773c5ee944f66e9b05cc1e51d97abc22ce098937ea01483045022100b44883be035600e9328a01b66c7d8439b74db64187e76b99a68f7893b701d5380220225bf286493e4c4adcf928c40f785422572eb232f84a0b83b0dea823c3a19c75014c695221020743d44be989540d27b1b4bbbcfd17721c337cb6bc9af20eb8a32520b393532f2102c0120a1dda9e51a938d39ddd9fe0ebc45ea97e1d27a7cbd671d5431416d3dd87210213820eb3d5f509d7438c9eeecb4157b2f595105e7cd564b3cdbb9ead3da41eed53aeffffffff02611e0000000000001976a914dc863734a218bfe83ef770ee9d41a27f824a6e5688acee2a02000000000017a9142a5edea39971049a540474c6a99edf0aa4074c588700000000' |
| 128 | + rpc_result = self.nodes[0].decoderawtransaction(tx) |
| 129 | + assert_equal('8e3730608c3b0bb5df54f09076e196bc292a8e39a78e73b44b6ba08c78f5cbb0', rpc_result['txid']) |
| 130 | + assert_equal('0 3045022100ae3b4e589dfc9d48cb82d41008dc5fa6a86f94d5c54f9935531924602730ab8002202f88cf464414c4ed9fa11b773c5ee944f66e9b05cc1e51d97abc22ce098937ea[ALL] 3045022100b44883be035600e9328a01b66c7d8439b74db64187e76b99a68f7893b701d5380220225bf286493e4c4adcf928c40f785422572eb232f84a0b83b0dea823c3a19c75[ALL] 5221020743d44be989540d27b1b4bbbcfd17721c337cb6bc9af20eb8a32520b393532f2102c0120a1dda9e51a938d39ddd9fe0ebc45ea97e1d27a7cbd671d5431416d3dd87210213820eb3d5f509d7438c9eeecb4157b2f595105e7cd564b3cdbb9ead3da41eed53ae', rpc_result['vin'][0]['scriptSig']['asm']) |
| 131 | + assert_equal('OP_DUP OP_HASH160 dc863734a218bfe83ef770ee9d41a27f824a6e56 OP_EQUALVERIFY OP_CHECKSIG', rpc_result['vout'][0]['scriptPubKey']['asm']) |
| 132 | + assert_equal('OP_HASH160 2a5edea39971049a540474c6a99edf0aa4074c58 OP_EQUAL', rpc_result['vout'][1]['scriptPubKey']['asm']) |
| 133 | + txSave = CTransaction() |
| 134 | + txSave.deserialize(StringIO(unhexlify(tx))) |
| 135 | + |
| 136 | + # make sure that a specifically crafted op_return value will not pass all the IsDERSignature checks and then get decoded as a sighash type |
| 137 | + tx = '01000000015ded05872fdbda629c7d3d02b194763ce3b9b1535ea884e3c8e765d42e316724020000006b48304502204c10d4064885c42638cbff3585915b322de33762598321145ba033fc796971e2022100bb153ad3baa8b757e30a2175bd32852d2e1cb9080f84d7e32fcdfd667934ef1b012103163c0ff73511ea1743fb5b98384a2ff09dd06949488028fd819f4d83f56264efffffffff0200000000000000000b6a0930060201000201000180380100000000001976a9141cabd296e753837c086da7a45a6c2fe0d49d7b7b88ac00000000' |
| 138 | + rpc_result = self.nodes[0].decoderawtransaction(tx) |
| 139 | + assert_equal('OP_RETURN 300602010002010001', rpc_result['vout'][0]['scriptPubKey']['asm']) |
| 140 | + |
| 141 | + # 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 |
| 142 | + tx = '01000000018d1f5635abd06e2c7e2ddf58dc85b3de111e4ad6e0ab51bb0dcf5e84126d927300000000fdfe0000483045022100ae3b4e589dfc9d48cb82d41008dc5fa6a86f94d5c54f9935531924602730ab8002202f88cf464414c4ed9fa11b773c5ee944f66e9b05cc1e51d97abc22ce098937ea01483045022100b44883be035600e9328a01b66c7d8439b74db64187e76b99a68f7893b701d5380220225bf286493e4c4adcf928c40f785422572eb232f84a0b83b0dea823c3a19c75014c695221020743d44be989540d27b1b4bbbcfd17721c337cb6bc9af20eb8a32520b393532f2102c0120a1dda9e51a938d39ddd9fe0ebc45ea97e1d27a7cbd671d5431416d3dd87210213820eb3d5f509d7438c9eeecb4157b2f595105e7cd564b3cdbb9ead3da41eed53aeffffffff02611e0000000000001976a914301102070101010101010102060101010101010188acee2a02000000000017a91430110207010101010101010206010101010101018700000000' |
| 143 | + rpc_result = self.nodes[0].decoderawtransaction(tx) |
| 144 | + assert_equal('OP_DUP OP_HASH160 3011020701010101010101020601010101010101 OP_EQUALVERIFY OP_CHECKSIG', rpc_result['vout'][0]['scriptPubKey']['asm']) |
| 145 | + assert_equal('OP_HASH160 3011020701010101010101020601010101010101 OP_EQUAL', rpc_result['vout'][1]['scriptPubKey']['asm']) |
| 146 | + |
| 147 | + # some more full transaction tests of varying specific scriptSigs. used instead of |
| 148 | + # tests in decodescript_script_sig because the decodescript RPC is specifically |
| 149 | + # for working on scriptPubKeys (argh!). |
| 150 | + push_signature = hexlify(txSave.vin[0].scriptSig)[2:(0x48*2+4)] |
| 151 | + signature = push_signature[2:] |
| 152 | + der_signature = signature[:-2] |
| 153 | + signature_sighash_decoded = der_signature + '[ALL]' |
| 154 | + signature_2 = der_signature + '82' |
| 155 | + push_signature_2 = '48' + signature_2 |
| 156 | + signature_2_sighash_decoded = der_signature + '[NONE|ANYONECANPAY]' |
| 157 | + |
| 158 | + # 1) P2PK scriptSig |
| 159 | + txSave.vin[0].scriptSig = unhexlify(push_signature) |
| 160 | + rpc_result = self.nodes[0].decoderawtransaction(hexlify(txSave.serialize())) |
| 161 | + assert_equal(signature_sighash_decoded, rpc_result['vin'][0]['scriptSig']['asm']) |
| 162 | + |
| 163 | + # make sure that the sighash decodes come out correctly for a more complex / lesser used case. |
| 164 | + txSave.vin[0].scriptSig = unhexlify(push_signature_2) |
| 165 | + rpc_result = self.nodes[0].decoderawtransaction(hexlify(txSave.serialize())) |
| 166 | + assert_equal(signature_2_sighash_decoded, rpc_result['vin'][0]['scriptSig']['asm']) |
| 167 | + |
| 168 | + # 2) multisig scriptSig |
| 169 | + txSave.vin[0].scriptSig = unhexlify('00' + push_signature + push_signature_2) |
| 170 | + rpc_result = self.nodes[0].decoderawtransaction(hexlify(txSave.serialize())) |
| 171 | + assert_equal('0 ' + signature_sighash_decoded + ' ' + signature_2_sighash_decoded, rpc_result['vin'][0]['scriptSig']['asm']) |
| 172 | + |
| 173 | + # 3) test a scriptSig that contains more than push operations. |
| 174 | + # in fact, it contains an OP_RETURN with data specially crafted to cause improper decode if the code does not catch it. |
| 175 | + txSave.vin[0].scriptSig = unhexlify('6a143011020701010101010101020601010101010101') |
| 176 | + rpc_result = self.nodes[0].decoderawtransaction(hexlify(txSave.serialize())) |
| 177 | + print(hexlify('636174')) |
| 178 | + assert_equal('OP_RETURN 3011020701010101010101020601010101010101', rpc_result['vin'][0]['scriptSig']['asm']) |
| 179 | + |
110 | 180 | def run_test(self): |
111 | 181 | self.decodescript_script_sig() |
112 | 182 | self.decodescript_script_pub_key() |
| 183 | + self.decoderawtransaction_asm_sighashtype() |
113 | 184 |
|
114 | 185 | if __name__ == '__main__': |
115 | 186 | DecodeScriptTest().main() |
116 | | - |
|
0 commit comments