From 189fb526f188e90eed24840b826b6c6b97f3e479 Mon Sep 17 00:00:00 2001 From: mrbandrews Date: Wed, 19 Nov 2014 15:55:40 -0500 Subject: [PATCH 1/2] Port of wallet.sh to python (wallet.py). Also included are minor edits to util.py to create a clean blockchain and add a parameter to gather_inputs to specify number of confirmations. --- qa/rpc-tests/util.py | 16 ++++-- qa/rpc-tests/wallet.py | 100 ++++++++++++++++++++++++++++++++++ qa/rpc-tests/wallet.sh | 118 ----------------------------------------- 3 files changed, 113 insertions(+), 121 deletions(-) create mode 100755 qa/rpc-tests/wallet.py delete mode 100755 qa/rpc-tests/wallet.sh diff --git a/qa/rpc-tests/util.py b/qa/rpc-tests/util.py index c6d918a81..bed7fed8c 100644 --- a/qa/rpc-tests/util.py +++ b/qa/rpc-tests/util.py @@ -57,7 +57,6 @@ def sync_mempools(rpc_connections): if num_match == len(rpc_connections): break time.sleep(1) - bitcoind_processes = {} @@ -130,6 +129,15 @@ def initialize_chain(test_dir): shutil.copytree(from_dir, to_dir) initialize_datadir(test_dir, i) # Overwrite port/rpcport in bitcoin.conf +def initialize_chain_clean(test_dir, num_nodes): + """ + Create an empty blockchain and num_nodes wallets. + Useful if a test case wants complete control over initialization. + """ + for i in range(num_nodes): + datadir=initialize_datadir(test_dir, i) + + def _rpchost_to_args(rpchost): '''Convert optional IP:port spec to rpcconnect/rpcport args''' if rpchost is None: @@ -221,11 +229,13 @@ def find_output(node, txid, amount): return i raise RuntimeError("find_output txid %s : %s not found"%(txid,str(amount))) -def gather_inputs(from_node, amount_needed): + +def gather_inputs(from_node, amount_needed, confirmations_required=1): """ Return a random set of unspent txouts that are enough to pay amount_needed """ - utxo = from_node.listunspent(1) + assert(confirmations_required >=0) + utxo = from_node.listunspent(confirmations_required) random.shuffle(utxo) inputs = [] total_in = Decimal("0.00000000") diff --git a/qa/rpc-tests/wallet.py b/qa/rpc-tests/wallet.py new file mode 100755 index 000000000..4271d96be --- /dev/null +++ b/qa/rpc-tests/wallet.py @@ -0,0 +1,100 @@ +#!/usr/bin/env python +# Copyright (c) 2014 The Bitcoin Core developers +# Distributed under the MIT/X11 software license, see the accompanying +# file COPYING or http://www.opensource.org/licenses/mit-license.php. + +# +# Exercise the wallet. Ported from wallet.sh. +# Does the following: +# a) creates 3 nodes, with an empty chain (no blocks). +# b) node0 mines a block +# c) node1 mines 101 blocks, so now nodes 0 and 1 have 50btc, node2 has none. +# d) node0 sends 21 btc to node2, in two transactions (11 btc, then 10 btc). +# e) node0 mines a block, collects the fee on the second transaction +# f) node1 mines 100 blocks, to mature node0's just-mined block +# g) check that node0 has 100-21, node2 has 21 +# h) node0 should now have 2 unspent outputs; send these to node2 via raw tx broadcast by node1 +# i) have node1 mine a block +# j) check balances - node0 should have 0, node2 should have 100 +# + +from test_framework import BitcoinTestFramework +from util import * + + +class WalletTest (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) + assert_equal(self.nodes[1].getbalance(), 50) + assert_equal(self.nodes[2].getbalance(), 0) + + # Send 21 BTC from 0 to 2 using sendtoaddress call. + # Second transaction will be child of first, and will require a fee + 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. + self.nodes[0].setgenerate(True, 1) + self.sync_all() + + # Have node1 generate 100 blocks (so node0 can recover the fee) + self.nodes[1].setgenerate(True, 100) + self.sync_all() + + # node0 should end up with 100 btc in block rewards plus fees, but + # minus the 21 plus fees sent to node2 + assert_equal(self.nodes[0].getbalance(), 100-21) + assert_equal(self.nodes[2].getbalance(), 21) + + # Node0 should have two unspent outputs. + # Create a couple of transactions to send them to node2, submit them through + # node1, and make sure both node0 and node2 pick them up properly: + node0utxos = self.nodes[0].listunspent(1) + assert_equal(len(node0utxos), 2) + + # create both transactions + txns_to_send = [] + for utxo in node0utxos: + inputs = [] + outputs = {} + inputs.append({ "txid" : utxo["txid"], "vout" : utxo["vout"]}) + outputs[self.nodes[2].getnewaddress("from1")] = utxo["amount"] + raw_tx = self.nodes[0].createrawtransaction(inputs, outputs) + txns_to_send.append(self.nodes[0].signrawtransaction(raw_tx)) + + # Have node 1 (miner) send the transactions + self.nodes[1].sendrawtransaction(txns_to_send[0]["hex"], True) + self.nodes[1].sendrawtransaction(txns_to_send[1]["hex"], True) + + # Have node1 mine a block to confirm transactions: + self.nodes[1].setgenerate(True, 1) + self.sync_all() + + assert_equal(self.nodes[0].getbalance(), 0) + assert_equal(self.nodes[2].getbalance(), 100) + assert_equal(self.nodes[2].getbalance("from1"), 100-21) + + +if __name__ == '__main__': + WalletTest ().main () diff --git a/qa/rpc-tests/wallet.sh b/qa/rpc-tests/wallet.sh deleted file mode 100755 index c9ad0f2a7..000000000 --- a/qa/rpc-tests/wallet.sh +++ /dev/null @@ -1,118 +0,0 @@ -#!/usr/bin/env bash -# Copyright (c) 2013-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 block generation and basic wallet sending - -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 connect=127.0.0.1:11000 -B2ARGS="-datadir=$D2" -$BITCOIND $B2ARGS & -B2PID=$! - -D3=${D}/node3 -CreateDataDir "$D3" port=11020 rpcport=11021 connect=127.0.0.1:11000 -B3ARGS="-datadir=$D3" -$BITCOIND $BITCOINDARGS $B3ARGS & -B3PID=$! - -# Wait until all three nodes are at the same block number -function WaitBlocks { - while : - do - sleep 1 - declare -i BLOCKS1=$( GetBlocks $B1ARGS ) - declare -i BLOCKS2=$( GetBlocks $B2ARGS ) - declare -i BLOCKS3=$( GetBlocks $B3ARGS ) - if (( BLOCKS1 == BLOCKS2 && BLOCKS2 == BLOCKS3 )) - then - break - fi - done -} - -echo "Generating test blockchain..." - -# 1 block, 50 XBT each == 50 XBT -$CLI $B1ARGS setgenerate true 1 -WaitBlocks -# 101 blocks, 1 mature == 50 XBT -$CLI $B2ARGS setgenerate true 101 -WaitBlocks - -CheckBalance "$B1ARGS" 50 -CheckBalance "$B2ARGS" 50 - -# Send 21 XBT from 1 to 3. Second -# transaction will be child of first, and -# will require a fee -Send $B1ARGS $B3ARGS 11 -Send $B1ARGS $B3ARGS 10 - -# Have B1 mine a new block, and mature it -# to recover transaction fees -$CLI $B1ARGS setgenerate true 1 -WaitBlocks - -# Have B2 mine 100 blocks so B1's block is mature: -$CLI $B2ARGS setgenerate true 100 -WaitBlocks - -# B1 should end up with 100 XBT in block rewards plus fees, -# minus the 21 XBT sent to B3: -CheckBalance "$B1ARGS" "100-21" -CheckBalance "$B3ARGS" "21" - -# B1 should have two unspent outputs; create a couple -# of raw transactions to send them to B3, submit them through -# B2, and make sure both B1 and B3 pick them up properly: -RAW1=$(CreateTxn1 $B1ARGS 1 $(Address $B3ARGS "from1" ) ) -RAW2=$(CreateTxn1 $B1ARGS 2 $(Address $B3ARGS "from1" ) ) -RAWTXID1=$(SendRawTxn "$B2ARGS" $RAW1) -RAWTXID2=$(SendRawTxn "$B2ARGS" $RAW2) - -# Have B2 mine a block to confirm transactions: -$CLI $B2ARGS setgenerate true 1 -WaitBlocks - -# Check balances after confirmation -CheckBalance "$B1ARGS" 0 -CheckBalance "$B3ARGS" 100 -CheckBalance "$B3ARGS" "100-21" "from1" - -$CLI $B3ARGS stop > /dev/null 2>&1 -wait $B3PID -$CLI $B2ARGS stop > /dev/null 2>&1 -wait $B2PID -$CLI $B1ARGS stop > /dev/null 2>&1 -wait $B1PID - -echo "Tests successful, cleaning up" -rm -rf $D -exit 0 From e4ef72449349a011110b23e5e26ce2c083801fb0 Mon Sep 17 00:00:00 2001 From: mrbandrews Date: Thu, 20 Nov 2014 14:27:18 -0500 Subject: [PATCH 2/2] Edited rpc-tests to run python script not shell script. --- qa/pull-tester/rpc-tests.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qa/pull-tester/rpc-tests.sh b/qa/pull-tester/rpc-tests.sh index 0b5ad2064..7da7404ad 100755 --- a/qa/pull-tester/rpc-tests.sh +++ b/qa/pull-tester/rpc-tests.sh @@ -16,7 +16,7 @@ fi #Run the tests if [ "x${ENABLE_BITCOIND}${ENABLE_UTILS}${ENABLE_WALLET}" = "x111" ]; then - ${BUILDDIR}/qa/rpc-tests/wallet.sh "${BUILDDIR}/src" + ${BUILDDIR}/qa/rpc-tests/wallet.py --srcdir "${BUILDDIR}/src" ${BUILDDIR}/qa/rpc-tests/listtransactions.py --srcdir "${BUILDDIR}/src" #${BUILDDIR}/qa/rpc-tests/forknotify.py --srcdir "${BUILDDIR}/src" else