Changeset View
Changeset View
Standalone View
Standalone View
test/functional/wallet_balance.py
#!/usr/bin/env python3 | #!/usr/bin/env python3 | ||||
# Copyright (c) 2018-2019 The Bitcoin Core developers | # Copyright (c) 2018-2019 The Bitcoin Core developers | ||||
# Distributed under the MIT software license, see the accompanying | # Distributed under the MIT software license, see the accompanying | ||||
# file COPYING or http://www.opensource.org/licenses/mit-license.php. | # file COPYING or http://www.opensource.org/licenses/mit-license.php. | ||||
"""Test the wallet balance RPC methods.""" | """Test the wallet balance RPC methods.""" | ||||
import struct | import struct | ||||
from decimal import Decimal | from decimal import Decimal | ||||
from test_framework.address import ADDRESS_ECREG_UNSPENDABLE as ADDRESS_WATCHONLY | from test_framework.address import ADDRESS_ECREG_UNSPENDABLE as ADDRESS_WATCHONLY | ||||
from test_framework.test_framework import BitcoinTestFramework | from test_framework.test_framework import BitcoinTestFramework | ||||
from test_framework.util import assert_equal, assert_raises_rpc_error | from test_framework.util import assert_equal, assert_raises_rpc_error | ||||
FAR_IN_THE_FUTURE = 2000000000 | |||||
def create_transactions(node, address, amt, fees): | def create_transactions(node, address, amt, fees): | ||||
# Create and sign raw transactions from node to address for amt. | # Create and sign raw transactions from node to address for amt. | ||||
# Creates a transaction for each fee and returns an array | # Creates a transaction for each fee and returns an array | ||||
# of the raw transactions. | # of the raw transactions. | ||||
utxos = [u for u in node.listunspent(0) if u["spendable"]] | utxos = [u for u in node.listunspent(0) if u["spendable"]] | ||||
# Create transactions | # Create transactions | ||||
Show All 20 Lines | def create_transactions(node, address, amt, fees): | ||||
return txs | return txs | ||||
class WalletTest(BitcoinTestFramework): | class WalletTest(BitcoinTestFramework): | ||||
def set_test_params(self): | def set_test_params(self): | ||||
self.num_nodes = 2 | self.num_nodes = 2 | ||||
self.setup_clean_chain = True | self.setup_clean_chain = True | ||||
self.extra_args = [ | |||||
# Limit mempool descendants as a hack to have wallet txs rejected | |||||
# from the mempool. This will no longer work after wellington, so | |||||
# move the activation in the future for this test. | |||||
[ | |||||
"-limitdescendantcount=3", | |||||
f"-wellingtonactivationtime={FAR_IN_THE_FUTURE}", | |||||
], | |||||
[], | |||||
] | |||||
# whitelist peers to speed up tx relay / mempool sync | # whitelist peers to speed up tx relay / mempool sync | ||||
for args in self.extra_args: | self.extra_args = [["-whitelist=noban@127.0.0.1"]] * self.num_nodes | ||||
args.append("-whitelist=noban@127.0.0.1") | |||||
def skip_test_if_missing_module(self): | def skip_test_if_missing_module(self): | ||||
self.skip_if_no_wallet() | self.skip_if_no_wallet() | ||||
def run_test(self): | def run_test(self): | ||||
if not self.options.descriptors: | if not self.options.descriptors: | ||||
# Tests legacy watchonly behavior which is not present (and does | # Tests legacy watchonly behavior which is not present (and does | ||||
# not need to be tested) in descriptor wallets | # not need to be tested) in descriptor wallets | ||||
▲ Show 20 Lines • Show All 221 Lines • ▼ Show 20 Lines | def run_test(self): | ||||
dst = self.nodes[1].getnewaddress() | dst = self.nodes[1].getnewaddress() | ||||
self.nodes[1].unloadwallet(self.default_wallet_name) | self.nodes[1].unloadwallet(self.default_wallet_name) | ||||
self.nodes[0].sendtoaddress(dst, 100000) | self.nodes[0].sendtoaddress(dst, 100000) | ||||
self.sync_all() | self.sync_all() | ||||
self.nodes[1].loadwallet(self.default_wallet_name) | self.nodes[1].loadwallet(self.default_wallet_name) | ||||
after = self.nodes[1].getbalances()["mine"]["untrusted_pending"] | after = self.nodes[1].getbalances()["mine"]["untrusted_pending"] | ||||
assert_equal(before + Decimal("100000"), after) | assert_equal(before + Decimal("100000"), after) | ||||
# Create 3 more wallet txs, where the last is not accepted to the | # Create a wallet txs which is not added to the mempool | ||||
# mempool because it is the third descendant of the tx above | txid = self.nodes[0].createwallettransaction( | ||||
for _ in range(3): | self.nodes[0].getnewaddress(), 99000000 | ||||
# Set amount high enough such that all coins are spent by each tx | ) | ||||
txid = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 99000000) | |||||
self.log.info("Check that wallet txs not in the mempool are untrusted") | self.log.info("Check that wallet txs not in the mempool are untrusted") | ||||
assert txid not in self.nodes[0].getrawmempool() | assert txid not in self.nodes[0].getrawmempool() | ||||
assert_equal(self.nodes[0].gettransaction(txid)["trusted"], False) | assert_equal(self.nodes[0].gettransaction(txid)["trusted"], False) | ||||
assert_equal(self.nodes[0].getbalance(minconf=0), 0) | assert_equal(self.nodes[0].getbalance(minconf=0), 0) | ||||
self.log.info("Test replacement and reorg of non-mempool tx") | self.log.info("Test replacement and reorg of non-mempool tx") | ||||
tx_orig = self.nodes[0].gettransaction(txid)["hex"] | tx_orig = self.nodes[0].gettransaction(txid)["hex"] | ||||
Show All 9 Lines | def run_test(self): | ||||
) | ) | ||||
self.sync_all() | self.sync_all() | ||||
self.nodes[1].sendrawtransaction(hexstring=tx_replace, maxfeerate=0) | self.nodes[1].sendrawtransaction(hexstring=tx_replace, maxfeerate=0) | ||||
# Now confirm tx_replace | # Now confirm tx_replace | ||||
block_reorg = self.generatetoaddress(self.nodes[1], 1, ADDRESS_WATCHONLY)[0] | block_reorg = self.generatetoaddress(self.nodes[1], 1, ADDRESS_WATCHONLY)[0] | ||||
assert_equal(self.nodes[0].getbalance(minconf=0), total_amount) | assert_equal(self.nodes[0].getbalance(minconf=0), total_amount) | ||||
self.log.info("Put txs back into mempool of node 1 (not node 0)") | self.log.info("Put txs back into the mempool of nodes") | ||||
self.nodes[0].invalidateblock(block_reorg) | self.nodes[0].invalidateblock(block_reorg) | ||||
self.nodes[1].invalidateblock(block_reorg) | self.nodes[1].invalidateblock(block_reorg) | ||||
# wallet txs not in the mempool are untrusted | |||||
assert_equal(self.nodes[0].getbalance(minconf=0), 0) | |||||
self.generatetoaddress(self.nodes[0], 1, ADDRESS_WATCHONLY, sync_fun=self.no_op) | |||||
# wallet txs not in the mempool are untrusted | |||||
assert_equal(self.nodes[0].getbalance(minconf=0), 0) | |||||
# Now confirm tx_orig | # Now confirm tx_orig | ||||
self.restart_node(1, ["-persistmempool=0"]) | self.restart_node(1, ["-persistmempool=0"]) | ||||
self.connect_nodes(0, 1) | self.connect_nodes(0, 1) | ||||
self.sync_blocks() | self.sync_blocks() | ||||
self.nodes[1].sendrawtransaction(tx_orig) | self.nodes[1].sendrawtransaction(tx_orig) | ||||
self.generatetoaddress(self.nodes[1], 1, ADDRESS_WATCHONLY) | self.generatetoaddress(self.nodes[1], 1, ADDRESS_WATCHONLY) | ||||
# The reorg recovered our fee of 1 coin | # The reorg recovered our fee of 1 coin | ||||
assert_equal(self.nodes[0].getbalance(minconf=0), total_amount + 1000000) | assert_equal(self.nodes[0].getbalance(minconf=0), total_amount + 1000000) | ||||
if __name__ == "__main__": | if __name__ == "__main__": | ||||
WalletTest().main() | WalletTest().main() |