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