2016-03-19 20:58:06 +01:00
#!/usr/bin/env python3
2019-01-25 00:52:29 +01:00
# Copyright (c) 2014-2019 The Bitcoin Core developers
2014-12-13 05:09:33 +01:00
# Distributed under the MIT software license, see the accompanying
2014-11-19 21:55:40 +01:00
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
2017-01-18 00:34:40 +01:00
""" Test the wallet. """
2018-04-24 21:55:53 +02:00
from decimal import Decimal
import time
2015-05-02 12:53:35 +02:00
from test_framework . test_framework import BitcoinTestFramework
2018-04-24 21:55:53 +02:00
from test_framework . util import (
assert_array_result ,
assert_equal ,
assert_fee_amount ,
assert_raises_rpc_error ,
2019-08-27 21:13:56 +02:00
connect_nodes ,
2018-04-24 21:55:53 +02:00
wait_until ,
)
2014-11-19 21:55:40 +01:00
2019-01-25 17:34:39 +01:00
2017-04-26 03:22:28 +02:00
class WalletTest ( BitcoinTestFramework ) :
2017-06-10 00:21:21 +02:00
def set_test_params ( self ) :
2016-05-14 13:01:31 +02:00
self . num_nodes = 4
2019-04-24 23:55:58 +02:00
self . extra_args = [ [
" -acceptnonstdtxn=1 " ,
] ] * self . num_nodes
2016-05-14 13:01:31 +02:00
self . setup_clean_chain = True
2014-11-19 21:55:40 +01:00
2018-09-09 19:32:37 +02:00
def skip_test_if_missing_module ( self ) :
self . skip_if_no_wallet ( )
2017-04-03 15:34:04 +02:00
def setup_network ( self ) :
2018-10-16 17:21:07 +02:00
self . setup_nodes ( )
# Only need nodes 0-2 running at start of test
self . stop_node ( 3 )
2019-08-27 21:13:56 +02:00
connect_nodes ( self . nodes [ 0 ] , 1 )
connect_nodes ( self . nodes [ 1 ] , 2 )
connect_nodes ( self . nodes [ 0 ] , 2 )
2019-04-09 17:46:05 +02:00
self . sync_all ( self . nodes [ 0 : 3 ] )
2014-11-19 21:55:40 +01:00
2017-06-10 00:21:21 +02:00
def check_fee_amount ( self , curr_balance , balance_with_fee , fee_per_byte , tx_size ) :
""" Return curr_balance after asserting the fee was in range """
fee = balance_with_fee - curr_balance
assert_fee_amount ( fee , tx_size , fee_per_byte * 1000 )
return curr_balance
2016-04-19 13:28:37 +02:00
2017-12-01 01:49:11 +01:00
def get_vsize ( self , txn ) :
return self . nodes [ 0 ] . decoderawtransaction ( txn ) [ ' vsize ' ]
2017-06-10 00:21:21 +02:00
def run_test ( self ) :
2016-04-19 13:28:37 +02:00
# Check that there's no UTXO on none of the nodes
assert_equal ( len ( self . nodes [ 0 ] . listunspent ( ) ) , 0 )
assert_equal ( len ( self . nodes [ 1 ] . listunspent ( ) ) , 0 )
assert_equal ( len ( self . nodes [ 2 ] . listunspent ( ) ) , 0 )
2017-03-08 00:46:17 +01:00
self . log . info ( " Mining blocks... " )
2014-11-19 21:55:40 +01:00
2015-04-01 05:28:28 +02:00
self . nodes [ 0 ] . generate ( 1 )
2014-11-19 21:55:40 +01:00
2014-12-25 08:57:16 +01:00
walletinfo = self . nodes [ 0 ] . getwalletinfo ( )
assert_equal ( walletinfo [ ' immature_balance ' ] , 50 )
assert_equal ( walletinfo [ ' balance ' ] , 0 )
2019-04-09 17:46:05 +02:00
self . sync_all ( self . nodes [ 0 : 3 ] )
2015-04-01 05:28:28 +02:00
self . nodes [ 1 ] . generate ( 101 )
2019-04-09 17:46:05 +02:00
self . sync_all ( self . nodes [ 0 : 3 ] )
2014-11-19 21:55:40 +01:00
assert_equal ( self . nodes [ 0 ] . getbalance ( ) , 50 )
assert_equal ( self . nodes [ 1 ] . getbalance ( ) , 50 )
assert_equal ( self . nodes [ 2 ] . getbalance ( ) , 0 )
2016-04-19 13:28:37 +02:00
# Check that only first and second nodes have UTXOs
2017-04-26 03:22:28 +02:00
utxos = self . nodes [ 0 ] . listunspent ( )
assert_equal ( len ( utxos ) , 1 )
2016-04-19 13:28:37 +02:00
assert_equal ( len ( self . nodes [ 1 ] . listunspent ( ) ) , 1 )
assert_equal ( len ( self . nodes [ 2 ] . listunspent ( ) ) , 0 )
2017-07-18 02:19:21 +02:00
self . log . info ( " test gettxout " )
confirmed_txid , confirmed_index = utxos [ 0 ] [ " txid " ] , utxos [ 0 ] [ " vout " ]
# First, outputs that are unspent both in the chain and in the
# mempool should appear with or without include_mempool
txout = self . nodes [ 0 ] . gettxout ( txid = confirmed_txid , n = confirmed_index , include_mempool = False )
assert_equal ( txout [ ' value ' ] , 50 )
txout = self . nodes [ 0 ] . gettxout ( txid = confirmed_txid , n = confirmed_index , include_mempool = True )
assert_equal ( txout [ ' value ' ] , 50 )
2017-06-13 03:53:46 +02:00
2014-11-19 21:55:40 +01:00
# Send 21 BTC from 0 to 2 using sendtoaddress call.
self . nodes [ 0 ] . sendtoaddress ( self . nodes [ 2 ] . getnewaddress ( ) , 11 )
2017-04-26 03:22:28 +02:00
mempool_txid = self . nodes [ 0 ] . sendtoaddress ( self . nodes [ 2 ] . getnewaddress ( ) , 10 )
2017-07-18 02:19:21 +02:00
self . log . info ( " test gettxout (second part) " )
2017-04-26 03:22:28 +02:00
# utxo spent in mempool should be visible if you exclude mempool
# but invisible if you include mempool
txout = self . nodes [ 0 ] . gettxout ( confirmed_txid , confirmed_index , False )
assert_equal ( txout [ ' value ' ] , 50 )
txout = self . nodes [ 0 ] . gettxout ( confirmed_txid , confirmed_index , True )
assert txout is None
# new utxo from mempool should be invisible if you exclude mempool
# but visible if you include mempool
txout = self . nodes [ 0 ] . gettxout ( mempool_txid , 0 , False )
assert txout is None
txout1 = self . nodes [ 0 ] . gettxout ( mempool_txid , 0 , True )
txout2 = self . nodes [ 0 ] . gettxout ( mempool_txid , 1 , True )
# note the mempool tx will have randomly assigned indices
# but 10 will go to node2 and the rest will go to node0
balance = self . nodes [ 0 ] . getbalance ( )
assert_equal ( set ( [ txout1 [ ' value ' ] , txout2 [ ' value ' ] ] ) , set ( [ 10 , balance ] ) )
2014-12-25 08:57:16 +01:00
walletinfo = self . nodes [ 0 ] . getwalletinfo ( )
assert_equal ( walletinfo [ ' immature_balance ' ] , 0 )
2015-04-28 16:48:28 +02:00
# Have node0 mine a block, thus it will collect its own fee.
2015-04-01 05:28:28 +02:00
self . nodes [ 0 ] . generate ( 1 )
2019-04-09 17:46:05 +02:00
self . sync_all ( self . nodes [ 0 : 3 ] )
2014-11-19 21:55:40 +01:00
2016-03-06 18:30:51 +01:00
# Exercise locking of unspent outputs
unspent_0 = self . nodes [ 2 ] . listunspent ( ) [ 0 ]
unspent_0 = { " txid " : unspent_0 [ " txid " ] , " vout " : unspent_0 [ " vout " ] }
2017-08-18 14:21:40 +02:00
assert_raises_rpc_error ( - 8 , " Invalid parameter, expected locked output " , self . nodes [ 2 ] . lockunspent , True , [ unspent_0 ] )
2016-03-06 18:30:51 +01:00
self . nodes [ 2 ] . lockunspent ( False , [ unspent_0 ] )
2017-08-18 14:21:40 +02:00
assert_raises_rpc_error ( - 8 , " Invalid parameter, output already locked " , self . nodes [ 2 ] . lockunspent , False , [ unspent_0 ] )
2017-07-12 16:33:46 +02:00
assert_raises_rpc_error ( - 4 , " Insufficient funds " , self . nodes [ 2 ] . sendtoaddress , self . nodes [ 2 ] . getnewaddress ( ) , 20 )
2016-03-06 18:30:51 +01:00
assert_equal ( [ unspent_0 ] , self . nodes [ 2 ] . listlockunspent ( ) )
self . nodes [ 2 ] . lockunspent ( True , [ unspent_0 ] )
assert_equal ( len ( self . nodes [ 2 ] . listlockunspent ( ) ) , 0 )
2018-06-08 20:16:07 +02:00
assert_raises_rpc_error ( - 8 , " txid must be of length 64 (not 34, for ' 0000000000000000000000000000000000 ' ) " ,
2018-04-24 21:55:53 +02:00
self . nodes [ 2 ] . lockunspent , False ,
[ { " txid " : " 0000000000000000000000000000000000 " , " vout " : 0 } ] )
2018-06-08 20:16:07 +02:00
assert_raises_rpc_error ( - 8 , " txid must be hexadecimal string (not ' ZZZ0000000000000000000000000000000000000000000000000000000000000 ' ) " ,
self . nodes [ 2 ] . lockunspent , False ,
[ { " txid " : " ZZZ0000000000000000000000000000000000000000000000000000000000000 " , " vout " : 0 } ] )
assert_raises_rpc_error ( - 8 , " Invalid parameter, unknown transaction " ,
self . nodes [ 2 ] . lockunspent , False ,
[ { " txid " : " 0000000000000000000000000000000000000000000000000000000000000000 " , " vout " : 0 } ] )
2017-08-18 14:21:40 +02:00
assert_raises_rpc_error ( - 8 , " Invalid parameter, vout index out of bounds " ,
2018-04-24 21:55:53 +02:00
self . nodes [ 2 ] . lockunspent , False ,
[ { " txid " : unspent_0 [ " txid " ] , " vout " : 999 } ] )
2016-03-06 18:30:51 +01:00
2018-05-25 15:28:37 +02:00
# An output should be unlocked when spent
unspent_0 = self . nodes [ 1 ] . listunspent ( ) [ 0 ]
self . nodes [ 1 ] . lockunspent ( False , [ unspent_0 ] )
tx = self . nodes [ 1 ] . createrawtransaction ( [ unspent_0 ] , { self . nodes [ 1 ] . getnewaddress ( ) : 1 } )
tx = self . nodes [ 1 ] . fundrawtransaction ( tx ) [ ' hex ' ]
tx = self . nodes [ 1 ] . signrawtransactionwithwallet ( tx ) [ " hex " ]
self . nodes [ 1 ] . sendrawtransaction ( tx )
assert_equal ( len ( self . nodes [ 1 ] . listlockunspent ( ) ) , 0 )
2014-11-19 21:55:40 +01:00
# Have node1 generate 100 blocks (so node0 can recover the fee)
2015-04-01 05:28:28 +02:00
self . nodes [ 1 ] . generate ( 100 )
2019-04-09 17:46:05 +02:00
self . sync_all ( self . nodes [ 0 : 3 ] )
2014-11-19 21:55:40 +01:00
# node0 should end up with 100 btc in block rewards plus fees, but
# minus the 21 plus fees sent to node2
2018-04-24 21:55:53 +02:00
assert_equal ( self . nodes [ 0 ] . getbalance ( ) , 100 - 21 )
2014-11-19 21:55:40 +01:00
assert_equal ( self . nodes [ 2 ] . getbalance ( ) , 21 )
# Node0 should have two unspent outputs.
2015-07-14 21:13:16 +02:00
# 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:
2014-11-19 21:55:40 +01:00
node0utxos = self . nodes [ 0 ] . listunspent ( 1 )
assert_equal ( len ( node0utxos ) , 2 )
# create both transactions
txns_to_send = [ ]
2015-07-14 21:13:16 +02:00
for utxo in node0utxos :
2014-11-19 21:55:40 +01:00
inputs = [ ]
outputs = { }
2018-04-24 21:55:53 +02:00
inputs . append ( { " txid " : utxo [ " txid " ] , " vout " : utxo [ " vout " ] } )
2018-04-24 21:50:00 +02:00
outputs [ self . nodes [ 2 ] . getnewaddress ( ) ] = utxo [ " amount " ] - 3
2014-11-19 21:55:40 +01:00
raw_tx = self . nodes [ 0 ] . createrawtransaction ( inputs , outputs )
2017-09-06 01:49:18 +02:00
txns_to_send . append ( self . nodes [ 0 ] . signrawtransactionwithwallet ( raw_tx ) )
2014-11-19 21:55:40 +01:00
# Have node 1 (miner) send the transactions
2019-09-21 16:03:28 +02:00
self . nodes [ 1 ] . sendrawtransaction ( hexstring = txns_to_send [ 0 ] [ " hex " ] , maxfeerate = 0 )
self . nodes [ 1 ] . sendrawtransaction ( hexstring = txns_to_send [ 1 ] [ " hex " ] , maxfeerate = 0 )
2014-11-19 21:55:40 +01:00
# Have node1 mine a block to confirm transactions:
2015-04-01 05:28:28 +02:00
self . nodes [ 1 ] . generate ( 1 )
2019-04-09 17:46:05 +02:00
self . sync_all ( self . nodes [ 0 : 3 ] )
2014-11-19 21:55:40 +01:00
assert_equal ( self . nodes [ 0 ] . getbalance ( ) , 0 )
2015-12-06 20:24:02 +01:00
assert_equal ( self . nodes [ 2 ] . getbalance ( ) , 94 )
2014-11-19 21:55:40 +01:00
2017-08-18 14:21:40 +02:00
# Verify that a spent output cannot be locked anymore
spent_0 = { " txid " : node0utxos [ 0 ] [ " txid " ] , " vout " : node0utxos [ 0 ] [ " vout " ] }
assert_raises_rpc_error ( - 8 , " Invalid parameter, expected unspent output " , self . nodes [ 0 ] . lockunspent , False , [ spent_0 ] )
2015-03-05 14:59:19 +01:00
# Send 10 BTC normal
2014-07-23 14:34:36 +02:00
address = self . nodes [ 0 ] . getnewaddress ( " test " )
2015-09-21 12:49:13 +02:00
fee_per_byte = Decimal ( ' 0.001 ' ) / 1000
self . nodes [ 2 ] . settxfee ( fee_per_byte * 1000 )
2014-07-23 14:34:36 +02:00
txid = self . nodes [ 2 ] . sendtoaddress ( address , 10 , " " , " " , False )
2015-04-01 05:28:28 +02:00
self . nodes [ 2 ] . generate ( 1 )
2019-04-09 17:46:05 +02:00
self . sync_all ( self . nodes [ 0 : 3 ] )
2019-01-25 00:52:29 +01:00
node_2_bal = self . check_fee_amount ( self . nodes [ 2 ] . getbalance ( ) , Decimal ( ' 84 ' ) , fee_per_byte , self . get_vsize ( self . nodes [ 2 ] . gettransaction ( txid ) [ ' hex ' ] ) )
2015-09-21 12:49:13 +02:00
assert_equal ( self . nodes [ 0 ] . getbalance ( ) , Decimal ( ' 10 ' ) )
2014-07-23 14:34:36 +02:00
2015-03-05 14:59:19 +01:00
# Send 10 BTC with subtract fee from amount
2014-07-23 14:34:36 +02:00
txid = self . nodes [ 2 ] . sendtoaddress ( address , 10 , " " , " " , True )
2015-04-01 05:28:28 +02:00
self . nodes [ 2 ] . generate ( 1 )
2019-04-09 17:46:05 +02:00
self . sync_all ( self . nodes [ 0 : 3 ] )
2015-09-21 12:49:13 +02:00
node_2_bal - = Decimal ( ' 10 ' )
assert_equal ( self . nodes [ 2 ] . getbalance ( ) , node_2_bal )
2019-01-25 00:52:29 +01:00
node_0_bal = self . check_fee_amount ( self . nodes [ 0 ] . getbalance ( ) , Decimal ( ' 20 ' ) , fee_per_byte , self . get_vsize ( self . nodes [ 2 ] . gettransaction ( txid ) [ ' hex ' ] ) )
2014-11-19 21:55:40 +01:00
2015-03-05 14:59:19 +01:00
# Sendmany 10 BTC
2018-04-24 21:50:00 +02:00
txid = self . nodes [ 2 ] . sendmany ( ' ' , { address : 10 } , 0 , " " , [ ] )
2015-04-01 05:28:28 +02:00
self . nodes [ 2 ] . generate ( 1 )
2019-04-09 17:46:05 +02:00
self . sync_all ( self . nodes [ 0 : 3 ] )
2015-09-21 12:49:13 +02:00
node_0_bal + = Decimal ( ' 10 ' )
2019-01-25 00:52:29 +01:00
node_2_bal = self . check_fee_amount ( self . nodes [ 2 ] . getbalance ( ) , node_2_bal - Decimal ( ' 10 ' ) , fee_per_byte , self . get_vsize ( self . nodes [ 2 ] . gettransaction ( txid ) [ ' hex ' ] ) )
2015-09-21 12:49:13 +02:00
assert_equal ( self . nodes [ 0 ] . getbalance ( ) , node_0_bal )
2015-03-05 14:59:19 +01:00
# Sendmany 10 BTC with subtract fee from amount
2018-04-24 21:50:00 +02:00
txid = self . nodes [ 2 ] . sendmany ( ' ' , { address : 10 } , 0 , " " , [ address ] )
2015-04-01 05:28:28 +02:00
self . nodes [ 2 ] . generate ( 1 )
2019-04-09 17:46:05 +02:00
self . sync_all ( self . nodes [ 0 : 3 ] )
2015-09-21 12:49:13 +02:00
node_2_bal - = Decimal ( ' 10 ' )
assert_equal ( self . nodes [ 2 ] . getbalance ( ) , node_2_bal )
2019-01-25 00:52:29 +01:00
node_0_bal = self . check_fee_amount ( self . nodes [ 0 ] . getbalance ( ) , node_0_bal + Decimal ( ' 10 ' ) , fee_per_byte , self . get_vsize ( self . nodes [ 2 ] . gettransaction ( txid ) [ ' hex ' ] ) )
2015-03-05 14:59:19 +01:00
2017-06-09 22:35:17 +02:00
self . start_node ( 3 )
2019-08-27 21:13:56 +02:00
connect_nodes ( self . nodes [ 0 ] , 3 )
2019-03-22 19:14:32 +01:00
self . sync_all ( )
2015-07-14 21:13:16 +02:00
2018-04-24 21:55:53 +02:00
# check if we can list zero value tx as available coins
# 1. create raw_tx
# 2. hex-changed one output to 0.0
# 3. sign and send
# 4. check if recipient (node0) can list the zero value tx
2018-06-25 15:17:21 +02:00
usp = self . nodes [ 1 ] . listunspent ( query_options = { ' minimumAmount ' : ' 49.998 ' } ) [ 0 ]
inputs = [ { " txid " : usp [ ' txid ' ] , " vout " : usp [ ' vout ' ] } ]
2015-04-21 10:27:35 +02:00
outputs = { self . nodes [ 1 ] . getnewaddress ( ) : 49.998 , self . nodes [ 0 ] . getnewaddress ( ) : 11.11 }
2015-07-14 21:13:16 +02:00
2018-04-24 21:55:53 +02:00
raw_tx = self . nodes [ 1 ] . createrawtransaction ( inputs , outputs ) . replace ( " c0833842 " , " 00000000 " ) # replace 11.11 with 0.0 (int32)
signed_raw_tx = self . nodes [ 1 ] . signrawtransactionwithwallet ( raw_tx )
decoded_raw_tx = self . nodes [ 1 ] . decoderawtransaction ( signed_raw_tx [ ' hex ' ] )
zero_value_txid = decoded_raw_tx [ ' txid ' ]
self . nodes [ 1 ] . sendrawtransaction ( signed_raw_tx [ ' hex ' ] )
2015-07-14 21:13:16 +02:00
2015-04-21 10:27:35 +02:00
self . sync_all ( )
2018-04-24 21:55:53 +02:00
self . nodes [ 1 ] . generate ( 1 ) # mine a block
2015-04-21 10:27:35 +02:00
self . sync_all ( )
2015-07-14 21:13:16 +02:00
2018-04-24 21:55:53 +02:00
unspent_txs = self . nodes [ 0 ] . listunspent ( ) # zero value tx must be in listunspents output
2015-04-21 10:27:35 +02:00
found = False
2018-04-24 21:55:53 +02:00
for uTx in unspent_txs :
if uTx [ ' txid ' ] == zero_value_txid :
2015-04-21 10:27:35 +02:00
found = True
2015-12-15 17:15:13 +01:00
assert_equal ( uTx [ ' amount ' ] , Decimal ( ' 0 ' ) )
2019-01-25 17:34:39 +01:00
assert found
2015-07-14 21:13:16 +02:00
2018-04-24 21:55:53 +02:00
# do some -walletbroadcast tests
2017-03-24 04:56:31 +01:00
self . stop_nodes ( )
2017-06-09 22:35:17 +02:00
self . start_node ( 0 , [ " -walletbroadcast=0 " ] )
self . start_node ( 1 , [ " -walletbroadcast=0 " ] )
self . start_node ( 2 , [ " -walletbroadcast=0 " ] )
2019-08-27 21:13:56 +02:00
connect_nodes ( self . nodes [ 0 ] , 1 )
connect_nodes ( self . nodes [ 1 ] , 2 )
connect_nodes ( self . nodes [ 0 ] , 2 )
2019-04-09 17:46:05 +02:00
self . sync_all ( self . nodes [ 0 : 3 ] )
2015-03-23 18:47:18 +01:00
2018-04-24 21:55:53 +02:00
txid_not_broadcast = self . nodes [ 0 ] . sendtoaddress ( self . nodes [ 2 ] . getnewaddress ( ) , 2 )
tx_obj_not_broadcast = self . nodes [ 0 ] . gettransaction ( txid_not_broadcast )
self . nodes [ 1 ] . generate ( 1 ) # mine a block, tx should not be in there
2019-04-09 17:46:05 +02:00
self . sync_all ( self . nodes [ 0 : 3 ] )
2018-04-24 21:55:53 +02:00
assert_equal ( self . nodes [ 2 ] . getbalance ( ) , node_2_bal ) # should not be changed because tx was not broadcasted
2015-07-14 21:13:16 +02:00
2018-04-24 21:55:53 +02:00
# now broadcast from another node, mine a block, sync, and check the balance
self . nodes [ 1 ] . sendrawtransaction ( tx_obj_not_broadcast [ ' hex ' ] )
2015-04-09 17:36:10 +02:00
self . nodes [ 1 ] . generate ( 1 )
2019-04-09 17:46:05 +02:00
self . sync_all ( self . nodes [ 0 : 3 ] )
2015-12-18 12:35:50 +01:00
node_2_bal + = 2
2018-04-24 21:55:53 +02:00
tx_obj_not_broadcast = self . nodes [ 0 ] . gettransaction ( txid_not_broadcast )
2015-12-18 12:35:50 +01:00
assert_equal ( self . nodes [ 2 ] . getbalance ( ) , node_2_bal )
2015-07-14 21:13:16 +02:00
2018-04-24 21:55:53 +02:00
# create another tx
self . nodes [ 0 ] . sendtoaddress ( self . nodes [ 2 ] . getnewaddress ( ) , 2 )
2015-07-14 21:13:16 +02:00
2018-04-24 21:55:53 +02:00
# restart the nodes with -walletbroadcast=1
2017-03-24 04:56:31 +01:00
self . stop_nodes ( )
2017-06-09 22:35:17 +02:00
self . start_node ( 0 )
self . start_node ( 1 )
self . start_node ( 2 )
2019-08-27 21:13:56 +02:00
connect_nodes ( self . nodes [ 0 ] , 1 )
connect_nodes ( self . nodes [ 1 ] , 2 )
connect_nodes ( self . nodes [ 0 ] , 2 )
2019-04-07 00:19:45 +02:00
self . sync_blocks ( self . nodes [ 0 : 3 ] )
2015-07-14 21:13:16 +02:00
2015-04-09 17:36:10 +02:00
self . nodes [ 0 ] . generate ( 1 )
2019-04-07 00:19:45 +02:00
self . sync_blocks ( self . nodes [ 0 : 3 ] )
2015-12-18 12:35:50 +01:00
node_2_bal + = 2
2015-07-14 21:13:16 +02:00
2018-04-24 21:55:53 +02:00
# tx should be added to balance because after restarting the nodes tx should be broadcast
2015-12-18 12:35:50 +01:00
assert_equal ( self . nodes [ 2 ] . getbalance ( ) , node_2_bal )
2015-07-14 21:13:16 +02:00
2018-04-24 21:55:53 +02:00
# send a tx with value in a string (PR#6380 +)
txid = self . nodes [ 0 ] . sendtoaddress ( self . nodes [ 2 ] . getnewaddress ( ) , " 2 " )
tx_obj = self . nodes [ 0 ] . gettransaction ( txid )
assert_equal ( tx_obj [ ' amount ' ] , Decimal ( ' -2 ' ) )
2015-07-14 21:13:16 +02:00
2018-04-24 21:55:53 +02:00
txid = self . nodes [ 0 ] . sendtoaddress ( self . nodes [ 2 ] . getnewaddress ( ) , " 0.0001 " )
tx_obj = self . nodes [ 0 ] . gettransaction ( txid )
assert_equal ( tx_obj [ ' amount ' ] , Decimal ( ' -0.0001 ' ) )
2015-07-14 21:13:16 +02:00
2018-04-24 21:55:53 +02:00
# check if JSON parser can handle scientific notation in strings
txid = self . nodes [ 0 ] . sendtoaddress ( self . nodes [ 2 ] . getnewaddress ( ) , " 1e-4 " )
tx_obj = self . nodes [ 0 ] . gettransaction ( txid )
assert_equal ( tx_obj [ ' amount ' ] , Decimal ( ' -0.0001 ' ) )
2015-07-14 21:13:16 +02:00
2019-02-12 01:19:22 +01:00
# General checks for errors from incorrect inputs
2017-03-07 20:08:59 +01:00
# This will raise an exception because the amount type is wrong
2017-07-12 16:33:46 +02:00
assert_raises_rpc_error ( - 3 , " Invalid amount " , self . nodes [ 0 ] . sendtoaddress , self . nodes [ 2 ] . getnewaddress ( ) , " 1f-4 " )
2015-07-14 21:13:16 +02:00
2017-03-07 20:08:59 +01:00
# This will raise an exception since generate does not accept a string
2017-07-12 16:33:46 +02:00
assert_raises_rpc_error ( - 1 , " not an integer " , self . nodes [ 0 ] . generate , " 2 " )
2015-07-14 21:13:16 +02:00
2019-02-12 01:19:22 +01:00
# This will raise an exception for the invalid private key format
assert_raises_rpc_error ( - 5 , " Invalid private key encoding " , self . nodes [ 0 ] . importprivkey , " invalid " )
# This will raise an exception for importing an address with the PS2H flag
temp_address = self . nodes [ 1 ] . getnewaddress ( )
assert_raises_rpc_error ( - 5 , " Cannot use the p2sh flag with an address - use a script instead " , self . nodes [ 0 ] . importaddress , temp_address , " label " , False , True )
# This will raise an exception for attempting to dump the private key of an address you do not own
assert_raises_rpc_error ( - 3 , " Address does not refer to a key " , self . nodes [ 0 ] . dumpprivkey , temp_address )
# This will raise an exception for attempting to get the private key of an invalid Bitcoin address
assert_raises_rpc_error ( - 5 , " Invalid Bitcoin address " , self . nodes [ 0 ] . dumpprivkey , " invalid " )
# This will raise an exception for attempting to set a label for an invalid Bitcoin address
assert_raises_rpc_error ( - 5 , " Invalid Bitcoin address " , self . nodes [ 0 ] . setlabel , " invalid address " , " label " )
# This will raise an exception for importing an invalid address
assert_raises_rpc_error ( - 5 , " Invalid Bitcoin address or script " , self . nodes [ 0 ] . importaddress , " invalid " )
# This will raise an exception for attempting to import a pubkey that isn't in hex
assert_raises_rpc_error ( - 5 , " Pubkey must be a hex string " , self . nodes [ 0 ] . importpubkey , " not hex " )
# This will raise an exception for importing an invalid pubkey
assert_raises_rpc_error ( - 5 , " Pubkey is not a valid public key " , self . nodes [ 0 ] . importpubkey , " 5361746f736869204e616b616d6f746f " )
2016-04-19 13:28:37 +02:00
# Import address and private key to check correct behavior of spendable unspents
# 1. Send some coins to generate new UTXO
address_to_import = self . nodes [ 2 ] . getnewaddress ( )
txid = self . nodes [ 0 ] . sendtoaddress ( address_to_import , 1 )
self . nodes [ 0 ] . generate ( 1 )
2019-04-09 17:46:05 +02:00
self . sync_all ( self . nodes [ 0 : 3 ] )
2016-04-19 13:28:37 +02:00
# 2. Import address from node2 to node1
self . nodes [ 1 ] . importaddress ( address_to_import )
# 3. Validate that the imported address is watch-only on node1
2019-01-25 17:34:39 +01:00
assert self . nodes [ 1 ] . getaddressinfo ( address_to_import ) [ " iswatchonly " ]
2016-04-19 13:28:37 +02:00
# 4. Check that the unspents after import are not spendable
assert_array_result ( self . nodes [ 1 ] . listunspent ( ) ,
2018-04-24 21:55:53 +02:00
{ " address " : address_to_import } ,
{ " spendable " : False } )
2016-04-19 13:28:37 +02:00
# 5. Import private key of the previously imported address on node1
priv_key = self . nodes [ 2 ] . dumpprivkey ( address_to_import )
self . nodes [ 1 ] . importprivkey ( priv_key )
# 6. Check that the unspents are now spendable on node1
assert_array_result ( self . nodes [ 1 ] . listunspent ( ) ,
2018-04-24 21:55:53 +02:00
{ " address " : address_to_import } ,
{ " spendable " : True } )
2015-07-14 21:13:16 +02:00
2016-03-14 22:54:34 +01:00
# Mine a block from node0 to an address from node1
2018-04-24 21:55:53 +02:00
coinbase_addr = self . nodes [ 1 ] . getnewaddress ( )
block_hash = self . nodes [ 0 ] . generatetoaddress ( 1 , coinbase_addr ) [ 0 ]
coinbase_txid = self . nodes [ 0 ] . getblock ( block_hash ) [ ' tx ' ] [ 0 ]
2019-04-09 17:46:05 +02:00
self . sync_all ( self . nodes [ 0 : 3 ] )
2016-03-14 22:54:34 +01:00
# Check that the txid and balance is found by node1
2018-04-24 21:55:53 +02:00
self . nodes [ 1 ] . gettransaction ( coinbase_txid )
2016-03-14 22:54:34 +01:00
2016-05-10 17:22:01 +02:00
# check if wallet or blockchain maintenance changes the balance
2019-04-09 17:46:05 +02:00
self . sync_all ( self . nodes [ 0 : 3 ] )
2016-03-06 18:30:51 +01:00
blocks = self . nodes [ 0 ] . generate ( 2 )
2019-04-09 17:46:05 +02:00
self . sync_all ( self . nodes [ 0 : 3 ] )
2015-12-18 12:35:50 +01:00
balance_nodes = [ self . nodes [ i ] . getbalance ( ) for i in range ( 3 ) ]
2016-03-28 21:47:13 +02:00
block_count = self . nodes [ 0 ] . getblockcount ( )
2015-12-18 12:35:50 +01:00
2016-04-28 15:18:01 +02:00
# Check modes:
# - True: unicode escaped as \u....
# - False: unicode directly as UTF-8
for mode in [ True , False ] :
2018-04-24 21:50:00 +02:00
self . nodes [ 0 ] . rpc . ensure_ascii = mode
2016-04-28 15:18:01 +02:00
# unicode check: Basic Multilingual Plane, Supplementary Plane respectively
2018-04-24 21:50:00 +02:00
for label in [ u ' рыба ' , u ' 𝅘𝅥𝅯 ' ] :
addr = self . nodes [ 0 ] . getnewaddress ( )
self . nodes [ 0 ] . setlabel ( addr , label )
assert_equal ( self . nodes [ 0 ] . getaddressinfo ( addr ) [ ' label ' ] , label )
2019-01-25 17:34:39 +01:00
assert label in self . nodes [ 0 ] . listlabels ( )
2018-04-24 21:50:00 +02:00
self . nodes [ 0 ] . rpc . ensure_ascii = True # restore to default
2016-04-28 15:18:01 +02:00
# maintenance tests
2015-12-18 12:35:50 +01:00
maintenance = [
' -rescan ' ,
' -reindex ' ,
' -zapwallettxes=1 ' ,
' -zapwallettxes=2 ' ,
2016-05-10 17:22:01 +02:00
# disabled until issue is fixed: https://github.com/bitcoin/bitcoin/issues/7463
# '-salvagewallet',
2015-12-18 12:35:50 +01:00
]
2016-12-02 18:20:29 +01:00
chainlimit = 6
2015-12-18 12:35:50 +01:00
for m in maintenance :
2017-03-08 00:46:17 +01:00
self . log . info ( " check " + m )
2017-03-24 04:56:31 +01:00
self . stop_nodes ( )
2016-12-02 18:20:29 +01:00
# set lower ancestor limit for later
2018-04-24 21:50:00 +02:00
self . start_node ( 0 , [ m , " -limitancestorcount= " + str ( chainlimit ) ] )
self . start_node ( 1 , [ m , " -limitancestorcount= " + str ( chainlimit ) ] )
self . start_node ( 2 , [ m , " -limitancestorcount= " + str ( chainlimit ) ] )
2018-02-26 23:04:41 +01:00
if m == ' -reindex ' :
2016-03-28 21:47:13 +02:00
# reindex will leave rpc warm up "early"; Wait for it to finish
2018-02-26 23:04:41 +01:00
wait_until ( lambda : [ block_count ] * 3 == [ self . nodes [ i ] . getblockcount ( ) for i in range ( 3 ) ] )
2015-12-18 12:35:50 +01:00
assert_equal ( balance_nodes , [ self . nodes [ i ] . getbalance ( ) for i in range ( 3 ) ] )
2015-07-14 21:13:16 +02:00
2016-03-06 18:30:51 +01:00
# Exercise listsinceblock with the last two blocks
coinbase_tx_1 = self . nodes [ 0 ] . listsinceblock ( blocks [ 0 ] )
assert_equal ( coinbase_tx_1 [ " lastblock " ] , blocks [ 1 ] )
assert_equal ( len ( coinbase_tx_1 [ " transactions " ] ) , 1 )
assert_equal ( coinbase_tx_1 [ " transactions " ] [ 0 ] [ " blockhash " ] , blocks [ 1 ] )
assert_equal ( len ( self . nodes [ 0 ] . listsinceblock ( blocks [ 1 ] ) [ " transactions " ] ) , 0 )
2015-07-14 21:13:16 +02:00
2016-12-02 18:20:29 +01:00
# ==Check that wallet prefers to use coins that don't exceed mempool limits =====
# Get all non-zero utxos together
chain_addrs = [ self . nodes [ 0 ] . getnewaddress ( ) , self . nodes [ 0 ] . getnewaddress ( ) ]
singletxid = self . nodes [ 0 ] . sendtoaddress ( chain_addrs [ 0 ] , self . nodes [ 0 ] . getbalance ( ) , " " , " " , True )
self . nodes [ 0 ] . generate ( 1 )
node0_balance = self . nodes [ 0 ] . getbalance ( )
# Split into two chains
2018-04-24 21:55:53 +02:00
rawtx = self . nodes [ 0 ] . createrawtransaction ( [ { " txid " : singletxid , " vout " : 0 } ] , { chain_addrs [ 0 ] : node0_balance / 2 - Decimal ( ' 0.01 ' ) , chain_addrs [ 1 ] : node0_balance / 2 - Decimal ( ' 0.01 ' ) } )
2017-09-06 01:49:18 +02:00
signedtx = self . nodes [ 0 ] . signrawtransactionwithwallet ( rawtx )
2019-09-21 16:03:28 +02:00
singletxid = self . nodes [ 0 ] . sendrawtransaction ( hexstring = signedtx [ " hex " ] , maxfeerate = 0 )
2016-12-02 18:20:29 +01:00
self . nodes [ 0 ] . generate ( 1 )
# Make a long chain of unconfirmed payments without hitting mempool limit
2016-12-21 03:54:31 +01:00
# Each tx we make leaves only one output of change on a chain 1 longer
# Since the amount to send is always much less than the outputs, we only ever need one output
# So we should be able to generate exactly chainlimit txs for each original output
sending_addr = self . nodes [ 1 ] . getnewaddress ( )
2016-12-02 18:20:29 +01:00
txid_list = [ ]
2018-04-24 21:55:53 +02:00
for i in range ( chainlimit * 2 ) :
2016-12-21 03:54:31 +01:00
txid_list . append ( self . nodes [ 0 ] . sendtoaddress ( sending_addr , Decimal ( ' 0.0001 ' ) ) )
2018-04-24 21:55:53 +02:00
assert_equal ( self . nodes [ 0 ] . getmempoolinfo ( ) [ ' size ' ] , chainlimit * 2 )
assert_equal ( len ( txid_list ) , chainlimit * 2 )
2016-12-02 18:20:29 +01:00
2016-12-21 03:54:31 +01:00
# Without walletrejectlongchains, we will still generate a txid
# The tx will be stored in the wallet but not accepted to the mempool
extra_txid = self . nodes [ 0 ] . sendtoaddress ( sending_addr , Decimal ( ' 0.0001 ' ) )
2019-01-25 17:34:39 +01:00
assert extra_txid not in self . nodes [ 0 ] . getrawmempool ( )
assert extra_txid in [ tx [ " txid " ] for tx in self . nodes [ 0 ] . listtransactions ( ) ]
2016-12-21 03:54:31 +01:00
self . nodes [ 0 ] . abandontransaction ( extra_txid )
2018-04-24 21:55:53 +02:00
total_txs = len ( self . nodes [ 0 ] . listtransactions ( " * " , 99999 ) )
2016-12-21 03:54:31 +01:00
# Try with walletrejectlongchains
# Double chain limit but require combining inputs, so we pass SelectCoinsMinConf
2017-03-24 04:56:31 +01:00
self . stop_node ( 0 )
2018-04-24 21:50:00 +02:00
self . start_node ( 0 , extra_args = [ " -walletrejectlongchains " , " -limitancestorcount= " + str ( 2 * chainlimit ) ] )
2016-12-21 03:54:31 +01:00
# wait for loadmempool
timeout = 10
2018-04-24 21:55:53 +02:00
while ( timeout > 0 and len ( self . nodes [ 0 ] . getrawmempool ( ) ) < chainlimit * 2 ) :
2016-12-21 03:54:31 +01:00
time . sleep ( 0.5 )
timeout - = 0.5
2018-04-24 21:55:53 +02:00
assert_equal ( len ( self . nodes [ 0 ] . getrawmempool ( ) ) , chainlimit * 2 )
2016-12-21 03:54:31 +01:00
node0_balance = self . nodes [ 0 ] . getbalance ( )
# With walletrejectlongchains we will not create the tx and store it in our wallet.
2017-07-12 16:33:46 +02:00
assert_raises_rpc_error ( - 4 , " Transaction has too long of a mempool chain " , self . nodes [ 0 ] . sendtoaddress , sending_addr , node0_balance - Decimal ( ' 0.01 ' ) )
2016-12-21 03:54:31 +01:00
# Verify nothing new in wallet
2018-04-24 21:55:53 +02:00
assert_equal ( total_txs , len ( self . nodes [ 0 ] . listtransactions ( " * " , 99999 ) ) )
2016-12-21 03:54:31 +01:00
2018-10-12 10:57:22 +02:00
# Test getaddressinfo on external address. Note that these addresses are taken from disablewallet.py
2017-06-13 03:53:46 +02:00
assert_raises_rpc_error ( - 5 , " Invalid address " , self . nodes [ 0 ] . getaddressinfo , " 3J98t1WpEZ73CNmQviecrnyiWrnqRhWNLy " )
address_info = self . nodes [ 0 ] . getaddressinfo ( " mneYUmWYsuk7kySiURxCi3AGxrAqZxLgPZ " )
assert_equal ( address_info [ ' address ' ] , " mneYUmWYsuk7kySiURxCi3AGxrAqZxLgPZ " )
assert_equal ( address_info [ " scriptPubKey " ] , " 76a9144e3854046c7bd1594ac904e4793b6a45b36dea0988ac " )
assert not address_info [ " ismine " ]
assert not address_info [ " iswatchonly " ]
assert not address_info [ " isscript " ]
2018-10-12 10:57:22 +02:00
assert not address_info [ " ischange " ]
# Test getaddressinfo 'ischange' field on change address.
self . nodes [ 0 ] . generate ( 1 )
destination = self . nodes [ 1 ] . getnewaddress ( )
txid = self . nodes [ 0 ] . sendtoaddress ( destination , 0.123 )
2019-01-25 00:52:29 +01:00
tx = self . nodes [ 0 ] . decoderawtransaction ( self . nodes [ 0 ] . gettransaction ( txid ) [ ' hex ' ] )
2018-10-12 10:57:22 +02:00
output_addresses = [ vout [ ' scriptPubKey ' ] [ ' addresses ' ] [ 0 ] for vout in tx [ " vout " ] ]
assert len ( output_addresses ) > 1
for address in output_addresses :
ischange = self . nodes [ 0 ] . getaddressinfo ( address ) [ ' ischange ' ]
assert_equal ( ischange , address != destination )
if ischange :
change = address
self . nodes [ 0 ] . setlabel ( change , ' foobar ' )
assert_equal ( self . nodes [ 0 ] . getaddressinfo ( change ) [ ' ischange ' ] , False )
2017-06-13 03:53:46 +02:00
2019-09-15 13:27:15 +02:00
# Test gettransaction response with different arguments.
self . log . info ( " Testing gettransaction response with different arguments... " )
self . nodes [ 0 ] . setlabel ( change , ' baz ' )
baz = self . nodes [ 0 ] . listtransactions ( label = " baz " , count = 1 ) [ 0 ]
expected_receive_vout = { " label " : " baz " ,
" address " : baz [ " address " ] ,
" amount " : baz [ " amount " ] ,
" category " : baz [ " category " ] ,
" vout " : baz [ " vout " ] }
expected_fields = frozenset ( { ' amount ' , ' bip125-replaceable ' , ' confirmations ' , ' details ' , ' fee ' ,
' hex ' , ' time ' , ' timereceived ' , ' trusted ' , ' txid ' , ' walletconflicts ' } )
verbose_field = " decoded "
expected_verbose_fields = expected_fields | { verbose_field }
self . log . debug ( " Testing gettransaction response without verbose " )
tx = self . nodes [ 0 ] . gettransaction ( txid = txid )
assert_equal ( set ( [ * tx ] ) , expected_fields )
assert_array_result ( tx [ " details " ] , { " category " : " receive " } , expected_receive_vout )
self . log . debug ( " Testing gettransaction response with verbose set to False " )
tx = self . nodes [ 0 ] . gettransaction ( txid = txid , verbose = False )
assert_equal ( set ( [ * tx ] ) , expected_fields )
assert_array_result ( tx [ " details " ] , { " category " : " receive " } , expected_receive_vout )
self . log . debug ( " Testing gettransaction response with verbose set to True " )
2019-09-13 21:31:11 +02:00
tx = self . nodes [ 0 ] . gettransaction ( txid = txid , verbose = True )
2019-09-15 13:27:15 +02:00
assert_equal ( set ( [ * tx ] ) , expected_verbose_fields )
assert_array_result ( tx [ " details " ] , { " category " : " receive " } , expected_receive_vout )
assert_equal ( tx [ verbose_field ] , self . nodes [ 0 ] . decoderawtransaction ( tx [ " hex " ] ) )
2019-06-13 00:11:27 +02:00
2019-01-25 17:34:39 +01:00
2014-11-19 21:55:40 +01:00
if __name__ == ' __main__ ' :
2016-05-10 17:22:01 +02:00
WalletTest ( ) . main ( )