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