aboutsummaryrefslogtreecommitdiff
path: root/qa
diff options
context:
space:
mode:
authormruddy <mruddy@users.noreply.github.com>2015-07-30 19:56:00 -0400
committermruddy <mruddy@users.noreply.github.com>2015-07-30 19:56:00 -0400
commitaf3208bfa6967d6b35aecf0ba35d9d6bf0f8317e (patch)
treef61b271e4446dae05172096c63d9320f4dbcaf2d /qa
parent675d2feffa84a6ffeabac32aeed37f6a7f74bee3 (diff)
downloadbitcoin-af3208bfa6967d6b35aecf0ba35d9d6bf0f8317e.tar.xz
Resolve issue 3166.
These changes decode valid SIGHASH types on signatures in assembly (asm) representations of scriptSig scripts. This squashed commit incorporates substantial helpful feedback from jtimon, laanwj, and sipa.
Diffstat (limited to 'qa')
-rwxr-xr-xqa/rpc-tests/decodescript.py72
1 files changed, 71 insertions, 1 deletions
diff --git a/qa/rpc-tests/decodescript.py b/qa/rpc-tests/decodescript.py
index ce3bc94ef7..4bca623380 100755
--- a/qa/rpc-tests/decodescript.py
+++ b/qa/rpc-tests/decodescript.py
@@ -5,6 +5,9 @@
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import *
+from test_framework.mininode import *
+from binascii import hexlify, unhexlify
+from cStringIO import StringIO
class DecodeScriptTest(BitcoinTestFramework):
"""Tests decoding scripts via RPC command "decodescript"."""
@@ -107,10 +110,77 @@ class DecodeScriptTest(BitcoinTestFramework):
rpc_result = self.nodes[0].decodescript('63' + push_public_key + 'ad670320a107b17568' + push_public_key + 'ac')
assert_equal('OP_IF ' + public_key + ' OP_CHECKSIGVERIFY OP_ELSE 500000 OP_NOP2 OP_DROP OP_ENDIF ' + public_key + ' OP_CHECKSIG', rpc_result['asm'])
+ def decoderawtransaction_asm_sighashtype(self):
+ """Tests decoding scripts via RPC command "decoderawtransaction".
+
+ This test is in with the "decodescript" tests because they are testing the same "asm" script decodes.
+ """
+
+ # this test case uses a random plain vanilla mainnet transaction with a single P2PKH input and output
+ tx = '0100000001696a20784a2c70143f634e95227dbdfdf0ecd51647052e70854512235f5986ca010000008a47304402207174775824bec6c2700023309a168231ec80b82c6069282f5133e6f11cbb04460220570edc55c7c5da2ca687ebd0372d3546ebc3f810516a002350cac72dfe192dfb014104d3f898e6487787910a690410b7a917ef198905c27fb9d3b0a42da12aceae0544fc7088d239d9a48f2828a15a09e84043001f27cc80d162cb95404e1210161536ffffffff0100e1f505000000001976a914eb6c6e0cdb2d256a32d97b8df1fc75d1920d9bca88ac00000000'
+ rpc_result = self.nodes[0].decoderawtransaction(tx)
+ assert_equal('304402207174775824bec6c2700023309a168231ec80b82c6069282f5133e6f11cbb04460220570edc55c7c5da2ca687ebd0372d3546ebc3f810516a002350cac72dfe192dfb[ALL] 04d3f898e6487787910a690410b7a917ef198905c27fb9d3b0a42da12aceae0544fc7088d239d9a48f2828a15a09e84043001f27cc80d162cb95404e1210161536', rpc_result['vin'][0]['scriptSig']['asm'])
+
+ # this test case uses a mainnet transaction that has a P2SH input and both P2PKH and P2SH outputs.
+ # 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
+ # verify that we have not altered scriptPubKey decoding.
+ tx = '01000000018d1f5635abd06e2c7e2ddf58dc85b3de111e4ad6e0ab51bb0dcf5e84126d927300000000fdfe0000483045022100ae3b4e589dfc9d48cb82d41008dc5fa6a86f94d5c54f9935531924602730ab8002202f88cf464414c4ed9fa11b773c5ee944f66e9b05cc1e51d97abc22ce098937ea01483045022100b44883be035600e9328a01b66c7d8439b74db64187e76b99a68f7893b701d5380220225bf286493e4c4adcf928c40f785422572eb232f84a0b83b0dea823c3a19c75014c695221020743d44be989540d27b1b4bbbcfd17721c337cb6bc9af20eb8a32520b393532f2102c0120a1dda9e51a938d39ddd9fe0ebc45ea97e1d27a7cbd671d5431416d3dd87210213820eb3d5f509d7438c9eeecb4157b2f595105e7cd564b3cdbb9ead3da41eed53aeffffffff02611e0000000000001976a914dc863734a218bfe83ef770ee9d41a27f824a6e5688acee2a02000000000017a9142a5edea39971049a540474c6a99edf0aa4074c588700000000'
+ rpc_result = self.nodes[0].decoderawtransaction(tx)
+ assert_equal('8e3730608c3b0bb5df54f09076e196bc292a8e39a78e73b44b6ba08c78f5cbb0', rpc_result['txid'])
+ assert_equal('0 3045022100ae3b4e589dfc9d48cb82d41008dc5fa6a86f94d5c54f9935531924602730ab8002202f88cf464414c4ed9fa11b773c5ee944f66e9b05cc1e51d97abc22ce098937ea[ALL] 3045022100b44883be035600e9328a01b66c7d8439b74db64187e76b99a68f7893b701d5380220225bf286493e4c4adcf928c40f785422572eb232f84a0b83b0dea823c3a19c75[ALL] 5221020743d44be989540d27b1b4bbbcfd17721c337cb6bc9af20eb8a32520b393532f2102c0120a1dda9e51a938d39ddd9fe0ebc45ea97e1d27a7cbd671d5431416d3dd87210213820eb3d5f509d7438c9eeecb4157b2f595105e7cd564b3cdbb9ead3da41eed53ae', rpc_result['vin'][0]['scriptSig']['asm'])
+ assert_equal('OP_DUP OP_HASH160 dc863734a218bfe83ef770ee9d41a27f824a6e56 OP_EQUALVERIFY OP_CHECKSIG', rpc_result['vout'][0]['scriptPubKey']['asm'])
+ assert_equal('OP_HASH160 2a5edea39971049a540474c6a99edf0aa4074c58 OP_EQUAL', rpc_result['vout'][1]['scriptPubKey']['asm'])
+ txSave = CTransaction()
+ txSave.deserialize(StringIO(unhexlify(tx)))
+
+ # make sure that a specifically crafted op_return value will not pass all the IsDERSignature checks and then get decoded as a sighash type
+ tx = '01000000015ded05872fdbda629c7d3d02b194763ce3b9b1535ea884e3c8e765d42e316724020000006b48304502204c10d4064885c42638cbff3585915b322de33762598321145ba033fc796971e2022100bb153ad3baa8b757e30a2175bd32852d2e1cb9080f84d7e32fcdfd667934ef1b012103163c0ff73511ea1743fb5b98384a2ff09dd06949488028fd819f4d83f56264efffffffff0200000000000000000b6a0930060201000201000180380100000000001976a9141cabd296e753837c086da7a45a6c2fe0d49d7b7b88ac00000000'
+ rpc_result = self.nodes[0].decoderawtransaction(tx)
+ assert_equal('OP_RETURN 300602010002010001', rpc_result['vout'][0]['scriptPubKey']['asm'])
+
+ # 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
+ tx = '01000000018d1f5635abd06e2c7e2ddf58dc85b3de111e4ad6e0ab51bb0dcf5e84126d927300000000fdfe0000483045022100ae3b4e589dfc9d48cb82d41008dc5fa6a86f94d5c54f9935531924602730ab8002202f88cf464414c4ed9fa11b773c5ee944f66e9b05cc1e51d97abc22ce098937ea01483045022100b44883be035600e9328a01b66c7d8439b74db64187e76b99a68f7893b701d5380220225bf286493e4c4adcf928c40f785422572eb232f84a0b83b0dea823c3a19c75014c695221020743d44be989540d27b1b4bbbcfd17721c337cb6bc9af20eb8a32520b393532f2102c0120a1dda9e51a938d39ddd9fe0ebc45ea97e1d27a7cbd671d5431416d3dd87210213820eb3d5f509d7438c9eeecb4157b2f595105e7cd564b3cdbb9ead3da41eed53aeffffffff02611e0000000000001976a914301102070101010101010102060101010101010188acee2a02000000000017a91430110207010101010101010206010101010101018700000000'
+ rpc_result = self.nodes[0].decoderawtransaction(tx)
+ assert_equal('OP_DUP OP_HASH160 3011020701010101010101020601010101010101 OP_EQUALVERIFY OP_CHECKSIG', rpc_result['vout'][0]['scriptPubKey']['asm'])
+ assert_equal('OP_HASH160 3011020701010101010101020601010101010101 OP_EQUAL', rpc_result['vout'][1]['scriptPubKey']['asm'])
+
+ # some more full transaction tests of varying specific scriptSigs. used instead of
+ # tests in decodescript_script_sig because the decodescript RPC is specifically
+ # for working on scriptPubKeys (argh!).
+ push_signature = hexlify(txSave.vin[0].scriptSig)[2:(0x48*2+4)]
+ signature = push_signature[2:]
+ der_signature = signature[:-2]
+ signature_sighash_decoded = der_signature + '[ALL]'
+ signature_2 = der_signature + '82'
+ push_signature_2 = '48' + signature_2
+ signature_2_sighash_decoded = der_signature + '[NONE|ANYONECANPAY]'
+
+ # 1) P2PK scriptSig
+ txSave.vin[0].scriptSig = unhexlify(push_signature)
+ rpc_result = self.nodes[0].decoderawtransaction(hexlify(txSave.serialize()))
+ assert_equal(signature_sighash_decoded, rpc_result['vin'][0]['scriptSig']['asm'])
+
+ # make sure that the sighash decodes come out correctly for a more complex / lesser used case.
+ txSave.vin[0].scriptSig = unhexlify(push_signature_2)
+ rpc_result = self.nodes[0].decoderawtransaction(hexlify(txSave.serialize()))
+ assert_equal(signature_2_sighash_decoded, rpc_result['vin'][0]['scriptSig']['asm'])
+
+ # 2) multisig scriptSig
+ txSave.vin[0].scriptSig = unhexlify('00' + push_signature + push_signature_2)
+ rpc_result = self.nodes[0].decoderawtransaction(hexlify(txSave.serialize()))
+ assert_equal('0 ' + signature_sighash_decoded + ' ' + signature_2_sighash_decoded, rpc_result['vin'][0]['scriptSig']['asm'])
+
+ # 3) test a scriptSig that contains more than push operations.
+ # in fact, it contains an OP_RETURN with data specially crafted to cause improper decode if the code does not catch it.
+ txSave.vin[0].scriptSig = unhexlify('6a143011020701010101010101020601010101010101')
+ rpc_result = self.nodes[0].decoderawtransaction(hexlify(txSave.serialize()))
+ print(hexlify('636174'))
+ assert_equal('OP_RETURN 3011020701010101010101020601010101010101', rpc_result['vin'][0]['scriptSig']['asm'])
+
def run_test(self):
self.decodescript_script_sig()
self.decodescript_script_pub_key()
+ self.decoderawtransaction_asm_sighashtype()
if __name__ == '__main__':
DecodeScriptTest().main()
-