diff options
Diffstat (limited to 'qa/rpc-tests')
26 files changed, 895 insertions, 485 deletions
diff --git a/qa/rpc-tests/README.md b/qa/rpc-tests/README.md index 3e916a7688..02170d13ec 100644 --- a/qa/rpc-tests/README.md +++ b/qa/rpc-tests/README.md @@ -12,7 +12,7 @@ Base class for new regression tests. ### [listtransactions.py](listtransactions.py) Tests for the listtransactions RPC call. -### [util.py](util.sh) +### [util.py](util.py) Generally useful functions. Bash-based tests, to be ported to Python: diff --git a/qa/rpc-tests/bipdersig.py b/qa/rpc-tests/bipdersig.py new file mode 100755 index 0000000000..9f2cc84601 --- /dev/null +++ b/qa/rpc-tests/bipdersig.py @@ -0,0 +1,90 @@ +#!/usr/bin/env python2 +# Copyright (c) 2014 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +# +# Test the BIP66 changeover logic +# + +from test_framework import BitcoinTestFramework +from bitcoinrpc.authproxy import AuthServiceProxy, JSONRPCException +from util import * +import os +import shutil + +class BIP66Test(BitcoinTestFramework): + + def setup_network(self): + self.nodes = [] + self.nodes.append(start_node(0, self.options.tmpdir, [])) + self.nodes.append(start_node(1, self.options.tmpdir, ["-blockversion=2"])) + self.nodes.append(start_node(2, self.options.tmpdir, ["-blockversion=3"])) + connect_nodes(self.nodes[1], 0) + connect_nodes(self.nodes[2], 0) + self.is_network_split = False + self.sync_all() + + def run_test(self): + cnt = self.nodes[0].getblockcount() + + # Mine some old-version blocks + self.nodes[1].setgenerate(True, 100) + self.sync_all() + if (self.nodes[0].getblockcount() != cnt + 100): + raise AssertionError("Failed to mine 100 version=2 blocks") + + # Mine 750 new-version blocks + for i in xrange(15): + self.nodes[2].setgenerate(True, 50) + self.sync_all() + if (self.nodes[0].getblockcount() != cnt + 850): + raise AssertionError("Failed to mine 750 version=3 blocks") + + # TODO: check that new DERSIG rules are not enforced + + # Mine 1 new-version block + self.nodes[2].setgenerate(True, 1) + self.sync_all() + if (self.nodes[0].getblockcount() != cnt + 851): + raise AssertionFailure("Failed to mine a version=3 blocks") + + # TODO: check that new DERSIG rules are enforced + + # Mine 198 new-version blocks + for i in xrange(2): + self.nodes[2].setgenerate(True, 99) + self.sync_all() + if (self.nodes[0].getblockcount() != cnt + 1049): + raise AssertionError("Failed to mine 198 version=3 blocks") + + # Mine 1 old-version block + self.nodes[1].setgenerate(True, 1) + self.sync_all() + if (self.nodes[0].getblockcount() != cnt + 1050): + raise AssertionError("Failed to mine a version=2 block after 949 version=3 blocks") + + # Mine 1 new-version blocks + self.nodes[2].setgenerate(True, 1) + self.sync_all() + if (self.nodes[0].getblockcount() != cnt + 1051): + raise AssertionError("Failed to mine a version=3 block") + + # Mine 1 old-version blocks + try: + self.nodes[1].setgenerate(True, 1) + raise AssertionError("Succeeded to mine a version=2 block after 950 version=3 blocks") + except JSONRPCException: + pass + self.sync_all() + if (self.nodes[0].getblockcount() != cnt + 1051): + raise AssertionError("Accepted a version=2 block after 950 version=3 blocks") + + # Mine 1 new-version blocks + self.nodes[2].setgenerate(True, 1) + self.sync_all() + if (self.nodes[0].getblockcount() != cnt + 1052): + raise AssertionError("Failed to mine a version=3 block") + +if __name__ == '__main__': + BIP66Test().main() diff --git a/qa/rpc-tests/forknotify.py b/qa/rpc-tests/forknotify.py index 1d2c4a9966..ad2a748ca1 100755 --- a/qa/rpc-tests/forknotify.py +++ b/qa/rpc-tests/forknotify.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python2 # Copyright (c) 2014 The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/qa/rpc-tests/getblocktemplate_longpoll.py b/qa/rpc-tests/getblocktemplate_longpoll.py index 263a5f6d59..b749b260b7 100755 --- a/qa/rpc-tests/getblocktemplate_longpoll.py +++ b/qa/rpc-tests/getblocktemplate_longpoll.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python2 # Copyright (c) 2014 The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/qa/rpc-tests/getblocktemplate_proposals.py b/qa/rpc-tests/getblocktemplate_proposals.py index 0f7859584a..f65162002d 100755 --- a/qa/rpc-tests/getblocktemplate_proposals.py +++ b/qa/rpc-tests/getblocktemplate_proposals.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python2 # Copyright (c) 2014 The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -95,6 +95,7 @@ class GetBlockTemplateProposalTest(BitcoinTestFramework): def run_test(self): node = self.nodes[0] + node.setgenerate(True, 1) # Mine a block to leave initial block download tmpl = node.getblocktemplate() if 'coinbasetxn' not in tmpl: rawcoinbase = encodeUNum(tmpl['height']) diff --git a/qa/rpc-tests/getchaintips.py b/qa/rpc-tests/getchaintips.py index dda3450eb6..84fe102d81 100755 --- a/qa/rpc-tests/getchaintips.py +++ b/qa/rpc-tests/getchaintips.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python2 # Copyright (c) 2014 The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -19,6 +19,7 @@ class GetChainTipsTest (BitcoinTestFramework): assert_equal (len (tips), 1) assert_equal (tips[0]['branchlen'], 0) assert_equal (tips[0]['height'], 200) + assert_equal (tips[0]['status'], 'active') # Split the network and build two chains of different lengths. self.split_network () @@ -31,12 +32,14 @@ class GetChainTipsTest (BitcoinTestFramework): shortTip = tips[0] assert_equal (shortTip['branchlen'], 0) assert_equal (shortTip['height'], 210) + assert_equal (tips[0]['status'], 'active') tips = self.nodes[3].getchaintips () assert_equal (len (tips), 1) longTip = tips[0] assert_equal (longTip['branchlen'], 0) assert_equal (longTip['height'], 220) + assert_equal (tips[0]['status'], 'active') # Join the network halves and check that we now have two tips # (at least at the nodes that previously had the short chain). @@ -47,7 +50,9 @@ class GetChainTipsTest (BitcoinTestFramework): assert_equal (tips[0], longTip) assert_equal (tips[1]['branchlen'], 10) - tips[1]['branchlen'] = 0; + assert_equal (tips[1]['status'], 'valid-fork') + tips[1]['branchlen'] = 0 + tips[1]['status'] = 'active' assert_equal (tips[1], shortTip) if __name__ == '__main__': diff --git a/qa/rpc-tests/httpbasics.py b/qa/rpc-tests/httpbasics.py new file mode 100755 index 0000000000..24533741e5 --- /dev/null +++ b/qa/rpc-tests/httpbasics.py @@ -0,0 +1,102 @@ +#!/usr/bin/env python2 +# Copyright (c) 2014 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +# +# Test REST interface +# + +from test_framework import BitcoinTestFramework +from util import * +import base64 + +try: + import http.client as httplib +except ImportError: + import httplib +try: + import urllib.parse as urlparse +except ImportError: + import urlparse + +class HTTPBasicsTest (BitcoinTestFramework): + def setup_nodes(self): + return start_nodes(4, self.options.tmpdir, extra_args=[['-rpckeepalive=1'], ['-rpckeepalive=0'], [], []]) + + def run_test(self): + + ################################################# + # lowlevel check for http persistent connection # + ################################################# + url = urlparse.urlparse(self.nodes[0].url) + authpair = url.username + ':' + url.password + headers = {"Authorization": "Basic " + base64.b64encode(authpair)} + + conn = httplib.HTTPConnection(url.hostname, url.port) + conn.connect() + conn.request('POST', '/', '{"method": "getbestblockhash"}', headers) + out1 = conn.getresponse().read(); + assert_equal('"error":null' in out1, True) + assert_equal(conn.sock!=None, True) #according to http/1.1 connection must still be open! + + #send 2nd request without closing connection + conn.request('POST', '/', '{"method": "getchaintips"}', headers) + out2 = conn.getresponse().read(); + assert_equal('"error":null' in out1, True) #must also response with a correct json-rpc message + assert_equal(conn.sock!=None, True) #according to http/1.1 connection must still be open! + conn.close() + + #same should be if we add keep-alive because this should be the std. behaviour + headers = {"Authorization": "Basic " + base64.b64encode(authpair), "Connection": "keep-alive"} + + conn = httplib.HTTPConnection(url.hostname, url.port) + conn.connect() + conn.request('POST', '/', '{"method": "getbestblockhash"}', headers) + out1 = conn.getresponse().read(); + assert_equal('"error":null' in out1, True) + assert_equal(conn.sock!=None, True) #according to http/1.1 connection must still be open! + + #send 2nd request without closing connection + conn.request('POST', '/', '{"method": "getchaintips"}', headers) + out2 = conn.getresponse().read(); + assert_equal('"error":null' in out1, True) #must also response with a correct json-rpc message + assert_equal(conn.sock!=None, True) #according to http/1.1 connection must still be open! + conn.close() + + #now do the same with "Connection: close" + headers = {"Authorization": "Basic " + base64.b64encode(authpair), "Connection":"close"} + + conn = httplib.HTTPConnection(url.hostname, url.port) + conn.connect() + conn.request('POST', '/', '{"method": "getbestblockhash"}', headers) + out1 = conn.getresponse().read(); + assert_equal('"error":null' in out1, True) + assert_equal(conn.sock!=None, False) #now the connection must be closed after the response + + #node1 (2nd node) is running with disabled keep-alive option + urlNode1 = urlparse.urlparse(self.nodes[1].url) + authpair = urlNode1.username + ':' + urlNode1.password + headers = {"Authorization": "Basic " + base64.b64encode(authpair)} + + conn = httplib.HTTPConnection(urlNode1.hostname, urlNode1.port) + conn.connect() + conn.request('POST', '/', '{"method": "getbestblockhash"}', headers) + out1 = conn.getresponse().read(); + assert_equal('"error":null' in out1, True) + assert_equal(conn.sock!=None, False) #connection must be closed because keep-alive was set to false + + #node2 (third node) is running with standard keep-alive parameters which means keep-alive is off + urlNode2 = urlparse.urlparse(self.nodes[2].url) + authpair = urlNode2.username + ':' + urlNode2.password + headers = {"Authorization": "Basic " + base64.b64encode(authpair)} + + conn = httplib.HTTPConnection(urlNode2.hostname, urlNode2.port) + conn.connect() + conn.request('POST', '/', '{"method": "getbestblockhash"}', headers) + out1 = conn.getresponse().read(); + assert_equal('"error":null' in out1, True) + assert_equal(conn.sock!=None, True) #connection must be closed because bitcoind should use keep-alive by default + +if __name__ == '__main__': + HTTPBasicsTest ().main () diff --git a/qa/rpc-tests/keypool.py b/qa/rpc-tests/keypool.py index 354ee0822c..3840ea39d3 100755 --- a/qa/rpc-tests/keypool.py +++ b/qa/rpc-tests/keypool.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python2 # Copyright (c) 2014 The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/qa/rpc-tests/listtransactions.py b/qa/rpc-tests/listtransactions.py index 530b00db8f..8ee9d66a29 100755 --- a/qa/rpc-tests/listtransactions.py +++ b/qa/rpc-tests/listtransactions.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python2 # Copyright (c) 2014 The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/qa/rpc-tests/mempool_coinbase_spends.py b/qa/rpc-tests/mempool_coinbase_spends.py new file mode 100755 index 0000000000..7b43712768 --- /dev/null +++ b/qa/rpc-tests/mempool_coinbase_spends.py @@ -0,0 +1,94 @@ +#!/usr/bin/env python2 +# Copyright (c) 2014 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +# +# Test re-org scenarios with a mempool that contains transactions +# that spend (directly or indirectly) coinbase transactions. +# + +from test_framework import BitcoinTestFramework +from bitcoinrpc.authproxy import AuthServiceProxy, JSONRPCException +from util import * +import os +import shutil + +# Create one-input, one-output, no-fee transaction: +class MempoolCoinbaseTest(BitcoinTestFramework): + + alert_filename = None # Set by setup_network + + def setup_network(self): + args = ["-checkmempool", "-debug=mempool"] + self.nodes = [] + self.nodes.append(start_node(0, self.options.tmpdir, args)) + self.nodes.append(start_node(1, self.options.tmpdir, args)) + connect_nodes(self.nodes[1], 0) + self.is_network_split = False + self.sync_all + + def create_tx(self, from_txid, to_address, amount): + inputs = [{ "txid" : from_txid, "vout" : 0}] + outputs = { to_address : amount } + rawtx = self.nodes[0].createrawtransaction(inputs, outputs) + signresult = self.nodes[0].signrawtransaction(rawtx) + assert_equal(signresult["complete"], True) + return signresult["hex"] + + def run_test(self): + start_count = self.nodes[0].getblockcount() + + # Mine three blocks. After this, nodes[0] blocks + # 101, 102, and 103 are spend-able. + new_blocks = self.nodes[1].setgenerate(True, 4) + self.sync_all() + + node0_address = self.nodes[0].getnewaddress() + node1_address = self.nodes[1].getnewaddress() + + # Three scenarios for re-orging coinbase spends in the memory pool: + # 1. Direct coinbase spend : spend_101 + # 2. Indirect (coinbase spend in chain, child in mempool) : spend_102 and spend_102_1 + # 3. Indirect (coinbase and child both in chain) : spend_103 and spend_103_1 + # Use invalidatblock to make all of the above coinbase spends invalid (immature coinbase), + # and make sure the mempool code behaves correctly. + b = [ self.nodes[0].getblockhash(n) for n in range(102, 105) ] + coinbase_txids = [ self.nodes[0].getblock(h)['tx'][0] for h in b ] + spend_101_raw = self.create_tx(coinbase_txids[0], node1_address, 50) + spend_102_raw = self.create_tx(coinbase_txids[1], node0_address, 50) + spend_103_raw = self.create_tx(coinbase_txids[2], node0_address, 50) + + # Broadcast and mine spend_102 and 103: + spend_102_id = self.nodes[0].sendrawtransaction(spend_102_raw) + spend_103_id = self.nodes[0].sendrawtransaction(spend_103_raw) + self.nodes[0].setgenerate(True, 1) + + # Create 102_1 and 103_1: + spend_102_1_raw = self.create_tx(spend_102_id, node1_address, 50) + spend_103_1_raw = self.create_tx(spend_103_id, node1_address, 50) + + # Broadcast and mine 103_1: + spend_103_1_id = self.nodes[0].sendrawtransaction(spend_103_1_raw) + self.nodes[0].setgenerate(True, 1) + + # ... now put spend_101 and spend_102_1 in memory pools: + spend_101_id = self.nodes[0].sendrawtransaction(spend_101_raw) + spend_102_1_id = self.nodes[0].sendrawtransaction(spend_102_1_raw) + + self.sync_all() + + assert_equal(set(self.nodes[0].getrawmempool()), set([ spend_101_id, spend_102_1_id ])) + + # Use invalidateblock to re-org back and make all those coinbase spends + # immature/invalid: + for node in self.nodes: + node.invalidateblock(new_blocks[0]) + + self.sync_all() + + # mempool should be empty. + assert_equal(set(self.nodes[0].getrawmempool()), set()) + +if __name__ == '__main__': + MempoolCoinbaseTest().main() diff --git a/qa/rpc-tests/mempool_resurrect_test.py b/qa/rpc-tests/mempool_resurrect_test.py new file mode 100755 index 0000000000..81db812bfc --- /dev/null +++ b/qa/rpc-tests/mempool_resurrect_test.py @@ -0,0 +1,88 @@ +#!/usr/bin/env python2 +# Copyright (c) 2014 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +# +# Test resurrection of mined transactions when +# the blockchain is re-organized. +# + +from test_framework import BitcoinTestFramework +from bitcoinrpc.authproxy import AuthServiceProxy, JSONRPCException +from util import * +import os +import shutil + +# Create one-input, one-output, no-fee transaction: +class MempoolCoinbaseTest(BitcoinTestFramework): + + def setup_network(self): + # Just need one node for this test + args = ["-checkmempool", "-debug=mempool"] + self.nodes = [] + self.nodes.append(start_node(0, self.options.tmpdir, args)) + self.is_network_split = False + + def create_tx(self, from_txid, to_address, amount): + inputs = [{ "txid" : from_txid, "vout" : 0}] + outputs = { to_address : amount } + rawtx = self.nodes[0].createrawtransaction(inputs, outputs) + signresult = self.nodes[0].signrawtransaction(rawtx) + assert_equal(signresult["complete"], True) + return signresult["hex"] + + def run_test(self): + node0_address = self.nodes[0].getnewaddress() + + # Spend block 1/2/3's coinbase transactions + # Mine a block. + # Create three more transactions, spending the spends + # Mine another block. + # ... make sure all the transactions are confirmed + # Invalidate both blocks + # ... make sure all the transactions are put back in the mempool + # Mine a new block + # ... make sure all the transactions are confirmed again. + + b = [ self.nodes[0].getblockhash(n) for n in range(1, 4) ] + coinbase_txids = [ self.nodes[0].getblock(h)['tx'][0] for h in b ] + spends1_raw = [ self.create_tx(txid, node0_address, 50) for txid in coinbase_txids ] + spends1_id = [ self.nodes[0].sendrawtransaction(tx) for tx in spends1_raw ] + + blocks = [] + blocks.extend(self.nodes[0].setgenerate(True, 1)) + + spends2_raw = [ self.create_tx(txid, node0_address, 49.99) for txid in spends1_id ] + spends2_id = [ self.nodes[0].sendrawtransaction(tx) for tx in spends2_raw ] + + blocks.extend(self.nodes[0].setgenerate(True, 1)) + + # mempool should be empty, all txns confirmed + assert_equal(set(self.nodes[0].getrawmempool()), set()) + for txid in spends1_id+spends2_id: + tx = self.nodes[0].gettransaction(txid) + assert(tx["confirmations"] > 0) + + # Use invalidateblock to re-org back; all transactions should + # end up unconfirmed and back in the mempool + for node in self.nodes: + node.invalidateblock(blocks[0]) + + # mempool should be empty, all txns confirmed + assert_equal(set(self.nodes[0].getrawmempool()), set(spends1_id+spends2_id)) + for txid in spends1_id+spends2_id: + tx = self.nodes[0].gettransaction(txid) + assert(tx["confirmations"] == 0) + + # Generate another block, they should all get mined + self.nodes[0].setgenerate(True, 1) + # mempool should be empty, all txns confirmed + assert_equal(set(self.nodes[0].getrawmempool()), set()) + for txid in spends1_id+spends2_id: + tx = self.nodes[0].gettransaction(txid) + assert(tx["confirmations"] > 0) + + +if __name__ == '__main__': + MempoolCoinbaseTest().main() diff --git a/qa/rpc-tests/mempool_spendcoinbase.py b/qa/rpc-tests/mempool_spendcoinbase.py new file mode 100755 index 0000000000..f0b34f2904 --- /dev/null +++ b/qa/rpc-tests/mempool_spendcoinbase.py @@ -0,0 +1,69 @@ +#!/usr/bin/env python2 +# Copyright (c) 2014 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +# +# Test spending coinbase transactions. +# The coinbase transaction in block N can appear in block +# N+100... so is valid in the mempool when the best block +# height is N+99. +# This test makes sure coinbase spends that will be mature +# in the next block are accepted into the memory pool, +# but less mature coinbase spends are NOT. +# + +from test_framework import BitcoinTestFramework +from bitcoinrpc.authproxy import AuthServiceProxy, JSONRPCException +from util import * +import os +import shutil + +# Create one-input, one-output, no-fee transaction: +class MempoolSpendCoinbaseTest(BitcoinTestFramework): + + def setup_network(self): + # Just need one node for this test + args = ["-checkmempool", "-debug=mempool"] + self.nodes = [] + self.nodes.append(start_node(0, self.options.tmpdir, args)) + self.is_network_split = False + + def create_tx(self, from_txid, to_address, amount): + inputs = [{ "txid" : from_txid, "vout" : 0}] + outputs = { to_address : amount } + rawtx = self.nodes[0].createrawtransaction(inputs, outputs) + signresult = self.nodes[0].signrawtransaction(rawtx) + assert_equal(signresult["complete"], True) + return signresult["hex"] + + def run_test(self): + chain_height = self.nodes[0].getblockcount() + assert_equal(chain_height, 200) + node0_address = self.nodes[0].getnewaddress() + + # Coinbase at height chain_height-100+1 ok in mempool, should + # get mined. Coinbase at height chain_height-100+2 is + # is too immature to spend. + b = [ self.nodes[0].getblockhash(n) for n in range(101, 103) ] + coinbase_txids = [ self.nodes[0].getblock(h)['tx'][0] for h in b ] + spends_raw = [ self.create_tx(txid, node0_address, 50) for txid in coinbase_txids ] + + spend_101_id = self.nodes[0].sendrawtransaction(spends_raw[0]) + + # coinbase at height 102 should be too immature to spend + assert_raises(JSONRPCException, self.nodes[0].sendrawtransaction, spends_raw[1]) + + # mempool should have just spend_101: + assert_equal(self.nodes[0].getrawmempool(), [ spend_101_id ]) + + # mine a block, spend_101 should get confirmed + self.nodes[0].setgenerate(True, 1) + assert_equal(set(self.nodes[0].getrawmempool()), set()) + + # ... and now height 102 can be spent: + spend_102_id = self.nodes[0].sendrawtransaction(spends_raw[1]) + assert_equal(self.nodes[0].getrawmempool(), [ spend_102_id ]) + +if __name__ == '__main__': + MempoolSpendCoinbaseTest().main() diff --git a/qa/rpc-tests/netutil.py b/qa/rpc-tests/netutil.py index b740ee0f98..b30a88a4f7 100644 --- a/qa/rpc-tests/netutil.py +++ b/qa/rpc-tests/netutil.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python2 # Copyright (c) 2014 The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/qa/rpc-tests/python-bitcoinrpc/setup.py b/qa/rpc-tests/python-bitcoinrpc/setup.py index b5a217bf93..43cdb1c038 100644 --- a/qa/rpc-tests/python-bitcoinrpc/setup.py +++ b/qa/rpc-tests/python-bitcoinrpc/setup.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python2 from distutils.core import setup diff --git a/qa/rpc-tests/receivedby.py b/qa/rpc-tests/receivedby.py index e3f86d38dc..d3504e0920 100755 --- a/qa/rpc-tests/receivedby.py +++ b/qa/rpc-tests/receivedby.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python2 # Copyright (c) 2014 The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/qa/rpc-tests/rest.py b/qa/rpc-tests/rest.py new file mode 100755 index 0000000000..a9d41cf367 --- /dev/null +++ b/qa/rpc-tests/rest.py @@ -0,0 +1,117 @@ +#!/usr/bin/env python2 +# Copyright (c) 2014 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +# +# Test REST interface +# + +from test_framework import BitcoinTestFramework +from util import * +import json + +try: + import http.client as httplib +except ImportError: + import httplib +try: + import urllib.parse as urlparse +except ImportError: + import urlparse + +def http_get_call(host, port, path, response_object = 0): + conn = httplib.HTTPConnection(host, port) + conn.request('GET', path) + + if response_object: + return conn.getresponse() + + return conn.getresponse().read() + + +class RESTTest (BitcoinTestFramework): + FORMAT_SEPARATOR = "." + + def run_test(self): + url = urlparse.urlparse(self.nodes[0].url) + bb_hash = self.nodes[0].getbestblockhash() + + # check binary format + response = http_get_call(url.hostname, url.port, '/rest/block/'+bb_hash+self.FORMAT_SEPARATOR+"bin", True) + assert_equal(response.status, 200) + assert_greater_than(int(response.getheader('content-length')), 80) + response_str = response.read() + + # compare with block header + response_header = http_get_call(url.hostname, url.port, '/rest/headers/1/'+bb_hash+self.FORMAT_SEPARATOR+"bin", True) + assert_equal(response_header.status, 200) + assert_equal(int(response_header.getheader('content-length')), 80) + response_header_str = response_header.read() + assert_equal(response_str[0:80], response_header_str) + + # check block hex format + response_hex = http_get_call(url.hostname, url.port, '/rest/block/'+bb_hash+self.FORMAT_SEPARATOR+"hex", True) + assert_equal(response_hex.status, 200) + assert_greater_than(int(response_hex.getheader('content-length')), 160) + response_hex_str = response_hex.read() + assert_equal(response_str.encode("hex")[0:160], response_hex_str[0:160]) + + # compare with hex block header + response_header_hex = http_get_call(url.hostname, url.port, '/rest/headers/1/'+bb_hash+self.FORMAT_SEPARATOR+"hex", True) + assert_equal(response_header_hex.status, 200) + assert_greater_than(int(response_header_hex.getheader('content-length')), 160) + response_header_hex_str = response_header_hex.read() + assert_equal(response_hex_str[0:160], response_header_hex_str[0:160]) + assert_equal(response_header_str.encode("hex")[0:160], response_header_hex_str[0:160]) + + # check json format + json_string = http_get_call(url.hostname, url.port, '/rest/block/'+bb_hash+self.FORMAT_SEPARATOR+'json') + json_obj = json.loads(json_string) + assert_equal(json_obj['hash'], bb_hash) + + # do tx test + tx_hash = json_obj['tx'][0]['txid']; + json_string = http_get_call(url.hostname, url.port, '/rest/tx/'+tx_hash+self.FORMAT_SEPARATOR+"json") + json_obj = json.loads(json_string) + assert_equal(json_obj['txid'], tx_hash) + + # check hex format response + hex_string = http_get_call(url.hostname, url.port, '/rest/tx/'+tx_hash+self.FORMAT_SEPARATOR+"hex", True) + assert_equal(hex_string.status, 200) + assert_greater_than(int(response.getheader('content-length')), 10) + + # check block tx details + # let's make 3 tx and mine them on node 1 + txs = [] + txs.append(self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 11)) + txs.append(self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 11)) + txs.append(self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 11)) + self.sync_all() + + # now mine the transactions + newblockhash = self.nodes[1].setgenerate(True, 1) + self.sync_all() + + #check if the 3 tx show up in the new block + json_string = http_get_call(url.hostname, url.port, '/rest/block/'+newblockhash[0]+self.FORMAT_SEPARATOR+'json') + json_obj = json.loads(json_string) + for tx in json_obj['tx']: + if not 'coinbase' in tx['vin'][0]: #exclude coinbase + assert_equal(tx['txid'] in txs, True) + + #check the same but without tx details + json_string = http_get_call(url.hostname, url.port, '/rest/block/notxdetails/'+newblockhash[0]+self.FORMAT_SEPARATOR+'json') + json_obj = json.loads(json_string) + for tx in txs: + assert_equal(tx in json_obj['tx'], True) + + #test rest bestblock + bb_hash = self.nodes[0].getbestblockhash() + + json_string = http_get_call(url.hostname, url.port, '/rest/chaininfo.json') + json_obj = json.loads(json_string) + assert_equal(json_obj['bestblockhash'], bb_hash) + +if __name__ == '__main__': + RESTTest ().main () diff --git a/qa/rpc-tests/rpcbind_test.py b/qa/rpc-tests/rpcbind_test.py index 5e476e2505..655e00b6e7 100755 --- a/qa/rpc-tests/rpcbind_test.py +++ b/qa/rpc-tests/rpcbind_test.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python2 # Copyright (c) 2014 The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/qa/rpc-tests/smartfees.py b/qa/rpc-tests/smartfees.py index 57a72dd96b..0c07ef8a53 100755 --- a/qa/rpc-tests/smartfees.py +++ b/qa/rpc-tests/smartfees.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python2 # Copyright (c) 2014 The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -16,20 +16,20 @@ class EstimateFeeTest(BitcoinTestFramework): def setup_network(self): self.nodes = [] self.nodes.append(start_node(0, self.options.tmpdir, - ["-debug=mempool", "-debug=estimatefee"])) + ["-debug=mempool", "-debug=estimatefee", "-relaypriority=0"])) # Node1 mines small-but-not-tiny blocks, and allows free transactions. # NOTE: the CreateNewBlock code starts counting block size at 1,000 bytes, # so blockmaxsize of 2,000 is really just 1,000 bytes (room enough for # 6 or 7 transactions) self.nodes.append(start_node(1, self.options.tmpdir, ["-blockprioritysize=1500", "-blockmaxsize=2000", - "-debug=mempool", "-debug=estimatefee"])) + "-debug=mempool", "-debug=estimatefee", "-relaypriority=0"])) connect_nodes(self.nodes[1], 0) # Node2 is a stingy miner, that # produces very small blocks (room for only 3 or so transactions) node2args = [ "-blockprioritysize=0", "-blockmaxsize=1500", - "-debug=mempool", "-debug=estimatefee"] + "-debug=mempool", "-debug=estimatefee", "-relaypriority=0"] self.nodes.append(start_node(2, self.options.tmpdir, node2args)) connect_nodes(self.nodes[2], 0) diff --git a/qa/rpc-tests/test_framework.py b/qa/rpc-tests/test_framework.py index 9591c024fb..4c8a11b821 100755 --- a/qa/rpc-tests/test_framework.py +++ b/qa/rpc-tests/test_framework.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python2 # Copyright (c) 2014 The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -33,8 +33,11 @@ class BitcoinTestFramework(object): print("Initializing test directory "+self.options.tmpdir) initialize_chain(self.options.tmpdir) + def setup_nodes(self): + return start_nodes(4, self.options.tmpdir) + def setup_network(self, split = False): - self.nodes = start_nodes(4, self.options.tmpdir) + self.nodes = self.setup_nodes() # Connect the nodes as a "chain". This allows us # to split the network between nodes 1 and 2 to get diff --git a/qa/rpc-tests/txn_doublespend.py b/qa/rpc-tests/txn_doublespend.py index 6125147ebc..942d9fc66c 100755 --- a/qa/rpc-tests/txn_doublespend.py +++ b/qa/rpc-tests/txn_doublespend.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python2 # Copyright (c) 2014 The Bitcoin Core developers # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. diff --git a/qa/rpc-tests/util.py b/qa/rpc-tests/util.py index bed7fed8ca..ec65f783e8 100644 --- a/qa/rpc-tests/util.py +++ b/qa/rpc-tests/util.py @@ -163,7 +163,7 @@ def start_node(i, dirname, extra_args=None, rpchost=None): Start a bitcoind and return RPC connection to it """ datadir = os.path.join(dirname, "node"+str(i)) - args = [ os.getenv("BITCOIND", "bitcoind"), "-datadir="+datadir, "-keypool=1", "-discover=0" ] + args = [ os.getenv("BITCOIND", "bitcoind"), "-datadir="+datadir, "-keypool=1", "-discover=0", "-rest" ] if extra_args is not None: args.extend(extra_args) bitcoind_processes[i] = subprocess.Popen(args) devnull = open("/dev/null", "w+") @@ -327,3 +327,17 @@ def random_transaction(nodes, amount, min_fee, fee_increment, fee_variants): def assert_equal(thing1, thing2): if thing1 != thing2: raise AssertionError("%s != %s"%(str(thing1),str(thing2))) + +def assert_greater_than(thing1, thing2): + if thing1 <= thing2: + raise AssertionError("%s <= %s"%(str(thing1),str(thing2))) + +def assert_raises(exc, fun, *args, **kwds): + try: + fun(*args, **kwds) + except exc: + pass + except Exception as e: + raise AssertionError("Unexpected exception raised: "+type(e).__name__) + else: + raise AssertionError("No exception raised") diff --git a/qa/rpc-tests/wallet.py b/qa/rpc-tests/wallet.py index 4271d96be7..3e63493dc6 100755 --- a/qa/rpc-tests/wallet.py +++ b/qa/rpc-tests/wallet.py @@ -1,6 +1,6 @@ -#!/usr/bin/env python +#!/usr/bin/env python2 # Copyright (c) 2014 The Bitcoin Core developers -# Distributed under the MIT/X11 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. # @@ -41,6 +41,10 @@ class WalletTest (BitcoinTestFramework): self.nodes[0].setgenerate(True, 1) + walletinfo = self.nodes[0].getwalletinfo() + assert_equal(walletinfo['immature_balance'], 50) + assert_equal(walletinfo['balance'], 0) + self.sync_all() self.nodes[1].setgenerate(True, 101) self.sync_all() @@ -54,7 +58,10 @@ class WalletTest (BitcoinTestFramework): self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 11) self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 10) - # Have node0 mine a block, thus he will collect his own fee. + walletinfo = self.nodes[0].getwalletinfo() + assert_equal(walletinfo['immature_balance'], 0) + + # Have node0 mine a block, thus they will collect their own fee. self.nodes[0].setgenerate(True, 1) self.sync_all() diff --git a/qa/rpc-tests/walletbackup.py b/qa/rpc-tests/walletbackup.py new file mode 100755 index 0000000000..049697c2db --- /dev/null +++ b/qa/rpc-tests/walletbackup.py @@ -0,0 +1,200 @@ +#!/usr/bin/env python2 +# Copyright (c) 2014 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +""" +Exercise the wallet backup code. Ported from walletbackup.sh. + +Test case is: +4 nodes. 1 2 and 3 send transactions between each other, +fourth node is a miner. +1 2 3 each mine a block to start, then +Miner creates 100 blocks so 1 2 3 each have 50 mature +coins to spend. +Then 5 iterations of 1/2/3 sending coins amongst +themselves to get transactions in the wallets, +and the miner mining one block. + +Wallets are backed up using dumpwallet/backupwallet. +Then 5 more iterations of transactions and mining a block. + +Miner then generates 101 more blocks, so any +transaction fees paid mature. + +Sanity check: + Sum(1,2,3,4 balances) == 114*50 + +1/2/3 are shutdown, and their wallets erased. +Then restore using wallet.dat backup. And +confirm 1/2/3/4 balances are same as before. + +Shutdown again, restore using importwallet, +and confirm again balances are correct. +""" + +from test_framework import BitcoinTestFramework +from util import * +from random import randint +import logging +logging.basicConfig(format='%(levelname)s:%(message)s', level=logging.INFO) + +class WalletBackupTest(BitcoinTestFramework): + + def setup_chain(self): + logging.info("Initializing test directory "+self.options.tmpdir) + initialize_chain_clean(self.options.tmpdir, 4) + + # This mirrors how the network was setup in the bash test + def setup_network(self, split=False): + # nodes 1, 2,3 are spenders, let's give them a keypool=100 + extra_args = [["-keypool=100"], ["-keypool=100"], ["-keypool=100"], []] + self.nodes = start_nodes(4, self.options.tmpdir, extra_args) + connect_nodes(self.nodes[0], 3) + connect_nodes(self.nodes[1], 3) + connect_nodes(self.nodes[2], 3) + connect_nodes(self.nodes[2], 0) + self.is_network_split=False + self.sync_all() + + def one_send(self, from_node, to_address): + if (randint(1,2) == 1): + amount = Decimal(randint(1,10)) / Decimal(10) + self.nodes[from_node].sendtoaddress(to_address, amount) + + def do_one_round(self): + a0 = self.nodes[0].getnewaddress() + a1 = self.nodes[1].getnewaddress() + a2 = self.nodes[2].getnewaddress() + + self.one_send(0, a1) + self.one_send(0, a2) + self.one_send(1, a0) + self.one_send(1, a2) + self.one_send(2, a0) + self.one_send(2, a1) + + # Have the miner (node3) mine a block. + # Must sync mempools before mining. + sync_mempools(self.nodes) + self.nodes[3].setgenerate(True, 1) + + # As above, this mirrors the original bash test. + def start_three(self): + self.nodes[0] = start_node(0, self.options.tmpdir) + self.nodes[1] = start_node(1, self.options.tmpdir) + self.nodes[2] = start_node(2, self.options.tmpdir) + connect_nodes(self.nodes[0], 3) + connect_nodes(self.nodes[1], 3) + connect_nodes(self.nodes[2], 3) + connect_nodes(self.nodes[2], 0) + + def stop_three(self): + stop_node(self.nodes[0], 0) + stop_node(self.nodes[1], 1) + stop_node(self.nodes[2], 2) + + def erase_three(self): + os.remove(self.options.tmpdir + "/node0/regtest/wallet.dat") + os.remove(self.options.tmpdir + "/node1/regtest/wallet.dat") + os.remove(self.options.tmpdir + "/node2/regtest/wallet.dat") + + def run_test(self): + logging.info("Generating initial blockchain") + self.nodes[0].setgenerate(True, 1) + sync_blocks(self.nodes) + self.nodes[1].setgenerate(True, 1) + sync_blocks(self.nodes) + self.nodes[2].setgenerate(True, 1) + sync_blocks(self.nodes) + self.nodes[3].setgenerate(True, 100) + sync_blocks(self.nodes) + + assert_equal(self.nodes[0].getbalance(), 50) + assert_equal(self.nodes[1].getbalance(), 50) + assert_equal(self.nodes[2].getbalance(), 50) + assert_equal(self.nodes[3].getbalance(), 0) + + logging.info("Creating transactions") + # Five rounds of sending each other transactions. + for i in range(5): + self.do_one_round() + + logging.info("Backing up") + tmpdir = self.options.tmpdir + self.nodes[0].backupwallet(tmpdir + "/node0/wallet.bak") + self.nodes[0].dumpwallet(tmpdir + "/node0/wallet.dump") + self.nodes[1].backupwallet(tmpdir + "/node1/wallet.bak") + self.nodes[1].dumpwallet(tmpdir + "/node1/wallet.dump") + self.nodes[2].backupwallet(tmpdir + "/node2/wallet.bak") + self.nodes[2].dumpwallet(tmpdir + "/node2/wallet.dump") + + logging.info("More transactions") + for i in range(5): + self.do_one_round() + + # Generate 101 more blocks, so any fees paid mature + self.nodes[3].setgenerate(True, 101) + self.sync_all() + + balance0 = self.nodes[0].getbalance() + balance1 = self.nodes[1].getbalance() + balance2 = self.nodes[2].getbalance() + balance3 = self.nodes[3].getbalance() + total = balance0 + balance1 + balance2 + balance3 + + # At this point, there are 214 blocks (103 for setup, then 10 rounds, then 101.) + # 114 are mature, so the sum of all wallets should be 114 * 50 = 5700. + assert_equal(total, 5700) + + ## + # Test restoring spender wallets from backups + ## + logging.info("Restoring using wallet.dat") + self.stop_three() + self.erase_three() + + # Start node2 with no chain + shutil.rmtree(self.options.tmpdir + "/node2/regtest/blocks") + shutil.rmtree(self.options.tmpdir + "/node2/regtest/chainstate") + + # Restore wallets from backup + shutil.copyfile(tmpdir + "/node0/wallet.bak", tmpdir + "/node0/regtest/wallet.dat") + shutil.copyfile(tmpdir + "/node1/wallet.bak", tmpdir + "/node1/regtest/wallet.dat") + shutil.copyfile(tmpdir + "/node2/wallet.bak", tmpdir + "/node2/regtest/wallet.dat") + + logging.info("Re-starting nodes") + self.start_three() + sync_blocks(self.nodes) + + assert_equal(self.nodes[0].getbalance(), balance0) + assert_equal(self.nodes[1].getbalance(), balance1) + assert_equal(self.nodes[2].getbalance(), balance2) + + logging.info("Restoring using dumped wallet") + self.stop_three() + self.erase_three() + + #start node2 with no chain + shutil.rmtree(self.options.tmpdir + "/node2/regtest/blocks") + shutil.rmtree(self.options.tmpdir + "/node2/regtest/chainstate") + + self.start_three() + + assert_equal(self.nodes[0].getbalance(), 0) + assert_equal(self.nodes[1].getbalance(), 0) + assert_equal(self.nodes[2].getbalance(), 0) + + self.nodes[0].importwallet(tmpdir + "/node0/wallet.dump") + self.nodes[1].importwallet(tmpdir + "/node1/wallet.dump") + self.nodes[2].importwallet(tmpdir + "/node2/wallet.dump") + + sync_blocks(self.nodes) + + assert_equal(self.nodes[0].getbalance(), balance0) + assert_equal(self.nodes[1].getbalance(), balance1) + assert_equal(self.nodes[2].getbalance(), balance2) + + +if __name__ == '__main__': + WalletBackupTest().main() diff --git a/qa/rpc-tests/walletbackup.sh b/qa/rpc-tests/walletbackup.sh deleted file mode 100755 index 4af3d97f35..0000000000 --- a/qa/rpc-tests/walletbackup.sh +++ /dev/null @@ -1,297 +0,0 @@ -#!/usr/bin/env bash -# Copyright (c) 2014 The Bitcoin Core developers -# Distributed under the MIT software license, see the accompanying -# file COPYING or http://www.opensource.org/licenses/mit-license.php. - -# Test wallet backup / dump / restore functionality - -# Test case is: -# 4 nodes. 1 2 3 and send transactions between each other, -# fourth node is a miner. -# 1 2 3 and each mine a block to start, then -# miner creates 100 blocks so 1 2 3 each have 50 mature -# coins to spend. -# Then 5 iterations of 1/2/3 sending coins amongst -# themselves to get transactions in the wallets, -# and the miner mining one block. -# -# Wallets are backed up using dumpwallet/backupwallet. -# Then 5 more iterations of transactions, then block. -# -# Miner then generates 101 more blocks, so any -# transaction fees paid mature. -# -# Sanity checks done: -# Miner balance >= 150*50 -# Sum(1,2,3,4 balances) == 153*150 -# -# 1/2/3 are shutdown, and their wallets erased. -# Then restore using wallet.dat backup. And -# confirm 1/2/3/4 balances are same as before. -# -# Shutdown again, restore using importwallet, -# and confirm again balances are correct. -# - -if [ $# -lt 1 ]; then - echo "Usage: $0 path_to_binaries" - echo "e.g. $0 ../../src" - echo "Env vars BITCOIND and BITCOINCLI may be used to specify the exact binaries used" - exit 1 -fi - -BITCOIND=${BITCOIND:-${1}/bitcoind} -CLI=${BITCOINCLI:-${1}/bitcoin-cli} - -DIR="${BASH_SOURCE%/*}" -SENDANDWAIT="${DIR}/send.sh" -if [[ ! -d "$DIR" ]]; then DIR="$PWD"; fi -. "$DIR/util.sh" - -D=$(mktemp -d test.XXXXX) - -echo "Starting nodes..." - -# "Miner": -D4=${D}/node4 -CreateDataDir $D4 port=11030 rpcport=11031 -B4ARGS="-datadir=$D4" -$BITCOIND $BITCOINDARGS $B4ARGS & -B4PID=$! - -# Want default keypool for 1/2/3, and -# don't need send-and-wait functionality, -# so don't use CreateDataDir: -function CreateConfDir { - DIR=$1 - mkdir -p $DIR - CONF=$DIR/bitcoin.conf - echo "regtest=1" >> $CONF - echo "rpcuser=rt" >> $CONF - echo "rpcpassword=rt" >> $CONF - echo "rpcwait=1" >> $CONF - shift - while (( "$#" )); do - echo $1 >> $CONF - shift - done -} - -# "Spenders" 1/2/3 -D1=${D}/node1 -CreateConfDir $D1 port=11000 rpcport=11001 addnode=127.0.0.1:11030 -B1ARGS="-datadir=$D1" -$BITCOIND $B1ARGS & -B1PID=$! -D2=${D}/node2 -CreateConfDir $D2 port=11010 rpcport=11011 addnode=127.0.0.1:11030 -B2ARGS="-datadir=$D2" -$BITCOIND $B2ARGS & -B2PID=$! -D3=${D}/node3 -CreateConfDir $D3 port=11020 rpcport=11021 addnode=127.0.0.1:11030 addnode=127.0.0.1:11000 -B3ARGS="-datadir=$D3" -$BITCOIND $BITCOINDARGS $B3ARGS & -B3PID=$! - -# Wait until all nodes are at the same block number -function WaitBlocks { - while : - do - sleep 1 - BLOCKS1=$( GetBlocks "$B1ARGS" ) - BLOCKS2=$( GetBlocks "$B2ARGS" ) - BLOCKS3=$( GetBlocks "$B3ARGS" ) - BLOCKS4=$( GetBlocks "$B4ARGS" ) - if (( BLOCKS1 == BLOCKS4 && BLOCKS2 == BLOCKS4 && BLOCKS3 == BLOCKS4 )) - then - break - fi - done -} - -# Wait until all nodes have the same txns in -# their memory pools -function WaitMemPools { - while : - do - sleep 1 - MEMPOOL1=$( $CLI "$B1ARGS" getrawmempool | sort | shasum ) - MEMPOOL2=$( $CLI "$B2ARGS" getrawmempool | sort | shasum ) - MEMPOOL3=$( $CLI "$B3ARGS" getrawmempool | sort | shasum ) - MEMPOOL4=$( $CLI "$B4ARGS" getrawmempool | sort | shasum ) - if [[ $MEMPOOL1 = $MEMPOOL4 && $MEMPOOL2 = $MEMPOOL4 && $MEMPOOL3 = $MEMPOOL4 ]] - then - break - fi - done -} - -echo "Generating initial blockchain..." - -# 1 block, 50 XBT each == 50 BTC -$CLI $B1ARGS setgenerate true 1 -WaitBlocks -$CLI $B2ARGS setgenerate true 1 -WaitBlocks -$CLI $B3ARGS setgenerate true 1 -WaitBlocks - -# 100 blocks, 0 mature -$CLI $B4ARGS setgenerate true 100 -WaitBlocks - -CheckBalance "$B1ARGS" 50 -CheckBalance "$B2ARGS" 50 -CheckBalance "$B3ARGS" 50 -CheckBalance "$B4ARGS" 0 - -echo "Creating transactions..." - -function S { - TXID=$( $CLI -datadir=${D}/node${1} sendtoaddress ${2} "${3}" 0 ) - if [ x$TXID = x ] ; then - echoerr "node${1}: error sending ${3} btc" - echo -n "node${1} balance: " - $CLI -datadir=${D}/node${1} getbalance "*" 0 - exit 1 - fi -} - -function OneRound { - A1=$( $CLI $B1ARGS getnewaddress ) - A2=$( $CLI $B2ARGS getnewaddress ) - A3=$( $CLI $B3ARGS getnewaddress ) - if [[ $(( $RANDOM%2 )) < 1 ]] ; then - N=$(( $RANDOM % 9 + 1 )) - S 1 $A2 "0.$N" - fi - if [[ $(( $RANDOM%2 )) < 1 ]] ; then - N=$(( $RANDOM % 9 + 1 )) - S 1 $A3 "0.0$N" - fi - if [[ $(( $RANDOM%2 )) < 1 ]] ; then - N=$(( $RANDOM % 9 + 1 )) - S 2 $A1 "0.$N" - fi - if [[ $(( $RANDOM%2 )) < 1 ]] ; then - N=$(( $RANDOM % 9 + 1 )) - S 2 $A3 "0.$N" - fi - if [[ $(( $RANDOM%2 )) < 1 ]] ; then - N=$(( $RANDOM % 9 + 1 )) - S 3 $A1 "0.$N" - fi - if [[ $(( $RANDOM%2 )) < 1 ]] ; then - N=$(( $RANDOM % 9 + 1 )) - S 3 $A2 "0.0$N" - fi - $CLI "$B4ARGS" setgenerate true 1 -} - -for i in {1..5}; do OneRound ; done - -echo "Backing up..." - -$CLI "$B1ARGS" backupwallet "$D1/wallet.bak" -$CLI "$B1ARGS" dumpwallet "$D1/wallet.dump" -$CLI "$B2ARGS" backupwallet "$D2/wallet.bak" -$CLI "$B2ARGS" dumpwallet "$D2/wallet.dump" -$CLI "$B3ARGS" backupwallet "$D3/wallet.bak" -$CLI "$B3ARGS" dumpwallet "$D3/wallet.dump" - -echo "More transactions..." -for i in {1..5}; do OneRound ; done - -WaitMemPools - -# Generate 101 more blocks, so any fees paid -# mature -$CLI "$B4ARGS" setgenerate true 101 - -BALANCE1=$( $CLI "$B1ARGS" getbalance ) -BALANCE2=$( $CLI "$B2ARGS" getbalance ) -BALANCE3=$( $CLI "$B3ARGS" getbalance ) -BALANCE4=$( $CLI "$B4ARGS" getbalance ) - -TOTAL=$( dc -e "$BALANCE1 $BALANCE2 $BALANCE3 $BALANCE4 + + + p" ) - -AssertEqual $TOTAL 5700.00000000 - -function StopThree { - $CLI $B1ARGS stop > /dev/null 2>&1 - $CLI $B2ARGS stop > /dev/null 2>&1 - $CLI $B3ARGS stop > /dev/null 2>&1 - wait $B1PID - wait $B2PID - wait $B3PID -} -function EraseThree { - rm $D1/regtest/wallet.dat - rm $D2/regtest/wallet.dat - rm $D3/regtest/wallet.dat -} -function StartThree { - $BITCOIND $BITCOINDARGS $B1ARGS & - B1PID=$! - $BITCOIND $BITCOINDARGS $B2ARGS & - B2PID=$! - $BITCOIND $BITCOINDARGS $B3ARGS & - B3PID=$! -} - -echo "Restoring using wallet.dat" - -StopThree -EraseThree - -# Start node3 with no chain -rm -rf $D3/regtest/blocks -rm -rf $D3/regtest/chainstate -rm -rf $D3/regtest/database - -cp $D1/wallet.bak $D1/regtest/wallet.dat -cp $D2/wallet.bak $D2/regtest/wallet.dat -cp $D3/wallet.bak $D3/regtest/wallet.dat - -StartThree -WaitBlocks - -AssertEqual $BALANCE1 $( $CLI "$B1ARGS" getbalance ) -AssertEqual $BALANCE2 $( $CLI "$B2ARGS" getbalance ) -AssertEqual $BALANCE3 $( $CLI "$B3ARGS" getbalance ) - -echo "Restoring using dumped wallet" - -StopThree -EraseThree - -# Start node3 with no chain -rm -rf $D3/regtest/blocks -rm -rf $D3/regtest/chainstate -rm -rf $D3/regtest/database - -StartThree - -AssertEqual 0 $( $CLI "$B1ARGS" getbalance ) -AssertEqual 0 $( $CLI "$B2ARGS" getbalance ) -AssertEqual 0 $( $CLI "$B3ARGS" getbalance ) - -$CLI "$B1ARGS" importwallet $D1/wallet.dump -$CLI "$B2ARGS" importwallet $D2/wallet.dump -$CLI "$B3ARGS" importwallet $D3/wallet.dump - -WaitBlocks - -AssertEqual $BALANCE1 $( $CLI "$B1ARGS" getbalance ) -AssertEqual $BALANCE2 $( $CLI "$B2ARGS" getbalance ) -AssertEqual $BALANCE3 $( $CLI "$B3ARGS" getbalance ) - -StopThree -$CLI $B4ARGS stop > /dev/null 2>&1 -wait $B4PID - -echo "Tests successful, cleaning up" -trap "" EXIT -rm -rf $D -exit 0 diff --git a/qa/rpc-tests/zapwallettxes.py b/qa/rpc-tests/zapwallettxes.py new file mode 100755 index 0000000000..a773575906 --- /dev/null +++ b/qa/rpc-tests/zapwallettxes.py @@ -0,0 +1,82 @@ +#!/usr/bin/env python2 +# Copyright (c) 2014 The Bitcoin Core developers +# Distributed under the MIT software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +from test_framework import BitcoinTestFramework +from util import * + + +class ZapWalletTXesTest (BitcoinTestFramework): + + def setup_chain(self): + print("Initializing test directory "+self.options.tmpdir) + initialize_chain_clean(self.options.tmpdir, 3) + + def setup_network(self, split=False): + self.nodes = start_nodes(3, self.options.tmpdir) + connect_nodes_bi(self.nodes,0,1) + connect_nodes_bi(self.nodes,1,2) + connect_nodes_bi(self.nodes,0,2) + self.is_network_split=False + self.sync_all() + + def run_test (self): + print "Mining blocks..." + self.nodes[0].setgenerate(True, 1) + self.sync_all() + self.nodes[1].setgenerate(True, 101) + self.sync_all() + + assert_equal(self.nodes[0].getbalance(), 50) + + txid0 = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 11) + txid1 = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 10) + self.sync_all() + self.nodes[0].setgenerate(True, 1) + self.sync_all() + + txid2 = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 11) + txid3 = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 10) + + tx0 = self.nodes[0].gettransaction(txid0) + assert_equal(tx0['txid'], txid0) #tx0 must be available (confirmed) + + tx1 = self.nodes[0].gettransaction(txid1) + assert_equal(tx1['txid'], txid1) #tx1 must be available (confirmed) + + tx2 = self.nodes[0].gettransaction(txid2) + assert_equal(tx2['txid'], txid2) #tx2 must be available (unconfirmed) + + tx3 = self.nodes[0].gettransaction(txid3) + assert_equal(tx3['txid'], txid3) #tx3 must be available (unconfirmed) + + #restart bitcoind + self.nodes[0].stop() + bitcoind_processes[0].wait() + self.nodes[0] = start_node(0,self.options.tmpdir) + + tx3 = self.nodes[0].gettransaction(txid3) + assert_equal(tx3['txid'], txid3) #tx must be available (unconfirmed) + + self.nodes[0].stop() + bitcoind_processes[0].wait() + + #restart bitcoind with zapwallettxes + self.nodes[0] = start_node(0,self.options.tmpdir, ["-zapwallettxes=1"]) + + aException = False + try: + tx3 = self.nodes[0].gettransaction(txid3) + except JSONRPCException,e: + print e + aException = True + + assert_equal(aException, True) #there must be a expection because the unconfirmed wallettx0 must be gone by now + + tx0 = self.nodes[0].gettransaction(txid0) + assert_equal(tx0['txid'], txid0) #tx0 (confirmed) must still be available because it was confirmed + + +if __name__ == '__main__': + ZapWalletTXesTest ().main () diff --git a/qa/rpc-tests/zapwallettxes.sh b/qa/rpc-tests/zapwallettxes.sh deleted file mode 100755 index 4312d84e94..0000000000 --- a/qa/rpc-tests/zapwallettxes.sh +++ /dev/null @@ -1,165 +0,0 @@ -#!/usr/bin/env bash -# Copyright (c) 2014 The Bitcoin Core developers -# Distributed under the MIT software license, see the accompanying -# file COPYING or http://www.opensource.org/licenses/mit-license.php. - -# Test -zapwallettxes=<mode> - -if [ $# -lt 1 ]; then - echo "Usage: $0 path_to_binaries" - echo "e.g. $0 ../../src" - echo "Env vars BITCOIND and BITCOINCLI may be used to specify the exact binaries used" - exit 1 -fi - -set -f - -BITCOIND=${BITCOIND:-${1}/bitcoind} -CLI=${BITCOINCLI:-${1}/bitcoin-cli} - -DIR="${BASH_SOURCE%/*}" -SENDANDWAIT="${DIR}/send.sh" -if [[ ! -d "$DIR" ]]; then DIR="$PWD"; fi -. "$DIR/util.sh" - -D=$(mktemp -d test.XXXXX) - -D1=${D}/node1 -CreateDataDir "$D1" port=11000 rpcport=11001 -B1ARGS="-datadir=$D1" -$BITCOIND $B1ARGS & -B1PID=$! - -D2=${D}/node2 -CreateDataDir "$D2" port=11010 rpcport=11011 -B2ARGS="-datadir=$D2" -$BITCOIND $B2ARGS & -B2PID=$! - -function CleanUp { -$CLI $B2ARGS stop > /dev/null 2>&1 -wait $B2PID -$CLI $B1ARGS stop > /dev/null 2>&1 -wait $B1PID - -rm -rf $D -} - -# 110 blocks, 10 mature == 500 XBT -$CLI $B1ARGS setgenerate true 110 -$CLI $B2ARGS setgenerate true 110 - -CheckBalance "$B1ARGS" 500 -CheckBalance "$B2ARGS" 500 - -# Send 10 XBT -TXID1_DEFAULT=$($CLI $B1ARGS sendtoaddress "mrhz5ZgSF3C1BSdyCKt3gEdhKoRL5BNfJV" 10) -TXID2_DEFAULT=$($CLI $B2ARGS sendtoaddress "mrhz5ZgSF3C1BSdyCKt3gEdhKoRL5BNfJV" 10) - -CheckBalance $B1ARGS 490 -CheckBalance $B2ARGS 490 - -# Move 10 XBT to testaccount -TMP=$($CLI $B1ARGS move "" "testaccount" 10) -TMP=$($CLI $B2ARGS move "" "testaccount" 10) - -CheckBalance $B1ARGS 10 "testaccount" -CheckBalance $B2ARGS 10 "testaccount" - -# Send 1 XBT from testaccount -TXID1_TESTACCOUNT=$($CLI $B1ARGS sendfrom "testaccount" "mrhz5ZgSF3C1BSdyCKt3gEdhKoRL5BNfJV" 1) -TXID2_TESTACCOUNT=$($CLI $B2ARGS sendfrom "testaccount" "mrhz5ZgSF3C1BSdyCKt3gEdhKoRL5BNfJV" 1) - -CheckBalance $B1ARGS 9 "testaccount" -CheckBalance $B2ARGS 9 "testaccount" - -CheckBalance $B1ARGS 489 -CheckBalance $B2ARGS 489 - -# Confirm transactions -$CLI $B1ARGS setgenerate true 1 -$CLI $B2ARGS setgenerate true 1 - -# Create unconfirmed transaction -TXID1_UNCONFIRMED=$($CLI $B1ARGS sendtoaddress "mrhz5ZgSF3C1BSdyCKt3gEdhKoRL5BNfJV" 1) -TXID2_UNCONFIRMED=$($CLI $B2ARGS sendtoaddress "mrhz5ZgSF3C1BSdyCKt3gEdhKoRL5BNfJV" 1) - -# check balance (we created another 50 and spent 1 in the meantime) -CheckBalance $B1ARGS 538 -CheckBalance $B2ARGS 538 - -# Safety check, if unconfirmed transactions are there -$CLI $B1ARGS gettransaction $TXID1_UNCONFIRMED > /dev/null 2>&1 -if [[ $? -ne 0 ]] ; then - echoerr "gettransaction1_1: $TXID1_UNCONFIRMED failed" - CleanUp - exit 1 -fi -$CLI $B2ARGS gettransaction $TXID2_UNCONFIRMED > /dev/null 2>&1 -if [[ $? -ne 0 ]] ; then - echoerr "gettransaction2_1: $TXID2_UNCONFIRMED failed" - CleanUp - exit 1 -fi - -# stop nodes -$CLI $B2ARGS stop > /dev/null 2>&1 -wait $B2PID -$CLI $B1ARGS stop > /dev/null 2>&1 -wait $B1PID - -# restart nodes with -zapwallettxes -$BITCOIND -zapwallettxes=1 $B1ARGS & -B1PID=$! -$BITCOIND -zapwallettxes=2 $B2ARGS & -B2PID=$! - -# check if confirmed transactions are there -$CLI $B1ARGS gettransaction $TXID1_DEFAULT > /dev/null 2>&1 -if [[ $? -ne 0 ]] ; then - echoerr "check confirmed transaction 1: $TXID1_DEFAULT failed" - CleanUp - exit 1 -fi -$CLI $B2ARGS gettransaction $TXID2_DEFAULT > /dev/null 2>&1 -if [[ $? -ne 0 ]] ; then - echoerr "check confirmed transaction 2: $TXID2_DEFAULT failed" - CleanUp - exit 1 -fi -$CLI $B1ARGS gettransaction $TXID1_TESTACCOUNT > /dev/null 2>&1 -if [[ $? -ne 0 ]] ; then - echoerr "check confirmed transaction 3: $TXID1_TESTACCOUNT failed" - CleanUp - exit 1 -fi -$CLI $B2ARGS gettransaction $TXID2_TESTACCOUNT > /dev/null 2>&1 -if [[ $? -ne 0 ]] ; then - echoerr "check confirmed transaction 4: $TXID2_TESTACCOUNT failed" - CleanUp - exit 1 -fi - -# check if unconfirmed transaction is gone -$CLI $B1ARGS gettransaction $TXID1_UNCONFIRMED > /dev/null 2>&1 -if [[ $? -eq 0 ]] ; then - echoerr "check unconfirmed transaction 1: $TXID1_UNCONFIRMED failed" - CleanUp - exit 1 -fi -$CLI $B2ARGS gettransaction $TXID2_UNCONFIRMED > /dev/null 2>&1 -if [[ $? -eq 0 ]] ; then - echoerr "check unconfirmed transaction 2: $TXID2_UNCONFIRMED failed" - CleanUp - exit 1 -fi - -# check zapwallet mode 1, testaccount balance must be 9 (keeping transaction metadata) -CheckBalance $B1ARGS 9 "testaccount" - -# check zapwallet mode 2, testaccount balance must be 10 (dropping transaction metadata) -CheckBalance $B2ARGS 10 "testaccount" - -echo "Tests successful, cleaning up" -CleanUp -exit 0 |