Merge bitcoin/bitcoin#23047: test: Use MiniWallet in mempool_persist

faae0988d6 test: Check other fields are loaded correctly as well (MarcoFalke)
fa4db92617 test: Remove unused self.connect_nodes (MarcoFalke)
fafb7b7a89 test: pep8 (MarcoFalke)
fa32cb2467 test: Use MiniWallet in mempool_persist (MarcoFalke)
faca688a85 test: Add MiniWallet get_descriptor function (MarcoFalke)

Pull request description:

ACKs for top commit:
  laanwj:
    Code review ACK faae0988d6

Tree-SHA512: 6124f16ee1f3f416c50dc07aebe8846ff7e2b7c8e5dd84f9517cb5f1df021b9e57ed7c7e17bc099a37c663cd93f6d417c5e0622c0b359956403d53e705eb5549
This commit is contained in:
W. J. van der Laan
2021-09-24 16:29:21 +02:00
2 changed files with 42 additions and 25 deletions

View File

@ -46,6 +46,7 @@ from test_framework.util import (
assert_greater_than_or_equal, assert_greater_than_or_equal,
assert_raises_rpc_error, assert_raises_rpc_error,
) )
from test_framework.wallet import MiniWallet
class MempoolPersistTest(BitcoinTestFramework): class MempoolPersistTest(BitcoinTestFramework):
@ -53,15 +54,26 @@ class MempoolPersistTest(BitcoinTestFramework):
self.num_nodes = 3 self.num_nodes = 3
self.extra_args = [[], ["-persistmempool=0"], []] self.extra_args = [[], ["-persistmempool=0"], []]
def skip_test_if_missing_module(self):
self.skip_if_no_wallet()
def run_test(self): def run_test(self):
self.mini_wallet = MiniWallet(self.nodes[2])
self.mini_wallet.rescan_utxos()
if self.is_sqlite_compiled():
self.nodes[2].createwallet(
wallet_name="watch",
descriptors=True,
disable_private_keys=True,
load_on_startup=False,
)
wallet_watch = self.nodes[2].get_wallet_rpc("watch")
assert_equal([{'success': True}], wallet_watch.importdescriptors([{'desc': self.mini_wallet.get_descriptor(), 'timestamp': 0}]))
self.log.debug("Send 5 transactions from node2 (to its own address)") self.log.debug("Send 5 transactions from node2 (to its own address)")
tx_creation_time_lower = int(time.time()) tx_creation_time_lower = int(time.time())
for _ in range(5): for _ in range(5):
last_txid = self.nodes[2].sendtoaddress(self.nodes[2].getnewaddress(), Decimal("10")) last_txid = self.mini_wallet.send_self_transfer(from_node=self.nodes[2])["txid"]
node2_balance = self.nodes[2].getbalance() if self.is_sqlite_compiled():
self.nodes[2].syncwithvalidationinterfacequeue() # Flush mempool to wallet
node2_balance = wallet_watch.getbalance()
self.sync_all() self.sync_all()
tx_creation_time_higher = int(time.time()) tx_creation_time_higher = int(time.time())
@ -82,16 +94,16 @@ class MempoolPersistTest(BitcoinTestFramework):
assert_equal(total_fee_old, self.nodes[0].getmempoolinfo()['total_fee']) assert_equal(total_fee_old, self.nodes[0].getmempoolinfo()['total_fee'])
assert_equal(total_fee_old, sum(v['fees']['base'] for k, v in self.nodes[0].getrawmempool(verbose=True).items())) assert_equal(total_fee_old, sum(v['fees']['base'] for k, v in self.nodes[0].getrawmempool(verbose=True).items()))
tx_creation_time = self.nodes[0].getmempoolentry(txid=last_txid)['time'] last_entry = self.nodes[0].getmempoolentry(txid=last_txid)
tx_creation_time = last_entry['time']
assert_greater_than_or_equal(tx_creation_time, tx_creation_time_lower) assert_greater_than_or_equal(tx_creation_time, tx_creation_time_lower)
assert_greater_than_or_equal(tx_creation_time_higher, tx_creation_time) assert_greater_than_or_equal(tx_creation_time_higher, tx_creation_time)
# disconnect nodes & make a txn that remains in the unbroadcast set. # disconnect nodes & make a txn that remains in the unbroadcast set.
self.disconnect_nodes(0, 1) self.disconnect_nodes(0, 1)
assert(len(self.nodes[0].getpeerinfo()) == 0) assert_equal(len(self.nodes[0].getpeerinfo()), 0)
assert(len(self.nodes[0].p2ps) == 0) assert_equal(len(self.nodes[0].p2ps), 0)
self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), Decimal("12")) self.mini_wallet.send_self_transfer(from_node=self.nodes[0])
self.connect_nodes(0, 2)
self.log.debug("Stop-start the nodes. Verify that node0 has the transactions in its mempool and node1 does not. Verify that node2 calculates its balance correctly after loading wallet transactions.") self.log.debug("Stop-start the nodes. Verify that node0 has the transactions in its mempool and node1 does not. Verify that node2 calculates its balance correctly after loading wallet transactions.")
self.stop_nodes() self.stop_nodes()
@ -111,17 +123,19 @@ class MempoolPersistTest(BitcoinTestFramework):
fees = self.nodes[0].getmempoolentry(txid=last_txid)['fees'] fees = self.nodes[0].getmempoolentry(txid=last_txid)['fees']
assert_equal(fees['base'] + Decimal('0.00001000'), fees['modified']) assert_equal(fees['base'] + Decimal('0.00001000'), fees['modified'])
self.log.debug('Verify time is loaded correctly') self.log.debug('Verify all fields are loaded correctly')
assert_equal(tx_creation_time, self.nodes[0].getmempoolentry(txid=last_txid)['time']) assert_equal(last_entry, self.nodes[0].getmempoolentry(txid=last_txid))
# Verify accounting of mempool transactions after restart is correct # Verify accounting of mempool transactions after restart is correct
self.nodes[2].syncwithvalidationinterfacequeue() # Flush mempool to wallet if self.is_sqlite_compiled():
assert_equal(node2_balance, self.nodes[2].getbalance()) self.nodes[2].loadwallet("watch")
wallet_watch = self.nodes[2].get_wallet_rpc("watch")
self.nodes[2].syncwithvalidationinterfacequeue() # Flush mempool to wallet
assert_equal(node2_balance, wallet_watch.getbalance())
# start node0 with wallet disabled so wallet transactions don't get resubmitted
self.log.debug("Stop-start node0 with -persistmempool=0. Verify that it doesn't load its mempool.dat file.") self.log.debug("Stop-start node0 with -persistmempool=0. Verify that it doesn't load its mempool.dat file.")
self.stop_nodes() self.stop_nodes()
self.start_node(0, extra_args=["-persistmempool=0", "-disablewallet"]) self.start_node(0, extra_args=["-persistmempool=0"])
assert self.nodes[0].getmempoolinfo()["loaded"] assert self.nodes[0].getmempoolinfo()["loaded"]
assert_equal(len(self.nodes[0].getrawmempool()), 0) assert_equal(len(self.nodes[0].getrawmempool()), 0)
@ -164,18 +178,18 @@ class MempoolPersistTest(BitcoinTestFramework):
# ensure node0 doesn't have any connections # ensure node0 doesn't have any connections
# make a transaction that will remain in the unbroadcast set # make a transaction that will remain in the unbroadcast set
assert(len(node0.getpeerinfo()) == 0) assert_equal(len(node0.getpeerinfo()), 0)
assert(len(node0.p2ps) == 0) assert_equal(len(node0.p2ps), 0)
node0.sendtoaddress(self.nodes[1].getnewaddress(), Decimal("12")) self.mini_wallet.send_self_transfer(from_node=node0)
# shutdown, then startup with wallet disabled # shutdown, then startup with wallet disabled
self.stop_nodes() self.restart_node(0, extra_args=["-disablewallet"])
self.start_node(0, extra_args=["-disablewallet"])
# check that txn gets broadcast due to unbroadcast logic # check that txn gets broadcast due to unbroadcast logic
conn = node0.add_p2p_connection(P2PTxInvStore()) conn = node0.add_p2p_connection(P2PTxInvStore())
node0.mockscheduler(16*60) # 15 min + 1 for buffer node0.mockscheduler(16 * 60) # 15 min + 1 for buffer
self.wait_until(lambda: len(conn.get_invs()) == 1) self.wait_until(lambda: len(conn.get_invs()) == 1)
if __name__ == '__main__':
if __name__ == "__main__":
MempoolPersistTest().main() MempoolPersistTest().main()

View File

@ -82,7 +82,7 @@ class MiniWallet:
def rescan_utxos(self): def rescan_utxos(self):
"""Drop all utxos and rescan the utxo set""" """Drop all utxos and rescan the utxo set"""
self._utxos = [] self._utxos = []
res = self._test_node.scantxoutset(action="start", scanobjects=[f'raw({self._scriptPubKey.hex()})']) res = self._test_node.scantxoutset(action="start", scanobjects=[self.get_descriptor()])
assert_equal(True, res['success']) assert_equal(True, res['success'])
for utxo in res['unspents']: for utxo in res['unspents']:
self._utxos.append({'txid': utxo['txid'], 'vout': utxo['vout'], 'value': utxo['amount']}) self._utxos.append({'txid': utxo['txid'], 'vout': utxo['vout'], 'value': utxo['amount']})
@ -110,12 +110,15 @@ class MiniWallet:
def generate(self, num_blocks): def generate(self, num_blocks):
"""Generate blocks with coinbase outputs to the internal address, and append the outputs to the internal list""" """Generate blocks with coinbase outputs to the internal address, and append the outputs to the internal list"""
blocks = self._test_node.generatetodescriptor(num_blocks, f'raw({self._scriptPubKey.hex()})') blocks = self._test_node.generatetodescriptor(num_blocks, self.get_descriptor())
for b in blocks: for b in blocks:
cb_tx = self._test_node.getblock(blockhash=b, verbosity=2)['tx'][0] cb_tx = self._test_node.getblock(blockhash=b, verbosity=2)['tx'][0]
self._utxos.append({'txid': cb_tx['txid'], 'vout': 0, 'value': cb_tx['vout'][0]['value']}) self._utxos.append({'txid': cb_tx['txid'], 'vout': 0, 'value': cb_tx['vout'][0]['value']})
return blocks return blocks
def get_descriptor(self):
return self._test_node.getdescriptorinfo(f'raw({self._scriptPubKey.hex()})')['descriptor']
def get_address(self): def get_address(self):
return self._address return self._address