Merge bd13d6b369 into merged_master (Bitcoin PR bitcoin/bitcoin#26656)

This commit is contained in:
Byron Hambly 2025-03-31 10:06:08 +02:00
commit 41f380c8f0
7 changed files with 115 additions and 73 deletions

View file

@ -24,7 +24,7 @@ from test_framework.wallet import MiniWallet
def small_txpuzzle_randfee(
wallet, from_node, conflist, unconflist, amount, min_fee, fee_increment
wallet, from_node, conflist, unconflist, amount, min_fee, fee_increment, batch_reqs
):
"""Create and send a transaction with a random fee using MiniWallet.
@ -59,8 +59,11 @@ def small_txpuzzle_randfee(
tx.vout.append(deepcopy(tx.vout[0]))
tx.vout[1].nValue = int(amount * COIN)
tx.vout.append(CTxOut(int(fee*COIN))) # fee
tx.rehash()
txid = tx.hash
tx_hex = tx.serialize().hex()
txid = from_node.sendrawtransaction(hexstring=tx.serialize().hex(), maxfeerate=0)
batch_reqs.append(from_node.sendrawtransaction.get_request(hexstring=tx_hex, maxfeerate=0))
unconflist.append({"txid": txid, "vout": 0, "value": total_in - amount - fee})
unconflist.append({"txid": txid, "vout": 1, "value": amount})
@ -117,13 +120,12 @@ def check_estimates(node, fees_seen):
check_smart_estimates(node, fees_seen)
def send_tx(wallet, node, utxo, feerate):
"""Broadcast a 1in-1out transaction with a specific input and feerate (sat/vb)."""
return wallet.send_self_transfer(
from_node=node,
def make_tx(wallet, utxo, feerate):
"""Create a 1in-1out transaction with a specific input and feerate (sat/vb)."""
return wallet.create_self_transfer(
utxo_to_spend=utxo,
fee_rate=Decimal(feerate * 1000) / COIN,
)['txid']
)
class EstimateFeeTest(BitcoinTestFramework):
@ -160,6 +162,7 @@ class EstimateFeeTest(BitcoinTestFramework):
random.shuffle(self.confutxo)
# ELEMENTS: make fewer txns since larger: ~236 bytes: 69k/4/234=~73
# Pick a number smaller than that, stingy miner is even stingier
batch_sendtx_reqs = []
for _ in range(random.randrange(55 - 15, 55 + 15)):
from_index = random.randint(1, 2)
(tx_bytes, fee) = small_txpuzzle_randfee(
@ -170,10 +173,13 @@ class EstimateFeeTest(BitcoinTestFramework):
Decimal("0.005"),
min_fee,
min_fee,
batch_sendtx_reqs,
)
tx_kbytes = tx_bytes / 1000.0
self.fees_per_kb.append(float(fee) / tx_kbytes)
self.sync_mempools(wait=10, timeout=240) # Slower to sync than btc
for node in self.nodes:
node.batch(batch_sendtx_reqs)
self.sync_mempools(wait=0.1, timeout=240)
mined = mining_node.getblock(self.generate(mining_node, 1)[0], True)["tx"]
# update which txouts are confirmed
newmem = []
@ -249,14 +255,20 @@ class EstimateFeeTest(BitcoinTestFramework):
assert_greater_than_or_equal(len(utxos), 250)
for _ in range(5):
# Broadcast 45 low fee transactions that will need to be RBF'd
txs = []
for _ in range(45):
u = utxos.pop(0)
txid = send_tx(self.wallet, node, u, low_feerate)
tx = make_tx(self.wallet, u, low_feerate)
utxos_to_respend.append(u)
txids_to_replace.append(txid)
txids_to_replace.append(tx["txid"])
txs.append(tx)
# Broadcast 5 low fee transaction which don't need to
for _ in range(5):
send_tx(self.wallet, node, utxos.pop(0), low_feerate)
tx = make_tx(self.wallet, utxos.pop(0), low_feerate)
txs.append(tx)
batch_send_tx = [node.sendrawtransaction.get_request(tx["hex"]) for tx in txs]
for n in self.nodes:
n.batch(batch_send_tx)
# Mine the transactions on another node
self.sync_mempools(wait=0.1, nodes=[node, miner])
for txid in txids_to_replace:
@ -265,7 +277,12 @@ class EstimateFeeTest(BitcoinTestFramework):
# RBF the low-fee transactions
while len(utxos_to_respend) > 0:
u = utxos_to_respend.pop(0)
send_tx(self.wallet, node, u, high_feerate)
tx = make_tx(self.wallet, u, high_feerate)
node.sendrawtransaction(tx["hex"])
txs.append(tx)
dec_txs = [res["result"] for res in node.batch([node.decoderawtransaction.get_request(tx["hex"]) for tx in txs])]
self.wallet.scan_txs(dec_txs)
# Mine the last replacement txs
self.sync_mempools(wait=0.1, nodes=[node, miner])

View file

@ -1336,7 +1336,7 @@ class TaprootTest(BitcoinTestFramework):
# It is not impossible to fit enough tapscript sigops to hit the old 80k limit without
# busting txin-level limits. We simply have to account for the p2pk outputs in all
# transactions.
extra_output_script = CScript([OP_CHECKSIG]*((MAX_BLOCK_SIGOPS_WEIGHT - sigops_weight) // WITNESS_SCALE_FACTOR))
extra_output_script = CScript(bytes([OP_CHECKSIG]*((MAX_BLOCK_SIGOPS_WEIGHT - sigops_weight) // WITNESS_SCALE_FACTOR)))
if extra_output_script == CScript():
extra_output_script = None ## ELEMENTS: an explicitly empty coinbase scriptpubkey would be rejected with bad-cb-fee

View file

@ -25,7 +25,7 @@ def expect_http_status(expected_http_status, expected_rpc_code,
def test_work_queue_getblock(node, got_exceeded_error):
while not got_exceeded_error:
try:
node.cli('getrpcinfo').send_cli()
node.cli("waitfornewblock", "500").send_cli()
except subprocess.CalledProcessError as e:
assert_equal(e.output, 'error: Server response: Work queue depth exceeded\n')
got_exceeded_error.append(True)

View file

@ -29,6 +29,7 @@ class RPCPackagesTest(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 1
self.setup_clean_chain = True
self.extra_args = [["-whitelist=noban@127.0.0.1"]] # noban speeds up tx relay
def assert_testres_equal(self, package_hex, testres_expected):
"""Shuffle package_hex and assert that the testmempoolaccept result matches testres_expected. This should only

View file

@ -143,6 +143,10 @@ class MiniWallet:
if out['scriptPubKey']['hex'] == self._scriptPubKey.hex():
self._utxos.append(self._create_utxo(txid=tx["txid"], vout=out["n"], value=out["value"], height=0))
def scan_txs(self, txs):
for tx in txs:
self.scan_tx(tx)
def sign_tx(self, tx, fixed_length=True):
"""Sign tx that has been created by MiniWallet in P2PK mode"""
assert_equal(self._mode, MiniWalletMode.RAW_P2PK)

View file

@ -120,57 +120,85 @@ BASE_SCRIPTS = [
'wallet_elements_regression_1259.py --legacy-wallet',
'wallet_elements_21million.py',
# Longest test should go first, to favor running tests in parallel
'wallet_hd.py --legacy-wallet',
'wallet_hd.py --descriptors',
'wallet_backup.py --legacy-wallet',
'wallet_backup.py --descriptors',
# vv Tests less than 5m vv
# ELEMENTS: no longpolling
#'mining_getblocktemplate_longpoll.py',
'feature_maxuploadtarget.py',
# 'feature_fee_estimation.py', # ELEMENTS FIXME: in extended tests
'feature_taproot.py',
'feature_block.py',
'wallet_elements_regression_1263.py',
# vv Tests less than 2m vv
# ELEMENTS: no longpolling
# 'mining_getblocktemplate_longpoll.py',
'p2p_segwit.py',
'feature_maxuploadtarget.py',
'mempool_updatefromblock.py',
'mempool_persist.py --descriptors',
# vv Tests less than 60s vv
'rpc_psbt.py --legacy-wallet',
'rpc_psbt.py --descriptors',
'wallet_fundrawtransaction.py --legacy-wallet',
'wallet_fundrawtransaction.py --descriptors',
'p2p_compactblocks.py',
'p2p_compactblocks_blocksonly.py',
'wallet_bumpfee.py --legacy-wallet',
'wallet_bumpfee.py --descriptors',
'wallet_import_rescan.py --legacy-wallet',
'wallet_backup.py --legacy-wallet',
'wallet_backup.py --descriptors',
'feature_segwit.py --legacy-wallet',
'feature_segwit.py --descriptors',
# vv Tests less than 2m vv
'p2p_tx_download.py',
'wallet_avoidreuse.py --legacy-wallet',
'wallet_avoidreuse.py --descriptors',
'feature_abortnode.py',
'wallet_address_types.py --legacy-wallet',
'wallet_address_types.py --descriptors',
'wallet_basic.py --legacy-wallet',
'wallet_basic.py --descriptors',
'wallet_labels.py --legacy-wallet',
'wallet_labels.py --descriptors',
'p2p_segwit.py',
'feature_maxtipage.py',
'wallet_multiwallet.py --legacy-wallet',
'wallet_multiwallet.py --descriptors',
'wallet_multiwallet.py --usecli',
'p2p_dns_seeds.py',
'wallet_groups.py --legacy-wallet',
'wallet_groups.py --descriptors',
'p2p_blockfilters.py',
'feature_assumevalid.py',
'wallet_taproot.py --descriptors',
'feature_bip68_sequence.py',
'rpc_packages.py',
'rpc_bind.py --ipv4',
'rpc_bind.py --ipv6',
'rpc_bind.py --nonloopback',
'p2p_headers_sync_with_minchainwork.py',
'p2p_feefilter.py',
# ELEMENTS: no transitions in Elements
# 'feature_csv_activation.py',
'p2p_sendheaders.py',
'wallet_listtransactions.py --legacy-wallet',
'wallet_listtransactions.py --descriptors',
# vv Tests less than 30s vv
# ELEMENTS: needs to be fixed
# 'p2p_invalid_messages.py',
'rpc_createmultisig.py',
'p2p_timeouts.py',
'p2p_tx_download.py',
'mempool_updatefromblock.py',
'wallet_dump.py --legacy-wallet',
'feature_taproot.py',
'rpc_signer.py',
'wallet_signer.py --descriptors',
'feature_taphash_pegins_issuances.py',
'feature_tapscript_opcodes.py',
# vv Tests less than 60s vv
'p2p_sendheaders.py',
'wallet_importmulti.py --legacy-wallet',
'mempool_limit.py',
'rpc_txoutproof.py',
'wallet_listreceivedby.py --legacy-wallet',
'wallet_listreceivedby.py --descriptors',
'wallet_abandonconflict.py --legacy-wallet',
'p2p_dns_seeds.py',
'wallet_abandonconflict.py --descriptors',
# ELEMENTS: no transitions in Elements
#'feature_csv_activation.py',
'wallet_address_types.py --legacy-wallet',
'wallet_address_types.py --descriptors',
'feature_bip68_sequence.py',
'p2p_feefilter.py',
'rpc_packages.py',
'feature_reindex.py',
'feature_abortnode.py',
# vv Tests less than 30s vv
'wallet_labels.py --legacy-wallet',
'wallet_labels.py --descriptors',
'p2p_compactblocks.py',
'p2p_compactblocks_blocksonly.py',
'wallet_hd.py --legacy-wallet',
'wallet_hd.py --descriptors',
'wallet_keypool_topup.py --legacy-wallet',
'wallet_keypool_topup.py --descriptors',
'wallet_fast_rescan.py --descriptors',
@ -191,23 +219,15 @@ BASE_SCRIPTS = [
'rpc_misc.py',
'interface_rest.py',
'mempool_spend_coinbase.py',
'wallet_avoidreuse.py --legacy-wallet',
'wallet_avoidreuse.py --descriptors',
'wallet_avoid_mixing_output_types.py --descriptors',
'mempool_reorg.py',
# ELEMENTS: discounted Confidential Transactions
'feature_discount_ct.py',
'feature_discount_ct_ordering.py',
'mempool_persist.py --descriptors',
'p2p_block_sync.py',
'wallet_multiwallet.py --legacy-wallet',
'wallet_multiwallet.py --descriptors',
'wallet_multiwallet.py --usecli',
'wallet_createwallet.py --legacy-wallet',
'wallet_createwallet.py --usecli',
'wallet_createwallet.py --descriptors',
'wallet_listtransactions.py --legacy-wallet',
'wallet_listtransactions.py --descriptors',
'wallet_watchonly.py --legacy-wallet',
'wallet_watchonly.py --usecli --legacy-wallet',
'wallet_reorgsrestore.py',
@ -217,8 +237,6 @@ BASE_SCRIPTS = [
'interface_usdt_net.py',
'interface_usdt_utxocache.py',
'interface_usdt_validation.py',
'rpc_psbt.py --legacy-wallet',
'rpc_psbt.py --descriptors',
'rpc_users.py',
'rpc_whitelist.py',
'feature_proxy.py',
@ -226,10 +244,7 @@ BASE_SCRIPTS = [
'wallet_signrawtransactionwithwallet.py --legacy-wallet',
'wallet_signrawtransactionwithwallet.py --descriptors',
'rpc_signrawtransactionwithkey.py',
'p2p_headers_sync_with_minchainwork.py',
'rpc_rawtransaction.py --legacy-wallet',
'wallet_groups.py --legacy-wallet',
'wallet_groups.py --descriptors',
'wallet_transactiontime_rescan.py --descriptors',
'wallet_transactiontime_rescan.py --legacy-wallet',
'p2p_addrv2_relay.py',
@ -248,7 +263,6 @@ BASE_SCRIPTS = [
'wallet_keypool.py --descriptors',
'wallet_descriptor.py --descriptors',
'wallet_miniscript.py --descriptors',
'feature_maxtipage.py',
'p2p_nobloomfilter_messages.py',
'p2p_filter.py',
'rpc_setban.py',
@ -258,10 +272,7 @@ BASE_SCRIPTS = [
'p2p_invalid_block.py',
'feature_elements_taproot_activation.py',
'feature_elements_simplicity_activation.py',
# ELEMENTS: needs to be fixed
#'p2p_invalid_messages.py',
'p2p_invalid_tx.py',
'feature_assumevalid.py',
'example_test.py',
'wallet_txn_doublespend.py --legacy-wallet',
'wallet_multisig_descriptor_psbt.py --descriptors',
@ -279,7 +290,6 @@ BASE_SCRIPTS = [
'feature_rbf.py',
'mempool_packages.py',
'mempool_package_onemore.py',
'rpc_createmultisig.py',
'mempool_package_limits.py',
# ELEMENTS: no versionbits in use
#'feature_versionbits_warning.py',
@ -297,19 +307,13 @@ BASE_SCRIPTS = [
'feature_nulldummy.py',
'mempool_accept.py',
'mempool_expiry.py',
'wallet_import_rescan.py --legacy-wallet',
'wallet_import_with_label.py --legacy-wallet',
'wallet_importdescriptors.py --descriptors',
# ELEMENTS: need to point past versions at our own release server
#'wallet_upgradewallet.py --legacy-wallet',
'rpc_bind.py --ipv4',
'rpc_bind.py --ipv6',
'rpc_bind.py --nonloopback',
'wallet_crosschain.py',
'mining_basic.py',
'feature_signet.py',
'wallet_bumpfee.py --legacy-wallet',
'wallet_bumpfee.py --descriptors',
'wallet_implicitsegwit.py --legacy-wallet',
'rpc_named_arguments.py',
'feature_startupnotify.py',
@ -340,7 +344,6 @@ BASE_SCRIPTS = [
'wallet_sendall.py --legacy-wallet',
'wallet_sendall.py --descriptors',
'wallet_create_tx.py --descriptors',
'wallet_taproot.py --descriptors',
'wallet_inactive_hdchains.py --legacy-wallet',
'p2p_fingerprint.py',
'feature_uacomment.py',
@ -353,7 +356,6 @@ BASE_SCRIPTS = [
'p2p_add_connections.py',
'feature_bind_port_discover.py',
'p2p_unrequested_blocks.py',
'p2p_blockfilters.py',
'p2p_message_capture.py',
'feature_includeconf.py',
'feature_addrman.py',

View file

@ -180,7 +180,16 @@ class ImportRescanTest(BitcoinTestFramework):
# Create one transaction on node 0 with a unique amount for
# each possible type of wallet import RPC.
last_variants = []
for i, variant in enumerate(IMPORT_VARIANTS):
if i % 10 == 0:
blockhash = self.generate(self.nodes[0], 1)[0]
conf_height = self.nodes[0].getblockcount()
timestamp = self.nodes[0].getblockheader(blockhash)["time"]
for var in last_variants:
var.confirmation_height = conf_height
var.timestamp = timestamp
last_variants.clear()
variant.label = "label {} {}".format(i, variant)
variant.address = self.nodes[1].getaddressinfo(self.nodes[1].getnewaddress(
label=variant.label,
@ -189,9 +198,15 @@ class ImportRescanTest(BitcoinTestFramework):
variant.key = self.nodes[1].dumpprivkey(variant.address["address"])
variant.initial_amount = get_rand_amount()
variant.initial_txid = self.nodes[0].sendtoaddress(variant.address["address"], variant.initial_amount)
self.generate(self.nodes[0], 1) # Generate one block for each send
variant.confirmation_height = self.nodes[0].getblockcount()
variant.timestamp = self.nodes[0].getblockheader(self.nodes[0].getbestblockhash())["time"]
last_variants.append(variant)
blockhash = self.generate(self.nodes[0], 1)[0]
conf_height = self.nodes[0].getblockcount()
timestamp = self.nodes[0].getblockheader(blockhash)["time"]
for var in last_variants:
var.confirmation_height = conf_height
var.timestamp = timestamp
last_variants.clear()
# Generate a block further in the future (past the rescan window).
assert_equal(self.nodes[0].getrawmempool(), [])
@ -218,11 +233,14 @@ class ImportRescanTest(BitcoinTestFramework):
variant.check()
# Create new transactions sending to each address.
for variant in IMPORT_VARIANTS:
for i, variant in enumerate(IMPORT_VARIANTS):
if i % 10 == 0:
blockhash = self.generate(self.nodes[0], 1)[0]
conf_height = self.nodes[0].getblockcount() + 1
variant.sent_amount = get_rand_amount()
variant.sent_txid = self.nodes[0].sendtoaddress(variant.address["address"], variant.sent_amount)
self.generate(self.nodes[0], 1) # Generate one block for each send
variant.confirmation_height = self.nodes[0].getblockcount()
variant.confirmation_height = conf_height
self.generate(self.nodes[0], 1)
assert_equal(self.nodes[0].getrawmempool(), [])
self.sync_all()