wallet_basic.py raw
1 #!/usr/bin/env python3
2 # Copyright (c) 2014-present 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"
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 fee_rate_sat_vb = fee_per_byte * Decimal(1e8)
244 txid = self.nodes[2].sendtoaddress(address, 10, "", "", False, fee_rate=fee_rate_sat_vb)
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, fee_rate=fee_rate_sat_vb)
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, "", [], fee_rate=fee_rate_sat_vb)
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], fee_rate=fee_rate_sat_vb)
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], fee_rate=fee_rate_sat_vb)
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', '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()
704