diff --git a/test/functional/mempool_expiry.py b/test/functional/mempool_expiry.py index 8b9b7b155a..4c46075ae9 100755 --- a/test/functional/mempool_expiry.py +++ b/test/functional/mempool_expiry.py @@ -16,8 +16,8 @@ from test_framework.test_framework import BitcoinTestFramework from test_framework.util import ( assert_equal, assert_raises_rpc_error, - find_vout_for_address, ) +from test_framework.wallet import MiniWallet DEFAULT_MEMPOOL_EXPIRY = 336 # hours CUSTOM_MEMPOOL_EXPIRY = 10 # hours @@ -26,44 +26,50 @@ CUSTOM_MEMPOOL_EXPIRY = 10 # hours class MempoolExpiryTest(BitcoinTestFramework): def set_test_params(self): self.num_nodes = 1 - - def skip_test_if_missing_module(self): - self.skip_if_no_wallet() + self.setup_clean_chain = True def test_transaction_expiry(self, timeout): """Tests that a transaction expires after the expiry timeout and its children are removed as well.""" node = self.nodes[0] + self.wallet = MiniWallet(node) + + # Add enough mature utxos to the wallet so that all txs spend confirmed coins. + self.wallet.generate(4) + node.generate(100) # Send a parent transaction that will expire. - parent_address = node.getnewaddress() - parent_txid = node.sendtoaddress(parent_address, 1.0) + parent_txid = self.wallet.send_self_transfer(from_node=node)['txid'] + parent_utxo = self.wallet.get_utxo(txid=parent_txid) + independent_utxo = self.wallet.get_utxo() + + # Ensure the transactions we send to trigger the mempool check spend utxos that are independent of + # the transactions being tested for expiration. + trigger_utxo1 = self.wallet.get_utxo() + trigger_utxo2 = self.wallet.get_utxo() # Set the mocktime to the arrival time of the parent transaction. entry_time = node.getmempoolentry(parent_txid)['time'] node.setmocktime(entry_time) - # Create child transaction spending the parent transaction - vout = find_vout_for_address(node, parent_txid, parent_address) - inputs = [{'txid': parent_txid, 'vout': vout}] - outputs = {node.getnewaddress(): 0.99} - child_raw = node.createrawtransaction(inputs, outputs) - child_signed = node.signrawtransactionwithwallet(child_raw)['hex'] - - # Let half of the timeout elapse and broadcast the child transaction. + # Let half of the timeout elapse and broadcast the child transaction spending the parent transaction. half_expiry_time = entry_time + int(60 * 60 * timeout/2) node.setmocktime(half_expiry_time) - child_txid = node.sendrawtransaction(child_signed) + child_txid = self.wallet.send_self_transfer(from_node=node, utxo_to_spend=parent_utxo)['txid'] + assert_equal(parent_txid, node.getmempoolentry(child_txid)['depends'][0]) self.log.info('Broadcast child transaction after {} hours.'.format( timedelta(seconds=(half_expiry_time-entry_time)))) + # Broadcast another (independent) transaction. + independent_txid = self.wallet.send_self_transfer(from_node=node, utxo_to_spend=independent_utxo)['txid'] + # Let most of the timeout elapse and check that the parent tx is still # in the mempool. nearly_expiry_time = entry_time + 60 * 60 * timeout - 5 node.setmocktime(nearly_expiry_time) - # Expiry of mempool transactions is only checked when a new transaction - # is added to the to the mempool. - node.sendtoaddress(node.getnewaddress(), 1.0) + # Broadcast a transaction as the expiry of transactions in the mempool is only checked + # when a new transaction is added to the mempool. + self.wallet.send_self_transfer(from_node=node, utxo_to_spend=trigger_utxo1) self.log.info('Test parent tx not expired after {} hours.'.format( timedelta(seconds=(nearly_expiry_time-entry_time)))) assert_equal(entry_time, node.getmempoolentry(parent_txid)['time']) @@ -72,9 +78,8 @@ class MempoolExpiryTest(BitcoinTestFramework): # has passed. expiry_time = entry_time + 60 * 60 * timeout + 5 node.setmocktime(expiry_time) - # Expiry of mempool transactions is only checked when a new transaction - # is added to the to the mempool. - node.sendtoaddress(node.getnewaddress(), 1.0) + # Again, broadcast a transaction so the expiry of transactions in the mempool is checked. + self.wallet.send_self_transfer(from_node=node, utxo_to_spend=trigger_utxo2) self.log.info('Test parent tx expiry after {} hours.'.format( timedelta(seconds=(expiry_time-entry_time)))) assert_raises_rpc_error(-5, 'Transaction not in mempool', @@ -85,6 +90,11 @@ class MempoolExpiryTest(BitcoinTestFramework): assert_raises_rpc_error(-5, 'Transaction not in mempool', node.getmempoolentry, child_txid) + # Check that the independent tx is still in the mempool. + self.log.info('Test the independent tx not expired after {} hours.'.format( + timedelta(seconds=(expiry_time-half_expiry_time)))) + assert_equal(half_expiry_time, node.getmempoolentry(independent_txid)['time']) + def run_test(self): self.log.info('Test default mempool expiry timeout of %d hours.' % DEFAULT_MEMPOOL_EXPIRY)