diff --git a/test/functional/feature_fee_estimation.py b/test/functional/feature_fee_estimation.py index 0357a6f2815..619f3c08eae 100755 --- a/test/functional/feature_fee_estimation.py +++ b/test/functional/feature_fee_estimation.py @@ -23,7 +23,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. @@ -57,8 +57,11 @@ def small_txpuzzle_randfee( tx.vout[0].nValue = int((total_in - amount - fee) * COIN) tx.vout.append(deepcopy(tx.vout[0])) tx.vout[1].nValue = int(amount * COIN) + 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}) @@ -115,13 +118,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): @@ -156,6 +158,7 @@ class EstimateFeeTest(BitcoinTestFramework): # resorting to tx's that depend on the mempool when those run out for _ in range(numblocks): random.shuffle(self.confutxo) + batch_sendtx_reqs = [] for _ in range(random.randrange(100 - 50, 100 + 50)): from_index = random.randint(1, 2) (tx_bytes, fee) = small_txpuzzle_randfee( @@ -166,9 +169,12 @@ 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) + for node in self.nodes: + node.batch(batch_sendtx_reqs) self.sync_mempools(wait=0.1) mined = mining_node.getblock(self.generate(mining_node, 1)[0], True)["tx"] # update which txouts are confirmed @@ -245,14 +251,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: @@ -261,7 +273,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]) diff --git a/test/functional/feature_taproot.py b/test/functional/feature_taproot.py index dbe51f8f548..f6f6f3f78ba 100755 --- a/test/functional/feature_taproot.py +++ b/test/functional/feature_taproot.py @@ -1292,7 +1292,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))) coinbase_tx = create_coinbase(self.lastblockheight + 1, pubkey=cb_pubkey, extra_output_script=extra_output_script, fees=fees) block = create_block(self.tip, coinbase_tx, self.lastblocktime + 1, txlist=txs) diff --git a/test/functional/interface_rpc.py b/test/functional/interface_rpc.py index 48082f3a17b..3389746635d 100755 --- a/test/functional/interface_rpc.py +++ b/test/functional/interface_rpc.py @@ -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) diff --git a/test/functional/rpc_packages.py b/test/functional/rpc_packages.py index a512a6b675f..df11750438d 100755 --- a/test/functional/rpc_packages.py +++ b/test/functional/rpc_packages.py @@ -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 diff --git a/test/functional/test_framework/wallet.py b/test/functional/test_framework/wallet.py index a94b9fe3fdc..ecde329a1e1 100644 --- a/test/functional/test_framework/wallet.py +++ b/test/functional/test_framework/wallet.py @@ -141,6 +141,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) diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py index ed547b68a8b..00e2d92f5f3 100755 --- a/test/functional/test_runner.py +++ b/test/functional/test_runner.py @@ -91,56 +91,81 @@ EXTENDED_SCRIPTS = [ BASE_SCRIPTS = [ # Scripts that are run by default. # 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 - 'mining_getblocktemplate_longpoll.py', - 'feature_maxuploadtarget.py', + 'feature_fee_estimation.py', + 'feature_taproot.py', 'feature_block.py', + # vv Tests less than 2m vv + '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', + 'feature_csv_activation.py', + 'p2p_sendheaders.py', + 'wallet_listtransactions.py --legacy-wallet', + 'wallet_listtransactions.py --descriptors', + # vv Tests less than 30s vv + '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', - # 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', - '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', - 'feature_fee_estimation.py', 'interface_zmq.py', 'rpc_invalid_address_message.py', 'interface_bitcoin_cli.py --legacy-wallet', @@ -158,20 +183,12 @@ 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', - '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', @@ -181,8 +198,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', @@ -190,13 +205,10 @@ 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_transactiontime_rescan.py --descriptors', 'wallet_transactiontime_rescan.py --legacy-wallet', 'p2p_addrv2_relay.py', - 'wallet_groups.py --descriptors', 'p2p_compactblocks_hb.py', 'p2p_disconnect_ban.py', 'rpc_decodescript.py', @@ -212,7 +224,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', @@ -220,9 +231,7 @@ BASE_SCRIPTS = [ 'mining_prioritisetransaction.py', 'p2p_invalid_locator.py', 'p2p_invalid_block.py', - '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', @@ -238,7 +247,6 @@ BASE_SCRIPTS = [ 'feature_rbf.py', 'mempool_packages.py', 'mempool_package_onemore.py', - 'rpc_createmultisig.py', 'mempool_package_limits.py', 'feature_versionbits_warning.py', 'rpc_preciousblock.py', @@ -255,18 +263,12 @@ 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', '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', @@ -297,7 +299,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', @@ -310,7 +311,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', diff --git a/test/functional/wallet_import_rescan.py b/test/functional/wallet_import_rescan.py index 64f8f2eb6e0..4dc39e83f80 100755 --- a/test/functional/wallet_import_rescan.py +++ b/test/functional/wallet_import_rescan.py @@ -179,7 +179,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, @@ -188,9 +197,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(), []) @@ -217,11 +232,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()