aboutsummaryrefslogtreecommitdiff
path: root/test/functional/wallet_basic.py
diff options
context:
space:
mode:
Diffstat (limited to 'test/functional/wallet_basic.py')
-rwxr-xr-xtest/functional/wallet_basic.py114
1 files changed, 74 insertions, 40 deletions
diff --git a/test/functional/wallet_basic.py b/test/functional/wallet_basic.py
index ab38ddb996..599e506f98 100755
--- a/test/functional/wallet_basic.py
+++ b/test/functional/wallet_basic.py
@@ -13,6 +13,7 @@ from test_framework.util import (
assert_equal,
assert_fee_amount,
assert_raises_rpc_error,
+ find_vout_for_address,
)
from test_framework.wallet_util import test_address
@@ -59,14 +60,14 @@ class WalletTest(BitcoinTestFramework):
self.log.info("Mining blocks...")
- self.nodes[0].generate(1)
+ self.generate(self.nodes[0], 1)
walletinfo = self.nodes[0].getwalletinfo()
assert_equal(walletinfo['immature_balance'], 50)
assert_equal(walletinfo['balance'], 0)
self.sync_all(self.nodes[0:3])
- self.nodes[1].generate(COINBASE_MATURITY + 1)
+ self.generate(self.nodes[1], COINBASE_MATURITY + 1)
self.sync_all(self.nodes[0:3])
assert_equal(self.nodes[0].getbalance(), 50)
@@ -115,19 +116,55 @@ class WalletTest(BitcoinTestFramework):
assert_equal(walletinfo['immature_balance'], 0)
# Have node0 mine a block, thus it will collect its own fee.
- self.nodes[0].generate(1)
+ self.generate(self.nodes[0], 1)
self.sync_all(self.nodes[0:3])
# Exercise locking of unspent outputs
unspent_0 = self.nodes[2].listunspent()[0]
unspent_0 = {"txid": unspent_0["txid"], "vout": unspent_0["vout"]}
+ # Trying to unlock an output which isn't locked should error
assert_raises_rpc_error(-8, "Invalid parameter, expected locked output", self.nodes[2].lockunspent, True, [unspent_0])
+
+ # Locking an already-locked output should error
self.nodes[2].lockunspent(False, [unspent_0])
assert_raises_rpc_error(-8, "Invalid parameter, output already locked", self.nodes[2].lockunspent, False, [unspent_0])
+
+ # Restarting the node should clear the lock
+ self.restart_node(2)
+ self.nodes[2].lockunspent(False, [unspent_0])
+
+ # Unloading and reloating the wallet should clear the lock
+ assert_equal(self.nodes[0].listwallets(), [self.default_wallet_name])
+ self.nodes[2].unloadwallet(self.default_wallet_name)
+ self.nodes[2].loadwallet(self.default_wallet_name)
+ assert_equal(len(self.nodes[2].listlockunspent()), 0)
+
+ # Locking non-persistently, then re-locking persistently, is allowed
+ self.nodes[2].lockunspent(False, [unspent_0])
+ self.nodes[2].lockunspent(False, [unspent_0], True)
+
+ # Restarting the node with the lock written to the wallet should keep the lock
+ self.restart_node(2)
+ assert_raises_rpc_error(-8, "Invalid parameter, output already locked", self.nodes[2].lockunspent, False, [unspent_0])
+
+ # Unloading and reloading the wallet with a persistent lock should keep the lock
+ self.nodes[2].unloadwallet(self.default_wallet_name)
+ self.nodes[2].loadwallet(self.default_wallet_name)
+ assert_raises_rpc_error(-8, "Invalid parameter, output already locked", self.nodes[2].lockunspent, False, [unspent_0])
+
+ # Locked outputs should not be used, even if they are the only available funds
assert_raises_rpc_error(-6, "Insufficient funds", self.nodes[2].sendtoaddress, self.nodes[2].getnewaddress(), 20)
assert_equal([unspent_0], self.nodes[2].listlockunspent())
+
+ # Unlocking should remove the persistent lock
self.nodes[2].lockunspent(True, [unspent_0])
+ self.restart_node(2)
assert_equal(len(self.nodes[2].listlockunspent()), 0)
+
+ # Reconnect node 2 after restarts
+ self.connect_nodes(1, 2)
+ self.connect_nodes(0, 2)
+
assert_raises_rpc_error(-8, "txid must be of length 64 (not 34, for '0000000000000000000000000000000000')",
self.nodes[2].lockunspent, False,
[{"txid": "0000000000000000000000000000000000", "vout": 0}])
@@ -159,7 +196,7 @@ class WalletTest(BitcoinTestFramework):
assert_equal(len(self.nodes[1].listlockunspent()), 0)
# Have node1 generate 100 blocks (so node0 can recover the fee)
- self.nodes[1].generate(COINBASE_MATURITY)
+ self.generate(self.nodes[1], COINBASE_MATURITY)
self.sync_all(self.nodes[0:3])
# node0 should end up with 100 btc in block rewards plus fees, but
@@ -188,7 +225,7 @@ class WalletTest(BitcoinTestFramework):
self.nodes[1].sendrawtransaction(hexstring=txns_to_send[1]["hex"], maxfeerate=0)
# Have node1 mine a block to confirm transactions:
- self.nodes[1].generate(1)
+ self.generate(self.nodes[1], 1)
self.sync_all(self.nodes[0:3])
assert_equal(self.nodes[0].getbalance(), 0)
@@ -203,14 +240,14 @@ class WalletTest(BitcoinTestFramework):
fee_per_byte = Decimal('0.001') / 1000
self.nodes[2].settxfee(fee_per_byte * 1000)
txid = self.nodes[2].sendtoaddress(address, 10, "", "", False)
- self.nodes[2].generate(1)
+ self.generate(self.nodes[2], 1)
self.sync_all(self.nodes[0:3])
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']))
assert_equal(self.nodes[0].getbalance(), Decimal('10'))
# Send 10 BTC with subtract fee from amount
txid = self.nodes[2].sendtoaddress(address, 10, "", "", True)
- self.nodes[2].generate(1)
+ self.generate(self.nodes[2], 1)
self.sync_all(self.nodes[0:3])
node_2_bal -= Decimal('10')
assert_equal(self.nodes[2].getbalance(), node_2_bal)
@@ -220,7 +257,7 @@ class WalletTest(BitcoinTestFramework):
# Sendmany 10 BTC
txid = self.nodes[2].sendmany('', {address: 10}, 0, "", [])
- self.nodes[2].generate(1)
+ self.generate(self.nodes[2], 1)
self.sync_all(self.nodes[0:3])
node_0_bal += Decimal('10')
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']))
@@ -228,7 +265,7 @@ class WalletTest(BitcoinTestFramework):
# Sendmany 10 BTC with subtract fee from amount
txid = self.nodes[2].sendmany('', {address: 10}, 0, "", [address])
- self.nodes[2].generate(1)
+ self.generate(self.nodes[2], 1)
self.sync_all(self.nodes[0:3])
node_2_bal -= Decimal('10')
assert_equal(self.nodes[2].getbalance(), node_2_bal)
@@ -241,7 +278,7 @@ class WalletTest(BitcoinTestFramework):
# Test passing fee_rate as a string
txid = self.nodes[2].sendmany(amounts={address: 10}, fee_rate=str(fee_rate_sat_vb))
- self.nodes[2].generate(1)
+ self.generate(self.nodes[2], 1)
self.sync_all(self.nodes[0:3])
balance = self.nodes[2].getbalance()
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']))
@@ -252,7 +289,7 @@ class WalletTest(BitcoinTestFramework):
# Test passing fee_rate as an integer
amount = Decimal("0.0001")
txid = self.nodes[2].sendmany(amounts={address: amount}, fee_rate=fee_rate_sat_vb)
- self.nodes[2].generate(1)
+ self.generate(self.nodes[2], 1)
self.sync_all(self.nodes[0:3])
balance = self.nodes[2].getbalance()
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']))
@@ -314,7 +351,7 @@ class WalletTest(BitcoinTestFramework):
self.nodes[1].sendrawtransaction(signed_raw_tx['hex'])
self.sync_all()
- self.nodes[1].generate(1) # mine a block
+ self.generate(self.nodes[1], 1) # mine a block
self.sync_all()
unspent_txs = self.nodes[0].listunspent() # zero value tx must be in listunspents output
@@ -337,13 +374,13 @@ class WalletTest(BitcoinTestFramework):
txid_not_broadcast = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 2)
tx_obj_not_broadcast = self.nodes[0].gettransaction(txid_not_broadcast)
- self.nodes[1].generate(1) # mine a block, tx should not be in there
+ self.generate(self.nodes[1], 1) # mine a block, tx should not be in there
self.sync_all(self.nodes[0:3])
assert_equal(self.nodes[2].getbalance(), node_2_bal) # should not be changed because tx was not broadcasted
# now broadcast from another node, mine a block, sync, and check the balance
self.nodes[1].sendrawtransaction(tx_obj_not_broadcast['hex'])
- self.nodes[1].generate(1)
+ self.generate(self.nodes[1], 1)
self.sync_all(self.nodes[0:3])
node_2_bal += 2
tx_obj_not_broadcast = self.nodes[0].gettransaction(txid_not_broadcast)
@@ -362,7 +399,7 @@ class WalletTest(BitcoinTestFramework):
self.connect_nodes(0, 2)
self.sync_blocks(self.nodes[0:3])
- self.nodes[0].generate(1)
+ self.generate(self.nodes[0], 1)
self.sync_blocks(self.nodes[0:3])
node_2_bal += 2
@@ -391,7 +428,7 @@ class WalletTest(BitcoinTestFramework):
assert_raises_rpc_error(-3, "Invalid amount", self.nodes[0].sendtoaddress, self.nodes[2].getnewaddress(), "1f-4")
# This will raise an exception since generate does not accept a string
- assert_raises_rpc_error(-1, "not an integer", self.nodes[0].generate, "2")
+ assert_raises_rpc_error(-1, "not an integer", self.generate, self.nodes[0], "2")
if not self.options.descriptors:
@@ -427,7 +464,10 @@ class WalletTest(BitcoinTestFramework):
# 1. Send some coins to generate new UTXO
address_to_import = self.nodes[2].getnewaddress()
txid = self.nodes[0].sendtoaddress(address_to_import, 1)
- self.nodes[0].generate(1)
+ self.sync_mempools(self.nodes[0:3])
+ vout = find_vout_for_address(self.nodes[2], txid, address_to_import)
+ self.nodes[2].lockunspent(False, [{"txid": txid, "vout": vout}])
+ self.generate(self.nodes[0], 1)
self.sync_all(self.nodes[0:3])
self.log.info("Test sendtoaddress with fee_rate param (explicit fee rate in sat/vB)")
@@ -440,7 +480,7 @@ class WalletTest(BitcoinTestFramework):
# Test passing fee_rate as an integer
txid = self.nodes[2].sendtoaddress(address=address, amount=amount, fee_rate=fee_rate_sat_vb)
tx_size = self.get_vsize(self.nodes[2].gettransaction(txid)['hex'])
- self.nodes[0].generate(1)
+ self.generate(self.nodes[0], 1)
self.sync_all(self.nodes[0:3])
postbalance = self.nodes[2].getbalance()
fee = prebalance - postbalance - Decimal(amount)
@@ -453,7 +493,7 @@ class WalletTest(BitcoinTestFramework):
# Test passing fee_rate as a string
txid = self.nodes[2].sendtoaddress(address=address, amount=amount, fee_rate=str(fee_rate_sat_vb))
tx_size = self.get_vsize(self.nodes[2].gettransaction(txid)['hex'])
- self.nodes[0].generate(1)
+ self.generate(self.nodes[0], 1)
self.sync_all(self.nodes[0:3])
postbalance = self.nodes[2].getbalance()
fee = prebalance - postbalance - amount
@@ -515,7 +555,7 @@ class WalletTest(BitcoinTestFramework):
# Mine a block from node0 to an address from node1
coinbase_addr = self.nodes[1].getnewaddress()
- block_hash = self.nodes[0].generatetoaddress(1, coinbase_addr)[0]
+ block_hash = self.generatetoaddress(self.nodes[0], 1, coinbase_addr)[0]
coinbase_txid = self.nodes[0].getblock(block_hash)['tx'][0]
self.sync_all(self.nodes[0:3])
@@ -524,7 +564,7 @@ class WalletTest(BitcoinTestFramework):
# check if wallet or blockchain maintenance changes the balance
self.sync_all(self.nodes[0:3])
- blocks = self.nodes[0].generate(2)
+ blocks = self.generate(self.nodes[0], 2)
self.sync_all(self.nodes[0:3])
balance_nodes = [self.nodes[i].getbalance() for i in range(3)]
block_count = self.nodes[0].getblockcount()
@@ -542,23 +582,17 @@ class WalletTest(BitcoinTestFramework):
assert label in self.nodes[0].listlabels()
self.nodes[0].rpc.ensure_ascii = True # restore to default
- # maintenance tests
- maintenance = [
- '-rescan',
- '-reindex',
- ]
+ # -reindex tests
chainlimit = 6
- for m in maintenance:
- self.log.info("Test " + m)
- self.stop_nodes()
- # set lower ancestor limit for later
- self.start_node(0, [m, "-limitancestorcount=" + str(chainlimit)])
- self.start_node(1, [m, "-limitancestorcount=" + str(chainlimit)])
- self.start_node(2, [m, "-limitancestorcount=" + str(chainlimit)])
- if m == '-reindex':
- # reindex will leave rpc warm up "early"; Wait for it to finish
- self.wait_until(lambda: [block_count] * 3 == [self.nodes[i].getblockcount() for i in range(3)])
- assert_equal(balance_nodes, [self.nodes[i].getbalance() for i in range(3)])
+ self.log.info("Test -reindex")
+ self.stop_nodes()
+ # set lower ancestor limit for later
+ self.start_node(0, ['-reindex', "-limitancestorcount=" + str(chainlimit)])
+ self.start_node(1, ['-reindex', "-limitancestorcount=" + str(chainlimit)])
+ self.start_node(2, ['-reindex', "-limitancestorcount=" + str(chainlimit)])
+ # reindex will leave rpc warm up "early"; Wait for it to finish
+ self.wait_until(lambda: [block_count] * 3 == [self.nodes[i].getblockcount() for i in range(3)])
+ assert_equal(balance_nodes, [self.nodes[i].getbalance() for i in range(3)])
# Exercise listsinceblock with the last two blocks
coinbase_tx_1 = self.nodes[0].listsinceblock(blocks[0])
@@ -572,13 +606,13 @@ class WalletTest(BitcoinTestFramework):
# Get all non-zero utxos together
chain_addrs = [self.nodes[0].getnewaddress(), self.nodes[0].getnewaddress()]
singletxid = self.nodes[0].sendtoaddress(chain_addrs[0], self.nodes[0].getbalance(), "", "", True)
- self.nodes[0].generate(1)
+ self.generate(self.nodes[0], 1)
node0_balance = self.nodes[0].getbalance()
# Split into two chains
rawtx = self.nodes[0].createrawtransaction([{"txid": singletxid, "vout": 0}], {chain_addrs[0]: node0_balance / 2 - Decimal('0.01'), chain_addrs[1]: node0_balance / 2 - Decimal('0.01')})
signedtx = self.nodes[0].signrawtransactionwithwallet(rawtx)
singletxid = self.nodes[0].sendrawtransaction(hexstring=signedtx["hex"], maxfeerate=0)
- self.nodes[0].generate(1)
+ self.generate(self.nodes[0], 1)
# Make a long chain of unconfirmed payments without hitting mempool limit
# Each tx we make leaves only one output of change on a chain 1 longer
@@ -629,7 +663,7 @@ class WalletTest(BitcoinTestFramework):
assert not address_info["ischange"]
# Test getaddressinfo 'ischange' field on change address.
- self.nodes[0].generate(1)
+ self.generate(self.nodes[0], 1)
destination = self.nodes[1].getnewaddress()
txid = self.nodes[0].sendtoaddress(destination, 0.123)
tx = self.nodes[0].decoderawtransaction(self.nodes[0].gettransaction(txid)['hex'])