diff --git a/qa/pull-tester/rpc-tests.sh b/qa/pull-tester/rpc-tests.sh index bd3357642..1483ead83 100755 --- a/qa/pull-tester/rpc-tests.sh +++ b/qa/pull-tester/rpc-tests.sh @@ -34,6 +34,7 @@ testScripts=( 'fundrawtransaction.py' 'signrawtransactions.py' 'walletbackup.py' + 'key_import_export.py' 'nodehandling.py' 'reindex.py' 'decodescript.py' diff --git a/qa/rpc-tests/key_import_export.py b/qa/rpc-tests/key_import_export.py new file mode 100755 index 000000000..a80babd5f --- /dev/null +++ b/qa/rpc-tests/key_import_export.py @@ -0,0 +1,111 @@ +#!/usr/bin/env python2 +# Copyright (c) 2017 The Zcash developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +from time import sleep +from decimal import Decimal +from test_framework.test_framework import BitcoinTestFramework +from test_framework.util import assert_equal, assert_greater_than, sync_blocks + +import logging + +logging.basicConfig(format='%(levelname)s:%(message)s', level=logging.INFO) + + +class KeyImportExportTest (BitcoinTestFramework): + + def run_test(self): + [alice, bob, charlie, miner] = self.nodes + + def wait_until_miner_sees(txid): + attempts = 123 + delay = 0.5 + + for _ in range(attempts): + try: + miner.getrawtransaction(txid) + except Exception: + logging.debug( + 'txid %r not yet seen by miner; sleep %r', + txid, + delay, + ) + sleep(delay) + else: + return + + raise Exception( + 'miner failed to see txid {!r} after {!r} attempts...'.format( + txid, + attempts, + ), + ) + + def alice_to_bob(amount): + txid = alice.sendtoaddress(addr, Decimal(amount)) + wait_until_miner_sees(txid) + miner.generate(1) + sync_blocks(self.nodes) + + def verify_utxos(node, amounts): + utxos = node.listunspent(1, 10**9, [addr]) + + def cmp_confirmations_high_to_low(a, b): + return cmp(b["confirmations"], a["confirmations"]) + + utxos.sort(cmp_confirmations_high_to_low) + + try: + assert_equal(amounts, [utxo["amount"] for utxo in utxos]) + except AssertionError: + logging.error( + 'Expected amounts: %r; utxos: %r', + amounts, utxos) + raise + + # The first address already mutated by the startup process, ignore it: + # BUG: Why is this necessary? + bob.getnewaddress() + + # Now get a pristine address for receiving transfers: + addr = bob.getnewaddress() + verify_utxos(bob, []) + + # the amounts of each txn embodied which generates a single UTXO: + amounts = map(Decimal, ['2.3', '3.7', '0.1', '0.5', '1.0', '0.19']) + + # Internal test consistency assertion: + assert_greater_than( + alice.getbalance(), + reduce(Decimal.__add__, amounts)) + + logging.info("Sending pre-export txns...") + for amount in amounts[0:2]: + alice_to_bob(amount) + + logging.info("Exporting privkey from bob...") + privkey = bob.dumpprivkey(addr) + + logging.info("Sending post-export txns...") + for amount in amounts[2:4]: + alice_to_bob(amount) + + verify_utxos(bob, amounts[:4]) + + logging.info("Importing privkey into charlie...") + charlie.importprivkey(privkey, '', True) + + # importprivkey should have rescanned, so this should pass: + verify_utxos(charlie, amounts[:4]) + + logging.info("Sending post-import txns...") + for amount in amounts[4:]: + alice_to_bob(amount) + + verify_utxos(bob, amounts) + verify_utxos(charlie, amounts) + + +if __name__ == '__main__': + KeyImportExportTest().main()