Changeset View
Changeset View
Standalone View
Standalone View
qa/rpc-tests/signrawtransactions.py
#!/usr/bin/env python3 | #!/usr/bin/env python3 | ||||
# Copyright (c) 2015-2016 The Bitcoin Core developers | # Copyright (c) 2015-2016 The Bitcoin Core developers | ||||
# Distributed under the MIT software license, see the accompanying | # Distributed under the MIT software license, see the accompanying | ||||
# file COPYING or http://www.opensource.org/licenses/mit-license.php. | # file COPYING or http://www.opensource.org/licenses/mit-license.php. | ||||
from test_framework.test_framework import BitcoinTestFramework | from test_framework.test_framework import BitcoinTestFramework | ||||
from test_framework.util import * | from test_framework.util import * | ||||
class SignRawTransactionsTest(BitcoinTestFramework): | class SignRawTransactionsTest(BitcoinTestFramework): | ||||
"""Tests transaction signing via RPC command "signrawtransaction".""" | """Tests transaction signing via RPC command "signrawtransaction".""" | ||||
def __init__(self): | def __init__(self): | ||||
super().__init__() | super().__init__() | ||||
self.setup_clean_chain = True | self.setup_clean_chain = True | ||||
self.num_nodes = 1 | self.num_nodes = 1 | ||||
def setup_network(self, split=False): | def setup_network(self, split=False): | ||||
self.nodes = start_nodes(self.num_nodes, self.options.tmpdir) | self.nodes = start_nodes(self.num_nodes, self.options.tmpdir) | ||||
self.is_network_split = False | self.is_network_split = False | ||||
def successful_signing_test(self): | def successful_signing_test(self): | ||||
"""Creates and signs a valid raw transaction with one input. | """Creates and signs a valid raw transaction with one input. | ||||
Expected results: | Expected results: | ||||
1) The transaction has a complete set of signatures | 1) The transaction has a complete set of signatures | ||||
2) No script verification error occurred""" | 2) No script verification error occurred""" | ||||
privKeys = ['cUeKHd5orzT3mz8P9pxyREHfsWtVfgsfDjiZZBcjUBAaGk1BTj7N', 'cVKpPfVKSJxKqVpE9awvXNWuLHCa5j5tiE7K6zbUSptFpTEtiFrA'] | privKeys = ['cUeKHd5orzT3mz8P9pxyREHfsWtVfgsfDjiZZBcjUBAaGk1BTj7N', | ||||
'cVKpPfVKSJxKqVpE9awvXNWuLHCa5j5tiE7K6zbUSptFpTEtiFrA'] | |||||
inputs = [ | inputs = [ | ||||
# Valid pay-to-pubkey scripts | # Valid pay-to-pubkey scripts | ||||
{'txid': '9b907ef1e3c26fc71fe4a4b3580bc75264112f95050014157059c736f0202e71', 'vout': 0, | {'txid': '9b907ef1e3c26fc71fe4a4b3580bc75264112f95050014157059c736f0202e71', | ||||
'vout': 0, 'amount': 3.14159, | |||||
'scriptPubKey': '76a91460baa0f494b38ce3c940dea67f3804dc52d1fb9488ac'}, | 'scriptPubKey': '76a91460baa0f494b38ce3c940dea67f3804dc52d1fb9488ac'}, | ||||
{'txid': '83a4f6a6b73660e13ee6cb3c6063fa3759c50c9b7521d0536022961898f4fb02', 'vout': 0, | {'txid': '83a4f6a6b73660e13ee6cb3c6063fa3759c50c9b7521d0536022961898f4fb02', | ||||
'vout': 0, 'amount': '123.456', | |||||
'scriptPubKey': '76a914669b857c03a5ed269d5d85a1ffac9ed5d663072788ac'}, | 'scriptPubKey': '76a914669b857c03a5ed269d5d85a1ffac9ed5d663072788ac'}, | ||||
] | ] | ||||
outputs = {'mpLQjfK79b7CCV4VMJWEWAj5Mpx8Up5zxB': 0.1} | outputs = {'mpLQjfK79b7CCV4VMJWEWAj5Mpx8Up5zxB': 0.1} | ||||
rawTx = self.nodes[0].createrawtransaction(inputs, outputs) | rawTx = self.nodes[0].createrawtransaction(inputs, outputs) | ||||
rawTxSigned = self.nodes[0].signrawtransaction(rawTx, inputs, privKeys) | rawTxSigned = self.nodes[0].signrawtransaction(rawTx, inputs, privKeys) | ||||
# 1) The transaction has a complete set of signatures | # 1) The transaction has a complete set of signatures | ||||
assert 'complete' in rawTxSigned | assert 'complete' in rawTxSigned | ||||
assert_equal(rawTxSigned['complete'], True) | assert_equal(rawTxSigned['complete'], True) | ||||
# 2) No script verification error occurred | # 2) No script verification error occurred | ||||
assert 'errors' not in rawTxSigned | assert 'errors' not in rawTxSigned | ||||
# Check that signrawtransaction doesn't blow up on garbage merge attempts | # Check that signrawtransaction doesn't blow up on garbage merge | ||||
dummyTxInconsistent = self.nodes[0].createrawtransaction([inputs[0]], outputs) | # attempts | ||||
rawTxUnsigned = self.nodes[0].signrawtransaction(rawTx + dummyTxInconsistent, inputs) | dummyTxInconsistent = self.nodes[ | ||||
0].createrawtransaction([inputs[0]], outputs) | |||||
rawTxUnsigned = self.nodes[0].signrawtransaction( | |||||
rawTx + dummyTxInconsistent, inputs) | |||||
assert 'complete' in rawTxUnsigned | assert 'complete' in rawTxUnsigned | ||||
assert_equal(rawTxUnsigned['complete'], False) | assert_equal(rawTxUnsigned['complete'], False) | ||||
# Check that signrawtransaction properly merges unsigned and signed txn, even with garbage in the middle | # Check that signrawtransaction properly merges unsigned and signed | ||||
rawTxSigned2 = self.nodes[0].signrawtransaction(rawTxUnsigned["hex"] + dummyTxInconsistent + rawTxSigned["hex"], inputs) | # txn, even with garbage in the middle | ||||
rawTxSigned2 = self.nodes[0].signrawtransaction( | |||||
rawTxUnsigned["hex"] + dummyTxInconsistent + rawTxSigned["hex"], inputs) | |||||
assert 'complete' in rawTxSigned2 | assert 'complete' in rawTxSigned2 | ||||
assert_equal(rawTxSigned2['complete'], True) | assert_equal(rawTxSigned2['complete'], True) | ||||
assert 'errors' not in rawTxSigned2 | assert 'errors' not in rawTxSigned2 | ||||
def script_verification_error_test(self): | def script_verification_error_test(self): | ||||
"""Creates and signs a raw transaction with valid (vin 0), invalid (vin 1) and one missing (vin 2) input script. | """Creates and signs a raw transaction with valid (vin 0), invalid (vin 1) and one missing (vin 2) input script. | ||||
Expected results: | Expected results: | ||||
3) The transaction has no complete set of signatures | 3) The transaction has no complete set of signatures | ||||
4) Two script verification errors occurred | 4) Two script verification errors occurred | ||||
5) Script verification errors have certain properties ("txid", "vout", "scriptSig", "sequence", "error") | 5) Script verification errors have certain properties ("txid", "vout", "scriptSig", "sequence", "error") | ||||
6) The verification errors refer to the invalid (vin 1) and missing input (vin 2)""" | 6) The verification errors refer to the invalid (vin 1) and missing input (vin 2)""" | ||||
privKeys = ['cUeKHd5orzT3mz8P9pxyREHfsWtVfgsfDjiZZBcjUBAaGk1BTj7N'] | privKeys = ['cUeKHd5orzT3mz8P9pxyREHfsWtVfgsfDjiZZBcjUBAaGk1BTj7N'] | ||||
inputs = [ | inputs = [ | ||||
# Valid pay-to-pubkey script | # Valid pay-to-pubkey script | ||||
{'txid': '9b907ef1e3c26fc71fe4a4b3580bc75264112f95050014157059c736f0202e71', 'vout': 0}, | {'txid': '9b907ef1e3c26fc71fe4a4b3580bc75264112f95050014157059c736f0202e71', | ||||
'vout': 0, 'amount': 0}, | |||||
# Invalid script | # Invalid script | ||||
{'txid': '5b8673686910442c644b1f4993d8f7753c7c8fcb5c87ee40d56eaeef25204547', 'vout': 7}, | {'txid': '5b8673686910442c644b1f4993d8f7753c7c8fcb5c87ee40d56eaeef25204547', | ||||
'vout': 7, 'amount': '1.1'}, | |||||
# Missing scriptPubKey | # Missing scriptPubKey | ||||
{'txid': '9b907ef1e3c26fc71fe4a4b3580bc75264112f95050014157059c736f0202e71', 'vout': 1}, | {'txid': '9b907ef1e3c26fc71fe4a4b3580bc75264112f95050014157059c736f0202e71', | ||||
'vout': 1, 'amount': 2.0}, | |||||
] | ] | ||||
scripts = [ | scripts = [ | ||||
# Valid pay-to-pubkey script | # Valid pay-to-pubkey script | ||||
{'txid': '9b907ef1e3c26fc71fe4a4b3580bc75264112f95050014157059c736f0202e71', 'vout': 0, | {'txid': '9b907ef1e3c26fc71fe4a4b3580bc75264112f95050014157059c736f0202e71', | ||||
'vout': 0, 'amount': 0, | |||||
'scriptPubKey': '76a91460baa0f494b38ce3c940dea67f3804dc52d1fb9488ac'}, | 'scriptPubKey': '76a91460baa0f494b38ce3c940dea67f3804dc52d1fb9488ac'}, | ||||
# Invalid script | # Invalid script | ||||
{'txid': '5b8673686910442c644b1f4993d8f7753c7c8fcb5c87ee40d56eaeef25204547', 'vout': 7, | {'txid': '5b8673686910442c644b1f4993d8f7753c7c8fcb5c87ee40d56eaeef25204547', | ||||
'vout': 7, 'amount': '1.1', | |||||
'scriptPubKey': 'badbadbadbad'} | 'scriptPubKey': 'badbadbadbad'} | ||||
] | ] | ||||
outputs = {'mpLQjfK79b7CCV4VMJWEWAj5Mpx8Up5zxB': 0.1} | outputs = {'mpLQjfK79b7CCV4VMJWEWAj5Mpx8Up5zxB': 0.1} | ||||
rawTx = self.nodes[0].createrawtransaction(inputs, outputs) | rawTx = self.nodes[0].createrawtransaction(inputs, outputs) | ||||
# Make sure decoderawtransaction is at least marginally sane | # Make sure decoderawtransaction is at least marginally sane | ||||
decodedRawTx = self.nodes[0].decoderawtransaction(rawTx) | decodedRawTx = self.nodes[0].decoderawtransaction(rawTx) | ||||
for i, inp in enumerate(inputs): | for i, inp in enumerate(inputs): | ||||
assert_equal(decodedRawTx["vin"][i]["txid"], inp["txid"]) | assert_equal(decodedRawTx["vin"][i]["txid"], inp["txid"]) | ||||
assert_equal(decodedRawTx["vin"][i]["vout"], inp["vout"]) | assert_equal(decodedRawTx["vin"][i]["vout"], inp["vout"]) | ||||
# Make sure decoderawtransaction throws if there is extra data | # Make sure decoderawtransaction throws if there is extra data | ||||
assert_raises(JSONRPCException, self.nodes[0].decoderawtransaction, rawTx + "00") | assert_raises(JSONRPCException, self.nodes[ | ||||
0].decoderawtransaction, rawTx + "00") | |||||
rawTxSigned = self.nodes[0].signrawtransaction(rawTx, scripts, privKeys) | rawTxSigned = self.nodes[0].signrawtransaction( | ||||
rawTx, scripts, privKeys) | |||||
# 3) The transaction has no complete set of signatures | # 3) The transaction has no complete set of signatures | ||||
assert 'complete' in rawTxSigned | assert 'complete' in rawTxSigned | ||||
assert_equal(rawTxSigned['complete'], False) | assert_equal(rawTxSigned['complete'], False) | ||||
# 4) Two script verification errors occurred | # 4) Two script verification errors occurred | ||||
assert 'errors' in rawTxSigned | assert 'errors' in rawTxSigned | ||||
assert_equal(len(rawTxSigned['errors']), 2) | assert_equal(len(rawTxSigned['errors']), 2) | ||||
# 5) Script verification errors have certain properties | # 5) Script verification errors have certain properties | ||||
assert 'txid' in rawTxSigned['errors'][0] | assert 'txid' in rawTxSigned['errors'][0] | ||||
assert 'vout' in rawTxSigned['errors'][0] | assert 'vout' in rawTxSigned['errors'][0] | ||||
assert 'scriptSig' in rawTxSigned['errors'][0] | assert 'scriptSig' in rawTxSigned['errors'][0] | ||||
assert 'sequence' in rawTxSigned['errors'][0] | assert 'sequence' in rawTxSigned['errors'][0] | ||||
assert 'error' in rawTxSigned['errors'][0] | assert 'error' in rawTxSigned['errors'][0] | ||||
# 6) The verification errors refer to the invalid (vin 1) and missing input (vin 2) | # 6) The verification errors refer to the invalid (vin 1) and missing | ||||
# input (vin 2) | |||||
assert_equal(rawTxSigned['errors'][0]['txid'], inputs[1]['txid']) | assert_equal(rawTxSigned['errors'][0]['txid'], inputs[1]['txid']) | ||||
assert_equal(rawTxSigned['errors'][0]['vout'], inputs[1]['vout']) | assert_equal(rawTxSigned['errors'][0]['vout'], inputs[1]['vout']) | ||||
assert_equal(rawTxSigned['errors'][1]['txid'], inputs[2]['txid']) | assert_equal(rawTxSigned['errors'][1]['txid'], inputs[2]['txid']) | ||||
assert_equal(rawTxSigned['errors'][1]['vout'], inputs[2]['vout']) | assert_equal(rawTxSigned['errors'][1]['vout'], inputs[2]['vout']) | ||||
def run_test(self): | def run_test(self): | ||||
self.successful_signing_test() | self.successful_signing_test() | ||||
self.script_verification_error_test() | self.script_verification_error_test() | ||||
if __name__ == '__main__': | if __name__ == '__main__': | ||||
SignRawTransactionsTest().main() | SignRawTransactionsTest().main() |