wallet_basic.py
1 #!/usr/bin/env python3 2 # Copyright (c) 2014-2022 The Bitcoin Core developers 3 # Distributed under the MIT software license, see the accompanying 4 # file COPYING or http://www.opensource.org/licenses/mit-license.php. 5 """Test the wallet.""" 6 from decimal import Decimal 7 from itertools import product 8 9 from test_framework.blocktools import COINBASE_MATURITY 10 from test_framework.descriptors import descsum_create 11 from test_framework.messages import ( 12 COIN, 13 DEFAULT_ANCESTOR_LIMIT, 14 ) 15 from test_framework.test_framework import BitcoinTestFramework 16 from test_framework.util import ( 17 assert_array_result, 18 assert_equal, 19 assert_fee_amount, 20 assert_raises_rpc_error, 21 ) 22 from test_framework.wallet_util import test_address 23 from test_framework.wallet import MiniWallet 24 25 NOT_A_NUMBER_OR_STRING = "Amount is not a number or string" 26 OUT_OF_RANGE = "Amount out of range" 27 28 29 class WalletTest(BitcoinTestFramework): 30 def set_test_params(self): 31 self.num_nodes = 4 32 # whitelist peers to speed up tx relay / mempool sync 33 self.noban_tx_relay = True 34 self.extra_args = [[ 35 "-dustrelayfee=0", "-walletrejectlongchains=0", "-deprecatedrpc=settxfee" 36 ]] * self.num_nodes 37 self.setup_clean_chain = True 38 self.supports_cli = False 39 40 def skip_test_if_missing_module(self): 41 self.skip_if_no_wallet() 42 43 def setup_network(self): 44 self.setup_nodes() 45 # Only need nodes 0-2 running at start of test 46 self.stop_node(3) 47 self.connect_nodes(0, 1) 48 self.connect_nodes(1, 2) 49 self.connect_nodes(0, 2) 50 self.sync_all(self.nodes[0:3]) 51 52 def check_fee_amount(self, curr_balance, balance_with_fee, fee_per_byte, tx_size): 53 """Return curr_balance after asserting the fee was in range""" 54 fee = balance_with_fee - curr_balance 55 assert_fee_amount(fee, tx_size, fee_per_byte * 1000) 56 return curr_balance 57 58 def get_vsize(self, txn): 59 return self.nodes[0].decoderawtransaction(txn)['vsize'] 60 61 def run_test(self): 62 63 # Check that there's no UTXO on none of the nodes 64 assert_equal(len(self.nodes[0].listunspent()), 0) 65 assert_equal(len(self.nodes[1].listunspent()), 0) 66 assert_equal(len(self.nodes[2].listunspent()), 0) 67 68 self.log.info("Mining blocks...") 69 70 self.generate(self.nodes[0], 1, sync_fun=self.no_op) 71 72 balances = self.nodes[0].getbalances() 73 assert_equal(balances["mine"]["immature"], 50) 74 assert_equal(balances["mine"]["trusted"], 0) 75 76 self.sync_all(self.nodes[0:3]) 77 self.generate(self.nodes[1], COINBASE_MATURITY + 1, sync_fun=lambda: self.sync_all(self.nodes[0:3])) 78 79 assert_equal(self.nodes[0].getbalance(), 50) 80 assert_equal(self.nodes[1].getbalance(), 50) 81 assert_equal(self.nodes[2].getbalance(), 0) 82 83 # Check that only first and second nodes have UTXOs 84 utxos = self.nodes[0].listunspent() 85 assert_equal(len(utxos), 1) 86 assert_equal(len(self.nodes[1].listunspent()), 1) 87 assert_equal(len(self.nodes[2].listunspent()), 0) 88 89 self.log.info("Test gettxout") 90 confirmed_txid, confirmed_index = utxos[0]["txid"], utxos[0]["vout"] 91 # First, outputs that are unspent both in the chain and in the 92 # mempool should appear with or without include_mempool 93 txout = self.nodes[0].gettxout(txid=confirmed_txid, n=confirmed_index, include_mempool=False) 94 assert_equal(txout['value'], 50) 95 txout = self.nodes[0].gettxout(txid=confirmed_txid, n=confirmed_index, include_mempool=True) 96 assert_equal(txout['value'], 50) 97 98 # Send 21 BTC from 0 to 2 using sendtoaddress call. 99 self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 11) 100 mempool_txid = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 10) 101 102 self.log.info("Test gettxout (second part)") 103 # utxo spent in mempool should be visible if you exclude mempool 104 # but invisible if you include mempool 105 txout = self.nodes[0].gettxout(confirmed_txid, confirmed_index, False) 106 assert_equal(txout['value'], 50) 107 txout = self.nodes[0].gettxout(confirmed_txid, confirmed_index) # by default include_mempool=True 108 assert txout is None 109 txout = self.nodes[0].gettxout(confirmed_txid, confirmed_index, True) 110 assert txout is None 111 # new utxo from mempool should be invisible if you exclude mempool 112 # but visible if you include mempool 113 txout = self.nodes[0].gettxout(mempool_txid, 0, False) 114 assert txout is None 115 txout1 = self.nodes[0].gettxout(mempool_txid, 0, True) 116 txout2 = self.nodes[0].gettxout(mempool_txid, 1, True) 117 # note the mempool tx will have randomly assigned indices 118 # but 10 will go to node2 and the rest will go to node0 119 balance = self.nodes[0].getbalance() 120 assert_equal(set([txout1['value'], txout2['value']]), set([10, balance])) 121 assert_equal(self.nodes[0].getbalances()["mine"]["immature"], 0) 122 123 # Have node0 mine a block, thus it will collect its own fee. 124 self.generate(self.nodes[0], 1, sync_fun=lambda: self.sync_all(self.nodes[0:3])) 125 126 # Exercise locking of unspent outputs 127 unspent_0 = self.nodes[2].listunspent()[0] 128 unspent_0 = {"txid": unspent_0["txid"], "vout": unspent_0["vout"]} 129 # Trying to unlock an output which isn't locked should error 130 assert_raises_rpc_error(-8, "Invalid parameter, expected locked output", self.nodes[2].lockunspent, True, [unspent_0]) 131 132 # Locking an already-locked output should error 133 self.nodes[2].lockunspent(False, [unspent_0]) 134 assert_raises_rpc_error(-8, "Invalid parameter, output already locked", self.nodes[2].lockunspent, False, [unspent_0]) 135 136 # Restarting the node should clear the lock 137 self.restart_node(2) 138 self.nodes[2].lockunspent(False, [unspent_0]) 139 140 # Unloading and reloating the wallet should clear the lock 141 assert_equal(self.nodes[0].listwallets(), [self.default_wallet_name]) 142 self.nodes[2].unloadwallet(self.default_wallet_name) 143 self.nodes[2].loadwallet(self.default_wallet_name) 144 assert_equal(len(self.nodes[2].listlockunspent()), 0) 145 146 # Locking non-persistently, then re-locking persistently, is allowed 147 self.nodes[2].lockunspent(False, [unspent_0]) 148 self.nodes[2].lockunspent(False, [unspent_0], True) 149 150 # Restarting the node with the lock written to the wallet should keep the lock 151 self.restart_node(2, ["-walletrejectlongchains=0"]) 152 assert_raises_rpc_error(-8, "Invalid parameter, output already locked", self.nodes[2].lockunspent, False, [unspent_0]) 153 154 # Unloading and reloading the wallet with a persistent lock should keep the lock 155 self.nodes[2].unloadwallet(self.default_wallet_name) 156 self.nodes[2].loadwallet(self.default_wallet_name) 157 assert_raises_rpc_error(-8, "Invalid parameter, output already locked", self.nodes[2].lockunspent, False, [unspent_0]) 158 159 # Locked outputs should not be used, even if they are the only available funds 160 assert_raises_rpc_error(-6, "Insufficient funds", self.nodes[2].sendtoaddress, self.nodes[2].getnewaddress(), 20) 161 assert_equal([unspent_0], self.nodes[2].listlockunspent()) 162 163 # Unlocking should remove the persistent lock 164 self.nodes[2].lockunspent(True, [unspent_0]) 165 self.restart_node(2) 166 assert_equal(len(self.nodes[2].listlockunspent()), 0) 167 168 # Reconnect node 2 after restarts 169 self.connect_nodes(1, 2) 170 self.connect_nodes(0, 2) 171 172 assert_raises_rpc_error(-8, "txid must be of length 64 (not 34, for '0000000000000000000000000000000000')", 173 self.nodes[2].lockunspent, False, 174 [{"txid": "0000000000000000000000000000000000", "vout": 0}]) 175 assert_raises_rpc_error(-8, "txid must be hexadecimal string (not 'ZZZ0000000000000000000000000000000000000000000000000000000000000')", 176 self.nodes[2].lockunspent, False, 177 [{"txid": "ZZZ0000000000000000000000000000000000000000000000000000000000000", "vout": 0}]) 178 assert_raises_rpc_error(-8, "Invalid parameter, unknown transaction", 179 self.nodes[2].lockunspent, False, 180 [{"txid": "0000000000000000000000000000000000000000000000000000000000000000", "vout": 0}]) 181 assert_raises_rpc_error(-8, "Invalid parameter, vout index out of bounds", 182 self.nodes[2].lockunspent, False, 183 [{"txid": unspent_0["txid"], "vout": 999}]) 184 185 # The lock on a manually selected output is ignored 186 unspent_0 = self.nodes[1].listunspent()[0] 187 self.nodes[1].lockunspent(False, [unspent_0]) 188 tx = self.nodes[1].createrawtransaction([unspent_0], { self.nodes[1].getnewaddress() : 1 }) 189 self.nodes[1].fundrawtransaction(tx,{"lockUnspents": True}) 190 191 # fundrawtransaction can lock an input 192 self.nodes[1].lockunspent(True, [unspent_0]) 193 assert_equal(len(self.nodes[1].listlockunspent()), 0) 194 tx = self.nodes[1].fundrawtransaction(tx,{"lockUnspents": True})['hex'] 195 assert_equal(len(self.nodes[1].listlockunspent()), 1) 196 197 # Send transaction 198 tx = self.nodes[1].signrawtransactionwithwallet(tx)["hex"] 199 self.nodes[1].sendrawtransaction(tx) 200 assert_equal(len(self.nodes[1].listlockunspent()), 0) 201 202 # Have node1 generate 100 blocks (so node0 can recover the fee) 203 self.generate(self.nodes[1], COINBASE_MATURITY, sync_fun=lambda: self.sync_all(self.nodes[0:3])) 204 205 # node0 should end up with 100 btc in block rewards plus fees, but 206 # minus the 21 plus fees sent to node2 207 assert_equal(self.nodes[0].getbalance(), 100 - 21) 208 assert_equal(self.nodes[2].getbalance(), 21) 209 210 # Node0 should have two unspent outputs. 211 # Create a couple of transactions to send them to node2, submit them through 212 # node1, and make sure both node0 and node2 pick them up properly: 213 node0utxos = self.nodes[0].listunspent(1) 214 assert_equal(len(node0utxos), 2) 215 216 # create both transactions 217 txns_to_send = [] 218 for utxo in node0utxos: 219 inputs = [] 220 outputs = {} 221 inputs.append({"txid": utxo["txid"], "vout": utxo["vout"]}) 222 outputs[self.nodes[2].getnewaddress()] = utxo["amount"] - 3 223 raw_tx = self.nodes[0].createrawtransaction(inputs, outputs) 224 txns_to_send.append(self.nodes[0].signrawtransactionwithwallet(raw_tx)) 225 226 # Have node 1 (miner) send the transactions 227 self.nodes[1].sendrawtransaction(hexstring=txns_to_send[0]["hex"], maxfeerate=0) 228 self.nodes[1].sendrawtransaction(hexstring=txns_to_send[1]["hex"], maxfeerate=0) 229 230 # Have node1 mine a block to confirm transactions: 231 self.generate(self.nodes[1], 1, sync_fun=lambda: self.sync_all(self.nodes[0:3])) 232 233 assert_equal(self.nodes[0].getbalance(), 0) 234 assert_equal(self.nodes[2].getbalance(), 94) 235 236 # Verify that a spent output cannot be locked anymore 237 spent_0 = {"txid": node0utxos[0]["txid"], "vout": node0utxos[0]["vout"]} 238 assert_raises_rpc_error(-8, "Invalid parameter, expected unspent output", self.nodes[0].lockunspent, False, [spent_0]) 239 240 # Send 10 BTC normal 241 address = self.nodes[0].getnewaddress("test") 242 fee_per_byte = Decimal('0.001') / 1000 243 self.nodes[2].settxfee(fee_per_byte * 1000) 244 txid = self.nodes[2].sendtoaddress(address, 10, "", "", False) 245 self.generate(self.nodes[2], 1, sync_fun=lambda: self.sync_all(self.nodes[0:3])) 246 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'])) 247 assert_equal(self.nodes[0].getbalance(), Decimal('10')) 248 249 # Send 10 BTC with subtract fee from amount 250 txid = self.nodes[2].sendtoaddress(address, 10, "", "", True) 251 self.generate(self.nodes[2], 1, sync_fun=lambda: self.sync_all(self.nodes[0:3])) 252 node_2_bal -= Decimal('10') 253 assert_equal(self.nodes[2].getbalance(), node_2_bal) 254 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'])) 255 256 self.log.info("Test sendmany") 257 258 # Sendmany 10 BTC 259 txid = self.nodes[2].sendmany('', {address: 10}, 0, "", []) 260 self.generate(self.nodes[2], 1, sync_fun=lambda: self.sync_all(self.nodes[0:3])) 261 node_0_bal += Decimal('10') 262 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'])) 263 assert_equal(self.nodes[0].getbalance(), node_0_bal) 264 265 # Sendmany 10 BTC with subtract fee from amount 266 txid = self.nodes[2].sendmany('', {address: 10}, 0, "", [address]) 267 self.generate(self.nodes[2], 1, sync_fun=lambda: self.sync_all(self.nodes[0:3])) 268 node_2_bal -= Decimal('10') 269 assert_equal(self.nodes[2].getbalance(), node_2_bal) 270 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'])) 271 272 # Sendmany 5 BTC to two addresses with subtracting fee from both addresses 273 a0 = self.nodes[0].getnewaddress() 274 a1 = self.nodes[0].getnewaddress() 275 txid = self.nodes[2].sendmany(dummy='', amounts={a0: 5, a1: 5}, subtractfeefrom=[a0, a1]) 276 self.generate(self.nodes[2], 1, sync_fun=lambda: self.sync_all(self.nodes[0:3])) 277 node_2_bal -= Decimal('10') 278 assert_equal(self.nodes[2].getbalance(), node_2_bal) 279 tx = self.nodes[2].gettransaction(txid) 280 node_0_bal = self.check_fee_amount(self.nodes[0].getbalance(), node_0_bal + Decimal('10'), fee_per_byte, self.get_vsize(tx['hex'])) 281 assert_equal(self.nodes[0].getbalance(), node_0_bal) 282 expected_bal = Decimal('5') + (tx['fee'] / 2) 283 assert_equal(self.nodes[0].getreceivedbyaddress(a0), expected_bal) 284 assert_equal(self.nodes[0].getreceivedbyaddress(a1), expected_bal) 285 286 self.log.info("Test sendmany with fee_rate param (explicit fee rate in sat/vB)") 287 fee_rate_sat_vb = 2 288 fee_rate_btc_kvb = fee_rate_sat_vb * 1e3 / 1e8 289 explicit_fee_rate_btc_kvb = Decimal(fee_rate_btc_kvb) / 1000 290 291 # Test passing fee_rate as a string 292 txid = self.nodes[2].sendmany(amounts={address: 10}, fee_rate=str(fee_rate_sat_vb)) 293 self.generate(self.nodes[2], 1, sync_fun=lambda: self.sync_all(self.nodes[0:3])) 294 balance = self.nodes[2].getbalance() 295 node_2_bal = self.check_fee_amount(balance, node_2_bal - Decimal('10'), explicit_fee_rate_btc_kvb, self.get_vsize(self.nodes[2].gettransaction(txid)['hex'])) 296 assert_equal(balance, node_2_bal) 297 node_0_bal += Decimal('10') 298 assert_equal(self.nodes[0].getbalance(), node_0_bal) 299 300 # Test passing fee_rate as an integer 301 amount = Decimal("0.0001") 302 txid = self.nodes[2].sendmany(amounts={address: amount}, fee_rate=fee_rate_sat_vb) 303 self.generate(self.nodes[2], 1, sync_fun=lambda: self.sync_all(self.nodes[0:3])) 304 balance = self.nodes[2].getbalance() 305 node_2_bal = self.check_fee_amount(balance, node_2_bal - amount, explicit_fee_rate_btc_kvb, self.get_vsize(self.nodes[2].gettransaction(txid)['hex'])) 306 assert_equal(balance, node_2_bal) 307 node_0_bal += amount 308 assert_equal(self.nodes[0].getbalance(), node_0_bal) 309 310 assert_raises_rpc_error(-8, "Unknown named parameter feeRate", self.nodes[2].sendtoaddress, address=address, amount=1, fee_rate=1, feeRate=1) 311 312 # Test setting explicit fee rate just below the minimum. 313 self.log.info("Test sendmany raises 'fee rate too low' if fee_rate of 0.99999999 is passed") 314 assert_raises_rpc_error(-6, "Fee rate (0.999 sat/vB) is lower than the minimum fee rate setting (1.000 sat/vB)", 315 self.nodes[2].sendmany, amounts={address: 10}, fee_rate=0.999) 316 317 self.log.info("Test sendmany raises if an invalid fee_rate is passed") 318 # Test fee_rate with zero values. 319 msg = "Fee rate (0.000 sat/vB) is lower than the minimum fee rate setting (1.000 sat/vB)" 320 for zero_value in [0, 0.000, 0.00000000, "0", "0.000", "0.00000000"]: 321 assert_raises_rpc_error(-6, msg, self.nodes[2].sendmany, amounts={address: 1}, fee_rate=zero_value) 322 msg = "Invalid amount" 323 # Test fee_rate values that don't pass fixed-point parsing checks. 324 for invalid_value in ["", 0.000000001, 1e-09, 1.111111111, 1111111111111111, "31.999999999999999999999"]: 325 assert_raises_rpc_error(-3, msg, self.nodes[2].sendmany, amounts={address: 1.0}, fee_rate=invalid_value) 326 # Test fee_rate values that cannot be represented in sat/vB. 327 for invalid_value in [0.0001, 0.00000001, 0.00099999, 31.99999999]: 328 assert_raises_rpc_error(-3, msg, self.nodes[2].sendmany, amounts={address: 10}, fee_rate=invalid_value) 329 # Test fee_rate out of range (negative number). 330 assert_raises_rpc_error(-3, OUT_OF_RANGE, self.nodes[2].sendmany, amounts={address: 10}, fee_rate=-1) 331 # Test type error. 332 for invalid_value in [True, {"foo": "bar"}]: 333 assert_raises_rpc_error(-3, NOT_A_NUMBER_OR_STRING, self.nodes[2].sendmany, amounts={address: 10}, fee_rate=invalid_value) 334 335 self.log.info("Test sendmany raises if an invalid conf_target or estimate_mode is passed") 336 for target, mode in product([-1, 0, 1009], ["economical", "conservative"]): 337 assert_raises_rpc_error(-8, "Invalid conf_target, must be between 1 and 1008", # max value of 1008 per src/policy/fees/block_policy_estimator.h 338 self.nodes[2].sendmany, amounts={address: 1}, conf_target=target, estimate_mode=mode) 339 for target, mode in product([-1, 0], ["btc/kb", "sat/b"]): 340 assert_raises_rpc_error(-8, 'Invalid estimate_mode parameter, must be one of: "unset", "economical", "conservative"', 341 self.nodes[2].sendmany, amounts={address: 1}, conf_target=target, estimate_mode=mode) 342 343 self.start_node(3, self.nodes[3].extra_args) 344 self.connect_nodes(0, 3) 345 self.sync_all() 346 347 # check if we can list zero value tx as available coins 348 # 1. create raw_tx 349 # 2. hex-changed one output to 0.0 350 # 3. sign and send 351 # 4. check if recipient (node0) can list the zero value tx 352 usp = self.nodes[1].listunspent(query_options={'minimumAmount': '49.998'})[0] 353 inputs = [{"txid": usp['txid'], "vout": usp['vout']}] 354 outputs = {self.nodes[1].getnewaddress(): 49.998, self.nodes[0].getnewaddress(): 11.11} 355 356 raw_tx = self.nodes[1].createrawtransaction(inputs, outputs).replace("c0833842", "00000000") # replace 11.11 with 0.0 (int32) 357 signed_raw_tx = self.nodes[1].signrawtransactionwithwallet(raw_tx) 358 decoded_raw_tx = self.nodes[1].decoderawtransaction(signed_raw_tx['hex']) 359 zero_value_txid = decoded_raw_tx['txid'] 360 self.nodes[1].sendrawtransaction(signed_raw_tx['hex']) 361 362 self.sync_all() 363 self.generate(self.nodes[1], 1) # mine a block 364 365 unspent_txs = self.nodes[0].listunspent() # zero value tx must be in listunspents output 366 found = False 367 for uTx in unspent_txs: 368 if uTx['txid'] == zero_value_txid: 369 found = True 370 assert_equal(uTx['amount'], Decimal('0')) 371 assert found 372 373 self.log.info("Test -walletbroadcast") 374 self.stop_nodes() 375 self.start_node(0, ["-walletbroadcast=0"]) 376 self.start_node(1, ["-walletbroadcast=0"]) 377 self.start_node(2, ["-walletbroadcast=0"]) 378 self.connect_nodes(0, 1) 379 self.connect_nodes(1, 2) 380 self.connect_nodes(0, 2) 381 self.sync_all(self.nodes[0:3]) 382 383 txid_not_broadcast = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 2) 384 tx_obj_not_broadcast = self.nodes[0].gettransaction(txid_not_broadcast) 385 self.generate(self.nodes[1], 1, sync_fun=lambda: self.sync_all(self.nodes[0:3])) # mine a block, tx should not be in there 386 assert_equal(self.nodes[2].getbalance(), node_2_bal) # should not be changed because tx was not broadcasted 387 388 # now broadcast from another node, mine a block, sync, and check the balance 389 self.nodes[1].sendrawtransaction(tx_obj_not_broadcast['hex']) 390 self.generate(self.nodes[1], 1, sync_fun=lambda: self.sync_all(self.nodes[0:3])) 391 node_2_bal += 2 392 tx_obj_not_broadcast = self.nodes[0].gettransaction(txid_not_broadcast) 393 assert_equal(self.nodes[2].getbalance(), node_2_bal) 394 395 # create another tx 396 self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 2) 397 398 # restart the nodes with -walletbroadcast=1 399 self.stop_nodes() 400 self.start_node(0) 401 self.start_node(1) 402 self.start_node(2) 403 self.connect_nodes(0, 1) 404 self.connect_nodes(1, 2) 405 self.connect_nodes(0, 2) 406 self.sync_blocks(self.nodes[0:3]) 407 408 self.generate(self.nodes[0], 1, sync_fun=lambda: self.sync_blocks(self.nodes[0:3])) 409 node_2_bal += 2 410 411 # tx should be added to balance because after restarting the nodes tx should be broadcast 412 assert_equal(self.nodes[2].getbalance(), node_2_bal) 413 414 # send a tx with value in a string (PR#6380 +) 415 txid = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), "2") 416 tx_obj = self.nodes[0].gettransaction(txid) 417 assert_equal(tx_obj['amount'], Decimal('-2')) 418 419 txid = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), "0.0001") 420 tx_obj = self.nodes[0].gettransaction(txid) 421 assert_equal(tx_obj['amount'], Decimal('-0.0001')) 422 423 # check if JSON parser can handle scientific notation in strings 424 txid = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), "1e-4") 425 tx_obj = self.nodes[0].gettransaction(txid) 426 assert_equal(tx_obj['amount'], Decimal('-0.0001')) 427 428 # General checks for errors from incorrect inputs 429 # This will raise an exception because the amount is negative 430 assert_raises_rpc_error(-3, OUT_OF_RANGE, self.nodes[0].sendtoaddress, self.nodes[2].getnewaddress(), "-1") 431 432 # This will raise an exception because the amount type is wrong 433 assert_raises_rpc_error(-3, "Invalid amount", self.nodes[0].sendtoaddress, self.nodes[2].getnewaddress(), "1f-4") 434 435 # This will raise an exception since generate does not accept a string 436 assert_raises_rpc_error(-3, "not of expected type number", self.generate, self.nodes[0], "2") 437 438 # Mine a block from node0 to an address from node1 439 coinbase_addr = self.nodes[1].getnewaddress() 440 block_hash = self.generatetoaddress(self.nodes[0], 1, coinbase_addr, sync_fun=lambda: self.sync_all(self.nodes[0:3]))[0] 441 coinbase_txid = self.nodes[0].getblock(block_hash)['tx'][0] 442 443 # Check that the txid and balance is found by node1 444 self.nodes[1].gettransaction(coinbase_txid) 445 446 # check if wallet or blockchain maintenance changes the balance 447 self.sync_all(self.nodes[0:3]) 448 blocks = self.generate(self.nodes[0], 2, sync_fun=lambda: self.sync_all(self.nodes[0:3])) 449 balance_nodes = [self.nodes[i].getbalance() for i in range(3)] 450 block_count = self.nodes[0].getblockcount() 451 452 # Check modes: 453 # - True: unicode escaped as \u.... 454 # - False: unicode directly as UTF-8 455 for mode in [True, False]: 456 self.nodes[0]._rpc.ensure_ascii = mode 457 # unicode check: Basic Multilingual Plane, Supplementary Plane respectively 458 for label in [u'рыба', u'𝅘𝅥𝅯']: 459 addr = self.nodes[0].getnewaddress() 460 self.nodes[0].setlabel(addr, label) 461 test_address(self.nodes[0], addr, labels=[label]) 462 assert label in self.nodes[0].listlabels() 463 self.nodes[0]._rpc.ensure_ascii = True # restore to default 464 465 # -reindex tests 466 chainlimit = 6 467 self.log.info("Test -reindex") 468 self.stop_nodes() 469 # set lower ancestor limit for later 470 self.start_node(0, ['-reindex', "-walletrejectlongchains=0", "-limitancestorcount=" + str(chainlimit), "-limitclustercount=" + str(chainlimit)]) 471 self.start_node(1, ['-reindex', "-limitclustercount=" + str(chainlimit)]) 472 self.start_node(2, ['-reindex', "-limitclustercount=" + str(chainlimit)]) 473 # reindex will leave rpc warm up "early"; Wait for it to finish 474 self.wait_until(lambda: [block_count] * 3 == [self.nodes[i].getblockcount() for i in range(3)]) 475 assert_equal(balance_nodes, [self.nodes[i].getbalance() for i in range(3)]) 476 477 # Exercise listsinceblock with the last two blocks 478 coinbase_tx_1 = self.nodes[0].listsinceblock(blocks[0]) 479 assert_equal(coinbase_tx_1["lastblock"], blocks[1]) 480 assert_equal(len(coinbase_tx_1["transactions"]), 1) 481 assert_equal(coinbase_tx_1["transactions"][0]["blockhash"], blocks[1]) 482 assert_equal(len(self.nodes[0].listsinceblock(blocks[1])["transactions"]), 0) 483 484 # ==Check that wallet prefers to use coins that don't exceed mempool limits ===== 485 486 # Get all non-zero utxos together and split into two chains 487 chain_addrs = [self.nodes[0].getnewaddress(), self.nodes[0].getnewaddress()] 488 self.nodes[0].sendall(recipients=chain_addrs) 489 self.generate(self.nodes[0], 1, sync_fun=self.no_op) 490 491 # Make a long chain of unconfirmed payments without hitting mempool limit 492 # Each tx we make leaves only one output of change on a chain 1 longer 493 # Since the amount to send is always much less than the outputs, we only ever need one output 494 # So we should be able to generate exactly chainlimit txs for each original output 495 sending_addr = self.nodes[1].getnewaddress() 496 txid_list = [] 497 for _ in range(chainlimit * 2): 498 txid_list.append(self.nodes[0].sendtoaddress(sending_addr, Decimal('0.0001'))) 499 assert_equal(self.nodes[0].getmempoolinfo()['size'], chainlimit * 2) 500 assert_equal(len(txid_list), chainlimit * 2) 501 502 # Without walletrejectlongchains, we will still generate a txid 503 # The tx will be stored in the wallet but not accepted to the mempool 504 extra_txid = self.nodes[0].sendtoaddress(sending_addr, Decimal('0.0001')) 505 assert extra_txid not in self.nodes[0].getrawmempool() 506 assert extra_txid in [tx["txid"] for tx in self.nodes[0].listtransactions()] 507 self.nodes[0].abandontransaction(extra_txid) 508 total_txs = len(self.nodes[0].listtransactions("*", 99999)) 509 510 # Try with walletrejectlongchains 511 # Double chain limit but require combining inputs, so we pass AttemptSelection 512 self.stop_node(0) 513 extra_args = ["-walletrejectlongchains", "-limitclustercount=" + str(2 * chainlimit), "-limitancestorcount=" + str(2*chainlimit)] 514 self.start_node(0, extra_args=extra_args) 515 516 # wait until the wallet has submitted all transactions to the mempool 517 self.wait_until(lambda: len(self.nodes[0].getrawmempool()) == chainlimit * 2) 518 519 # Prevent potential race condition when calling wallet RPCs right after restart 520 self.nodes[0].syncwithvalidationinterfacequeue() 521 522 node0_balance = self.nodes[0].getbalance() 523 # With walletrejectlongchains we will not create the tx and store it in our wallet. 524 assert_raises_rpc_error(-6, "too many unconfirmed transactions in cluster", self.nodes[0].sendtoaddress, sending_addr, node0_balance - Decimal('0.01')) 525 526 # Verify nothing new in wallet 527 assert_equal(total_txs, len(self.nodes[0].listtransactions("*", 99999))) 528 529 # Test getaddressinfo on external address. Note that these addresses are taken from disablewallet.py 530 assert_raises_rpc_error(-5, "Invalid or unsupported Base58-encoded address.", self.nodes[0].getaddressinfo, "3J98t1WpEZ73CNmQviecrnyiWrnqRhWNLy") 531 address_info = self.nodes[0].getaddressinfo("mneYUmWYsuk7kySiURxCi3AGxrAqZxLgPZ") 532 assert_equal(address_info['address'], "mneYUmWYsuk7kySiURxCi3AGxrAqZxLgPZ") 533 assert_equal(address_info["scriptPubKey"], "76a9144e3854046c7bd1594ac904e4793b6a45b36dea0988ac") 534 assert not address_info["ismine"] 535 assert not address_info["isscript"] 536 assert not address_info["ischange"] 537 538 # Test getaddressinfo 'ischange' field on change address. 539 self.generate(self.nodes[0], 1, sync_fun=self.no_op) 540 destination = self.nodes[1].getnewaddress() 541 txid = self.nodes[0].sendtoaddress(destination, 0.123) 542 tx = self.nodes[0].gettransaction(txid=txid, verbose=True)['decoded'] 543 assert len(tx["vout"]) > 1 544 for vout in tx["vout"]: 545 address = vout['scriptPubKey']['address'] 546 ischange = self.nodes[0].getaddressinfo(address)['ischange'] 547 assert_equal(ischange, address != destination) 548 if ischange: 549 change = address 550 assert vout["ischange"] 551 else: 552 assert "ischange" not in vout 553 self.nodes[0].setlabel(change, 'foobar') 554 assert_equal(self.nodes[0].getaddressinfo(change)['ischange'], False) 555 556 # Test gettransaction response with different arguments. 557 self.log.info("Testing gettransaction response with different arguments...") 558 self.nodes[0].setlabel(change, 'baz') 559 baz = self.nodes[0].listtransactions(label="baz", count=1)[0] 560 expected_receive_vout = {"label": "baz", 561 "address": baz["address"], 562 "amount": baz["amount"], 563 "category": baz["category"], 564 "vout": baz["vout"]} 565 expected_fields = frozenset({'amount', 'bip125-replaceable', 'confirmations', 'details', 'fee', 566 'hex', 'lastprocessedblock', 'time', 'timereceived', 'trusted', 'txid', 'wtxid', 'walletconflicts', 'mempoolconflicts'}) 567 verbose_field = "decoded" 568 expected_verbose_fields = expected_fields | {verbose_field} 569 570 self.log.debug("Testing gettransaction response without verbose") 571 tx = self.nodes[0].gettransaction(txid=txid) 572 assert_equal(set([*tx]), expected_fields) 573 assert_array_result(tx["details"], {"category": "receive"}, expected_receive_vout) 574 575 self.log.debug("Testing gettransaction response with verbose set to False") 576 tx = self.nodes[0].gettransaction(txid=txid, verbose=False) 577 assert_equal(set([*tx]), expected_fields) 578 assert_array_result(tx["details"], {"category": "receive"}, expected_receive_vout) 579 580 self.log.debug("Testing gettransaction response with verbose set to True") 581 tx = self.nodes[0].gettransaction(txid=txid, verbose=True) 582 assert_equal(set([*tx]), expected_verbose_fields) 583 assert_array_result(tx["details"], {"category": "receive"}, expected_receive_vout) 584 assert_equal(tx[verbose_field], self.nodes[0].decoderawtransaction(tx["hex"])) 585 586 self.log.info("Test send* RPCs with verbose=True") 587 address = self.nodes[0].getnewaddress("test") 588 txid_feeReason_one = self.nodes[2].sendtoaddress(address=address, amount=5, verbose=True) 589 assert_equal(txid_feeReason_one["fee_reason"], "Fallback fee") 590 txid_feeReason_two = self.nodes[2].sendmany(dummy='', amounts={address: 5}, verbose=True) 591 assert_equal(txid_feeReason_two["fee_reason"], "Fallback fee") 592 self.log.info("Test send* RPCs with verbose=False") 593 txid_feeReason_three = self.nodes[2].sendtoaddress(address=address, amount=5, verbose=False) 594 assert_equal(self.nodes[2].gettransaction(txid_feeReason_three)['txid'], txid_feeReason_three) 595 txid_feeReason_four = self.nodes[2].sendmany(dummy='', amounts={address: 5}, verbose=False) 596 assert_equal(self.nodes[2].gettransaction(txid_feeReason_four)['txid'], txid_feeReason_four) 597 598 self.log.info("Testing 'listunspent' outputs the parent descriptor(s) of coins") 599 # Create two multisig descriptors, and send a UTxO each. 600 multi_a = descsum_create("wsh(multi(1,tpubD6NzVbkrYhZ4YBNjUo96Jxd1u4XKWgnoc7LsA1jz3Yc2NiDbhtfBhaBtemB73n9V5vtJHwU6FVXwggTbeoJWQ1rzdz8ysDuQkpnaHyvnvzR/*,tpubD6NzVbkrYhZ4YHdDGMAYGaWxMSC1B6tPRTHuU5t3BcfcS3nrF523iFm5waFd1pP3ZvJt4Jr8XmCmsTBNx5suhcSgtzpGjGMASR3tau1hJz4/*))") 601 multi_b = descsum_create("wsh(multi(1,tpubD6NzVbkrYhZ4YHdDGMAYGaWxMSC1B6tPRTHuU5t3BcfcS3nrF523iFm5waFd1pP3ZvJt4Jr8XmCmsTBNx5suhcSgtzpGjGMASR3tau1hJz4/*,tpubD6NzVbkrYhZ4Y2RLiuEzNQkntjmsLpPYDm3LTRBYynUQtDtpzeUKAcb9sYthSFL3YR74cdFgF5mW8yKxv2W2CWuZDFR2dUpE5PF9kbrVXNZ/*))") 602 addr_a = self.nodes[0].deriveaddresses(multi_a, 0)[0] 603 addr_b = self.nodes[0].deriveaddresses(multi_b, 0)[0] 604 txid_a = self.nodes[0].sendtoaddress(addr_a, 0.01) 605 txid_b = self.nodes[0].sendtoaddress(addr_b, 0.01) 606 self.generate(self.nodes[0], 1, sync_fun=self.no_op) 607 # Prevent race of listunspent with outstanding TxAddedToMempool notifications 608 self.nodes[0].syncwithvalidationinterfacequeue() 609 # Now import the descriptors, make sure we can identify on which descriptor each coin was received. 610 self.nodes[0].createwallet(wallet_name="wo", disable_private_keys=True) 611 wo_wallet = self.nodes[0].get_wallet_rpc("wo") 612 wo_wallet.importdescriptors([ 613 { 614 "desc": multi_a, 615 "active": False, 616 "timestamp": "now", 617 }, 618 { 619 "desc": multi_b, 620 "active": False, 621 "timestamp": "now", 622 }, 623 ]) 624 coins = wo_wallet.listunspent(minconf=0) 625 assert_equal(len(coins), 2) 626 coin_a = next(c for c in coins if c["txid"] == txid_a) 627 assert_equal(coin_a["parent_descs"][0], multi_a) 628 coin_b = next(c for c in coins if c["txid"] == txid_b) 629 assert_equal(coin_b["parent_descs"][0], multi_b) 630 self.nodes[0].unloadwallet("wo") 631 632 self.log.info("Test -spendzeroconfchange") 633 self.restart_node(0, ["-spendzeroconfchange=0"]) 634 635 # create new wallet and fund it with a confirmed UTXO 636 self.nodes[0].createwallet(wallet_name="zeroconf", load_on_startup=True) 637 zeroconf_wallet = self.nodes[0].get_wallet_rpc("zeroconf") 638 default_wallet = self.nodes[0].get_wallet_rpc(self.default_wallet_name) 639 default_wallet.sendtoaddress(zeroconf_wallet.getnewaddress(), Decimal('1.0')) 640 self.generate(self.nodes[0], 1, sync_fun=self.no_op) 641 utxos = zeroconf_wallet.listunspent(minconf=0) 642 assert_equal(len(utxos), 1) 643 assert_equal(utxos[0]['confirmations'], 1) 644 645 # spend confirmed UTXO to ourselves 646 zeroconf_wallet.sendall(recipients=[zeroconf_wallet.getnewaddress()]) 647 utxos = zeroconf_wallet.listunspent(minconf=0) 648 assert_equal(len(utxos), 1) 649 assert_equal(utxos[0]['confirmations'], 0) 650 # accounts for untrusted pending balance 651 bal = zeroconf_wallet.getbalances() 652 assert_equal(bal['mine']['trusted'], 0) 653 assert_equal(bal['mine']['untrusted_pending'], utxos[0]['amount']) 654 655 # spending an unconfirmed UTXO sent to ourselves should fail 656 assert_raises_rpc_error(-6, "Insufficient funds", zeroconf_wallet.sendtoaddress, zeroconf_wallet.getnewaddress(), Decimal('0.5')) 657 658 # check that it works again with -spendzeroconfchange set (=default) 659 self.restart_node(0, ["-spendzeroconfchange=1"]) 660 # Make sure the wallet knows the tx in the mempool 661 self.nodes[0].syncwithvalidationinterfacequeue() 662 663 zeroconf_wallet = self.nodes[0].get_wallet_rpc("zeroconf") 664 utxos = zeroconf_wallet.listunspent(minconf=0) 665 assert_equal(len(utxos), 1) 666 assert_equal(utxos[0]['confirmations'], 0) 667 # accounts for trusted balance 668 bal = zeroconf_wallet.getbalances() 669 assert_equal(bal['mine']['trusted'], utxos[0]['amount']) 670 assert_equal(bal['mine']['untrusted_pending'], 0) 671 672 zeroconf_wallet.sendtoaddress(zeroconf_wallet.getnewaddress(), Decimal('0.5')) 673 674 self.test_chain_listunspent() 675 676 def test_chain_listunspent(self): 677 self.wallet = MiniWallet(self.nodes[0]) 678 self.nodes[0].get_wallet_rpc(self.default_wallet_name).sendtoaddress(self.wallet.get_address(), "5") 679 self.generate(self.wallet, 1, sync_fun=self.no_op) 680 self.nodes[0].createwallet("watch_wallet", disable_private_keys=True) 681 watch_wallet = self.nodes[0].get_wallet_rpc("watch_wallet") 682 import_res = watch_wallet.importdescriptors([{"desc": self.wallet.get_descriptor(), "timestamp": "now"}]) 683 assert_equal(import_res[0]["success"], True) 684 685 # DEFAULT_ANCESTOR_LIMIT transactions off a confirmed tx should be fine 686 chain = self.wallet.create_self_transfer_chain(chain_length=DEFAULT_ANCESTOR_LIMIT) 687 ancestor_vsize = 0 688 ancestor_fees = Decimal(0) 689 690 for i, t in enumerate(chain): 691 ancestor_vsize += t["tx"].get_vsize() 692 ancestor_fees += t["fee"] 693 self.wallet.sendrawtransaction(from_node=self.nodes[0], tx_hex=t["hex"]) 694 # Check that listunspent ancestor{count, size, fees} yield the correct results 695 wallet_unspent = watch_wallet.listunspent(minconf=0) 696 this_unspent = next(utxo_info for utxo_info in wallet_unspent if utxo_info["txid"] == t["txid"]) 697 assert_equal(this_unspent['ancestorcount'], i + 1) 698 assert_equal(this_unspent['ancestorsize'], ancestor_vsize) 699 assert_equal(this_unspent['ancestorfees'], ancestor_fees * COIN) 700 701 702 if __name__ == '__main__': 703 WalletTest(__file__).main()