mirror of
https://github.com/bitcoin/bitcoin.git
synced 2025-01-10 20:03:34 -03:00
Merge bitcoin/bitcoin#25087: test: use MiniWallet for feature_dbcrash.py
1da5e45725
test: use MiniWallet for feature_dbcrash.py (Sebastian Falbesoner) Pull request description: This PR enables one more of the non-wallet functional tests (feature_dbcrash.py) to be run even with the Bitcoin Code wallet by using the MiniWallet instead, as proposed in https://github.com/bitcoin/bitcoin/issues/20078. ACKs for top commit: laanwj: Code review ACK1da5e45725
brunoerg: crACK1da5e45725
Tree-SHA512: 75ee9a32fd1451254004797d695d18032bd0fcb66ebd88cf737e147e43812525f6e884ec05fcc4f76f566dc71174c8ed7347bcdce16567db6511746ae64cead0
This commit is contained in:
commit
9cc010f5a9
2 changed files with 34 additions and 28 deletions
|
@ -30,17 +30,17 @@ import http.client
|
|||
import random
|
||||
import time
|
||||
|
||||
from test_framework.blocktools import COINBASE_MATURITY
|
||||
from test_framework.messages import (
|
||||
COIN,
|
||||
COutPoint,
|
||||
CTransaction,
|
||||
CTxIn,
|
||||
CTxOut,
|
||||
)
|
||||
from test_framework.test_framework import BitcoinTestFramework
|
||||
from test_framework.util import (
|
||||
assert_equal,
|
||||
create_confirmed_utxos,
|
||||
)
|
||||
from test_framework.wallet import (
|
||||
MiniWallet,
|
||||
getnewdestination,
|
||||
)
|
||||
|
||||
|
||||
|
@ -66,13 +66,9 @@ class ChainstateWriteCrashTest(BitcoinTestFramework):
|
|||
self.node3_args = ["-blockmaxweight=4000000", "-acceptnonstdtxn"]
|
||||
self.extra_args = [self.node0_args, self.node1_args, self.node2_args, self.node3_args]
|
||||
|
||||
def skip_test_if_missing_module(self):
|
||||
self.skip_if_no_wallet()
|
||||
|
||||
def setup_network(self):
|
||||
self.add_nodes(self.num_nodes, extra_args=self.extra_args)
|
||||
self.start_nodes()
|
||||
self.import_deterministic_coinbase_privkeys()
|
||||
# Leave them unconnected, we'll use submitblock directly in this test
|
||||
|
||||
def restart_node(self, node_index, expected_tip):
|
||||
|
@ -190,34 +186,36 @@ class ChainstateWriteCrashTest(BitcoinTestFramework):
|
|||
num_transactions = 0
|
||||
random.shuffle(utxo_list)
|
||||
while len(utxo_list) >= 2 and num_transactions < count:
|
||||
tx = CTransaction()
|
||||
input_amount = 0
|
||||
for _ in range(2):
|
||||
utxo = utxo_list.pop()
|
||||
tx.vin.append(CTxIn(COutPoint(int(utxo['txid'], 16), utxo['vout'])))
|
||||
input_amount += int(utxo['amount'] * COIN)
|
||||
output_amount = (input_amount - FEE) // 3
|
||||
|
||||
if output_amount <= 0:
|
||||
utxos_to_spend = [utxo_list.pop() for _ in range(2)]
|
||||
input_amount = int(sum([utxo['value'] for utxo in utxos_to_spend]) * COIN)
|
||||
if input_amount < FEE:
|
||||
# Sanity check -- if we chose inputs that are too small, skip
|
||||
continue
|
||||
|
||||
for _ in range(3):
|
||||
tx.vout.append(CTxOut(output_amount, bytes.fromhex(utxo['scriptPubKey'])))
|
||||
tx = self.wallet.create_self_transfer_multi(
|
||||
from_node=node,
|
||||
utxos_to_spend=utxos_to_spend,
|
||||
num_outputs=3,
|
||||
fee_per_output=FEE // 3)
|
||||
|
||||
# Sign and send the transaction to get into the mempool
|
||||
tx_signed_hex = node.signrawtransactionwithwallet(tx.serialize().hex())['hex']
|
||||
node.sendrawtransaction(tx_signed_hex)
|
||||
# Send the transaction to get into the mempool (skip fee-checks to run faster)
|
||||
node.sendrawtransaction(hexstring=tx.serialize().hex(), maxfeerate=0)
|
||||
num_transactions += 1
|
||||
|
||||
def run_test(self):
|
||||
self.wallet = MiniWallet(self.nodes[3])
|
||||
self.wallet.rescan_utxos()
|
||||
initial_height = self.nodes[3].getblockcount()
|
||||
self.generate(self.nodes[3], COINBASE_MATURITY, sync_fun=self.no_op)
|
||||
|
||||
# Track test coverage statistics
|
||||
self.restart_counts = [0, 0, 0] # Track the restarts for nodes 0-2
|
||||
self.crashed_on_restart = 0 # Track count of crashes during recovery
|
||||
|
||||
# Start by creating a lot of utxos on node3
|
||||
initial_height = self.nodes[3].getblockcount()
|
||||
utxo_list = create_confirmed_utxos(self, self.nodes[3].getnetworkinfo()['relayfee'], self.nodes[3], 5000, sync_fun=self.no_op)
|
||||
utxo_list = self.wallet.send_self_transfer_multi(from_node=self.nodes[3], num_outputs=5000)['new_utxos']
|
||||
self.generate(self.nodes[3], 1, sync_fun=self.no_op)
|
||||
assert_equal(len(self.nodes[3].getrawmempool()), 0)
|
||||
self.log.info(f"Prepped {len(utxo_list)} utxo entries")
|
||||
|
||||
# Sync these blocks with the other nodes
|
||||
|
@ -257,13 +255,14 @@ class ChainstateWriteCrashTest(BitcoinTestFramework):
|
|||
self.nodes[3],
|
||||
nblocks=min(10, current_height + 1 - self.nodes[3].getblockcount()),
|
||||
# new address to avoid mining a block that has just been invalidated
|
||||
address=self.nodes[3].getnewaddress(),
|
||||
address=getnewdestination()[2],
|
||||
sync_fun=self.no_op,
|
||||
))
|
||||
self.log.debug(f"Syncing {len(block_hashes)} new blocks...")
|
||||
self.sync_node3blocks(block_hashes)
|
||||
utxo_list = self.nodes[3].listunspent()
|
||||
self.log.debug(f"Node3 utxo count: {len(utxo_list)}")
|
||||
self.wallet.rescan_utxos()
|
||||
utxo_list = self.wallet.get_utxos()
|
||||
self.log.debug(f"MiniWallet utxo count: {len(utxo_list)}")
|
||||
|
||||
# Check that the utxo hashes agree with node3
|
||||
# Useful side effect: each utxo cache gets flushed here, so that we
|
||||
|
|
|
@ -167,6 +167,13 @@ class MiniWallet:
|
|||
else:
|
||||
return self._utxos[index]
|
||||
|
||||
def get_utxos(self, *, mark_as_spent=True):
|
||||
"""Returns the list of all utxos and optionally mark them as spent"""
|
||||
utxos = deepcopy(self._utxos)
|
||||
if mark_as_spent:
|
||||
self._utxos = []
|
||||
return utxos
|
||||
|
||||
def send_self_transfer(self, **kwargs):
|
||||
"""Create and send a tx with the specified fee_rate. Fee may be exact or at most one satoshi higher than needed."""
|
||||
tx = self.create_self_transfer(**kwargs)
|
||||
|
|
Loading…
Reference in a new issue