From 93a18a3650292afbb441a47d1fa1b94aeb0164e3 Mon Sep 17 00:00:00 2001 From: Gavin Andresen Date: Sat, 15 Feb 2014 16:38:28 -0500 Subject: Remove CWalletTx::vfSpent Use the spent outpoint multimap to figure out which wallet transaction outputs are unspent, instead of a vfSpent array that is saved to disk. --- qa/rpc-tests/README.md | 5 +- qa/rpc-tests/conflictedbalance.sh | 143 ++++++++++++++++++++++++++++++++++++++ qa/rpc-tests/txnmall.sh | 58 ++++++++-------- qa/rpc-tests/util.sh | 5 +- qa/rpc-tests/wallet.sh | 39 ++++++----- 5 files changed, 197 insertions(+), 53 deletions(-) create mode 100755 qa/rpc-tests/conflictedbalance.sh (limited to 'qa') diff --git a/qa/rpc-tests/README.md b/qa/rpc-tests/README.md index ee9e8b35ca..15aede6c41 100644 --- a/qa/rpc-tests/README.md +++ b/qa/rpc-tests/README.md @@ -1,9 +1,10 @@ Regression tests of RPC interface ================================= -wallet.sh : Exercise wallet send/receive code. +Bash scripts that use the RPC interface and command-line bitcoin-cli to test +full functionality in -regtest mode. -walletbackup.sh : Exercise wallet backup / dump / import +wallet.sh : Exercise wallet send/receive code. txnmall.sh : Test proper accounting of malleable transactions diff --git a/qa/rpc-tests/conflictedbalance.sh b/qa/rpc-tests/conflictedbalance.sh new file mode 100755 index 0000000000..9d854d2d87 --- /dev/null +++ b/qa/rpc-tests/conflictedbalance.sh @@ -0,0 +1,143 @@ +#!/usr/bin/env bash + +# Test marking of spent outputs + +# Create a transaction graph with four transactions, +# A/B/C/D +# C spends A +# D spends B and C + +# Then simulate C being mutated, to create C' +# that is mined. +# A is still (correctly) considered spent. +# B should be treated as unspent + +if [ $# -lt 1 ]; then + echo "Usage: $0 path_to_binaries" + echo "e.g. $0 ../../src" + exit 1 +fi + +set -f + +BITCOIND=${1}/bitcoind +CLI=${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) + +# Two nodes; one will play the part of merchant, the +# other an evil transaction-mutating miner. + +D1=${D}/node1 +CreateDataDir $D1 port=11000 rpcport=11001 +B1ARGS="-datadir=$D1 -debug=mempool" +$BITCOIND $B1ARGS & +B1PID=$! + +D2=${D}/node2 +CreateDataDir $D2 port=11010 rpcport=11011 +B2ARGS="-datadir=$D2 -debug=mempool" +$BITCOIND $B2ARGS & +B2PID=$! + +# Wait until all four nodes are at the same block number +function WaitBlocks { + while : + do + sleep 1 + declare -i BLOCKS1=$( GetBlocks $B1ARGS ) + declare -i BLOCKS2=$( GetBlocks $B2ARGS ) + if (( BLOCKS1 == BLOCKS2 )) + then + break + fi + done +} + +# Wait until node has $N peers +function WaitPeers { + while : + do + declare -i PEERS=$( $CLI $1 getconnectioncount ) + if (( PEERS == "$2" )) + then + break + fi + sleep 1 + done +} + +echo "Generating test blockchain..." + +# Start with B2 connected to B1: +$CLI $B2ARGS addnode 127.0.0.1:11000 onetry +WaitPeers "$B1ARGS" 1 + +# 2 block, 50 XBT each == 100 XBT +# These will be transactions "A" and "B" +$CLI $B1ARGS setgenerate true 2 + +WaitBlocks +# 100 blocks, 0 mature == 0 XBT +$CLI $B2ARGS setgenerate true 100 +WaitBlocks + +CheckBalance "$B1ARGS" 100 +CheckBalance "$B2ARGS" 0 + +# restart B2 with no connection +$CLI $B2ARGS stop > /dev/null 2>&1 +wait $B2PID +$BITCOIND $B2ARGS & +B2PID=$! + +B1ADDRESS=$( $CLI $B1ARGS getnewaddress ) +B2ADDRESS=$( $CLI $B2ARGS getnewaddress ) + +# Transaction C: send-to-self, spend A +TXID_C=$( $CLI $B1ARGS sendtoaddress $B1ADDRESS 50.0) + +# Transaction D: spends B and C +TXID_D=$( $CLI $B1ARGS sendtoaddress $B2ADDRESS 100.0) + +CheckBalance "$B1ARGS" 0 + +# Mutate TXID_C and add it to B2's memory pool: +RAWTX_C=$( $CLI $B1ARGS getrawtransaction $TXID_C ) + +# ... mutate C to create C' +L=${RAWTX_C:82:2} +NEWLEN=$( printf "%x" $(( 16#$L + 1 )) ) +MUTATEDTX_C=${RAWTX_C:0:82}${NEWLEN}4c${RAWTX_C:84} +# ... give mutated tx1 to B2: +MUTATEDTXID=$( $CLI $B2ARGS sendrawtransaction $MUTATEDTX_C ) + +echo "TXID_C: " $TXID_C +echo "Mutated: " $MUTATEDTXID + +# Re-connect nodes, and have both nodes mine some blocks: +$CLI $B2ARGS addnode 127.0.0.1:11000 onetry +WaitPeers "$B1ARGS" 1 + +# Having B2 mine the next block puts the mutated +# transaction C in the chain: +$CLI $B2ARGS setgenerate true 1 +WaitBlocks + +# B1 should still be able to spend 100, because D is conflicted +# so does not count as a spend of B +CheckBalance "$B1ARGS" 100 + +$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 diff --git a/qa/rpc-tests/txnmall.sh b/qa/rpc-tests/txnmall.sh index 06e4f7102d..11e0276494 100755 --- a/qa/rpc-tests/txnmall.sh +++ b/qa/rpc-tests/txnmall.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash -# Test block generation and basic wallet sending +# Test proper accounting with malleable transactions if [ $# -lt 1 ]; then echo "Usage: $0 path_to_binaries" @@ -35,16 +35,14 @@ B2ARGS="-datadir=$D2" $BITCOIND $B2ARGS & B2PID=$! -trap "kill -9 $B1PID $B2PID; rm -rf $D" EXIT - -# Wait until all four nodes are at the same block number +# Wait until both nodes are at the same block number function WaitBlocks { while : do sleep 1 - BLOCKS1=$( GetBlocks $B1ARGS ) - BLOCKS2=$( GetBlocks $B2ARGS ) - if (( $BLOCKS1 == $BLOCKS2 )) + declare -i BLOCKS1=$( GetBlocks $B1ARGS ) + declare -i BLOCKS2=$( GetBlocks $B2ARGS ) + if (( BLOCKS1 == BLOCKS2 )) then break fi @@ -55,8 +53,8 @@ function WaitBlocks { function WaitPeers { while : do - PEERS=$( $CLI $1 getconnectioncount ) - if (( "$PEERS" == $2 )) + declare -i PEERS=$( $CLI $1 getconnectioncount ) + if (( PEERS == "$2" )) then break fi @@ -64,6 +62,8 @@ function WaitPeers { done } +echo "Generating test blockchain..." + # Start with B2 connected to B1: $CLI $B2ARGS addnode 127.0.0.1:11000 onetry WaitPeers "$B1ARGS" 1 @@ -76,8 +76,8 @@ WaitBlocks $CLI $B2ARGS setgenerate true 100 WaitBlocks -CheckBalance $B1ARGS 50 -CheckBalance $B2ARGS 0 +CheckBalance "$B1ARGS" 50 +CheckBalance "$B2ARGS" 0 # restart B2 with no connection $CLI $B2ARGS stop > /dev/null 2>&1 @@ -85,20 +85,18 @@ wait $B2PID $BITCOIND $B2ARGS & B2PID=$! -B2ADDRESS=$( $CLI $B2ARGS getnewaddress ) +B2ADDRESS=$( $CLI $B2ARGS getaccountaddress "from1" ) # Have B1 create two transactions; second will # spend change from first, since B1 starts with only a single # 50 bitcoin output: -$CLI $B1ARGS move "" "foo" 10.0 -$CLI $B1ARGS move "" "bar" 10.0 +$CLI $B1ARGS move "" "foo" 10.0 > /dev/null +$CLI $B1ARGS move "" "bar" 10.0 > /dev/null TXID1=$( $CLI $B1ARGS sendfrom foo $B2ADDRESS 1.0 0) TXID2=$( $CLI $B1ARGS sendfrom bar $B2ADDRESS 2.0 0) # Mutate TXID1 and add it to B2's memory pool: RAWTX1=$( $CLI $B1ARGS getrawtransaction $TXID1 ) -RAWTX2=$( $CLI $B1ARGS getrawtransaction $TXID2 ) -# ... mutate RAWTX1: # RAWTX1 is hex-encoded, serialized transaction. So each # byte is two characters; we'll prepend the first # "push" in the scriptsig with OP_PUSHDATA1 (0x4c), @@ -123,28 +121,28 @@ echo "TXID1: " $TXID1 echo "Mutated: " $MUTATEDTXID # Re-connect nodes, and have B2 mine a block +# containing the mutant: $CLI $B2ARGS addnode 127.0.0.1:11000 onetry -WaitPeers "$B1ARGS" 1 - -$CLI $B2ARGS setgenerate true 3 -WaitBlocks -$CLI $B1ARGS setgenerate true 3 +$CLI $B2ARGS setgenerate true 1 WaitBlocks +# B1 should have 49 BTC; the 2 BTC send is +# conflicted, and should not count in +# balances. +CheckBalance "$B1ARGS" 49 +CheckBalance "$B1ARGS" 49 "*" +CheckBalance "$B1ARGS" 9 "foo" +CheckBalance "$B1ARGS" 10 "bar" + +# B2 should have 51 BTC +CheckBalance "$B2ARGS" 51 +CheckBalance "$B2ARGS" 1 "from1" + $CLI $B2ARGS stop > /dev/null 2>&1 wait $B2PID $CLI $B1ARGS stop > /dev/null 2>&1 wait $B1PID -trap "" EXIT - -echo "Done, bitcoind's shut down. To rerun/poke around:" -echo "${1}/bitcoind -datadir=$D1 -daemon" -echo "${1}/bitcoind -datadir=$D2 -daemon -connect=127.0.0.1:11000" -echo "To cleanup:" -echo "killall bitcoind; rm -rf test.*" -exit 0 - echo "Tests successful, cleaning up" rm -rf $D exit 0 diff --git a/qa/rpc-tests/util.sh b/qa/rpc-tests/util.sh index d1e4c941cc..9001c42fbc 100644 --- a/qa/rpc-tests/util.sh +++ b/qa/rpc-tests/util.sh @@ -41,8 +41,9 @@ function AssertEqual { # CheckBalance -datadir=... amount account minconf function CheckBalance { + declare -i EXPECT="$2" B=$( $CLI $1 getbalance $3 $4 ) - if (( $( echo "$B == $2" | bc ) == 0 )) + if (( $( echo "$B == $EXPECT" | bc ) == 0 )) then echoerr "bad balance: $B (expected $2)" exit 1 @@ -87,5 +88,5 @@ function SendRawTxn { # Use: GetBlocks # returns number of blocks from getinfo function GetBlocks { - ExtractKey blocks "$( $CLI $1 getinfo )" + $CLI $1 getblockcount } diff --git a/qa/rpc-tests/wallet.sh b/qa/rpc-tests/wallet.sh index 8d5a6cdc78..2940566af9 100755 --- a/qa/rpc-tests/wallet.sh +++ b/qa/rpc-tests/wallet.sh @@ -8,6 +8,8 @@ if [ $# -lt 1 ]; then exit 1 fi +set -f + BITCOIND=${1}/bitcoind CLI=${1}/bitcoin-cli @@ -19,40 +21,40 @@ if [[ ! -d "$DIR" ]]; then DIR="$PWD"; fi D=$(mktemp -d test.XXXXX) D1=${D}/node1 -CreateDataDir $D1 port=11000 rpcport=11001 +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 +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 +CreateDataDir "$D3" port=11020 rpcport=11021 connect=127.0.0.1:11000 B3ARGS="-datadir=$D3" $BITCOIND $BITCOINDARGS $B3ARGS & B3PID=$! -trap "kill -9 $B1PID $B2PID $B3PID; rm -rf $D" EXIT - # Wait until all three nodes are at the same block number function WaitBlocks { while : do sleep 1 - BLOCKS1=$( GetBlocks $B1ARGS ) - BLOCKS2=$( GetBlocks $B2ARGS ) - BLOCKS3=$( GetBlocks $B3ARGS ) - if (( $BLOCKS1 == $BLOCKS2 && $BLOCKS2 == $BLOCKS3 )) + 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 @@ -60,8 +62,8 @@ WaitBlocks $CLI $B2ARGS setgenerate true 101 WaitBlocks -CheckBalance $B1ARGS 50 -CheckBalance $B2ARGS 50 +CheckBalance "$B1ARGS" 50 +CheckBalance "$B2ARGS" 50 # Send 21 XBT from 1 to 3. Second # transaction will be child of first, and @@ -80,25 +82,25 @@ 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" +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) +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" +CheckBalance "$B1ARGS" 0 +CheckBalance "$B3ARGS" 100 +CheckBalance "$B3ARGS" "100-21" "from1" $CLI $B3ARGS stop > /dev/null 2>&1 wait $B3PID @@ -108,6 +110,5 @@ $CLI $B1ARGS stop > /dev/null 2>&1 wait $B1PID echo "Tests successful, cleaning up" -trap "" EXIT rm -rf $D exit 0 -- cgit v1.2.3