aboutsummaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rw-r--r--test/README.md2
-rwxr-xr-xtest/functional/feature_dbcrash.py55
-rwxr-xr-xtest/functional/feature_index_prune.py6
-rwxr-xr-xtest/functional/feature_minchainwork.py29
-rwxr-xr-xtest/functional/feature_pruning.py2
-rwxr-xr-xtest/functional/mempool_accept.py4
-rwxr-xr-xtest/functional/mempool_packages.py6
-rwxr-xr-xtest/functional/p2p_block_sync.py37
-rwxr-xr-xtest/functional/rpc_createmultisig.py11
-rwxr-xr-xtest/functional/rpc_getblockfrompeer.py13
-rwxr-xr-xtest/functional/rpc_mempool_entry_fee_fields_deprecation.py67
-rwxr-xr-xtest/functional/rpc_mempool_info.py102
-rwxr-xr-xtest/functional/rpc_rawtransaction.py165
-rwxr-xr-xtest/functional/rpc_signrawtransaction.py51
-rw-r--r--test/functional/test_framework/wallet.py11
-rwxr-xr-xtest/functional/test_runner.py4
-rw-r--r--test/lint/README.md2
-rwxr-xr-xtest/lint/all-lint.py (renamed from test/lint/lint-all.py)11
-rwxr-xr-xtest/lint/lint-logs.py4
-rw-r--r--test/lint/spelling.ignore-words.txt1
20 files changed, 346 insertions, 237 deletions
diff --git a/test/README.md b/test/README.md
index 0d9b9fb89b..6ca7cc0016 100644
--- a/test/README.md
+++ b/test/README.md
@@ -327,7 +327,7 @@ test/lint/lint-files.py
You can run all the shell-based lint tests by running:
```
-test/lint/lint-all.py
+test/lint/all-lint.py
```
# Writing functional tests
diff --git a/test/functional/feature_dbcrash.py b/test/functional/feature_dbcrash.py
index 3e60efbb3c..a3a5e9e27d 100755
--- a/test/functional/feature_dbcrash.py
+++ b/test/functional/feature_dbcrash.py
@@ -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
diff --git a/test/functional/feature_index_prune.py b/test/functional/feature_index_prune.py
index 3ee6a8036c..bc85e43a57 100755
--- a/test/functional/feature_index_prune.py
+++ b/test/functional/feature_index_prune.py
@@ -73,7 +73,7 @@ class FeatureIndexPruneTest(BitcoinTestFramework):
pruneheight_new = node.pruneblockchain(400)
# the prune heights used here and below are magic numbers that are determined by the
# thresholds at which block files wrap, so they depend on disk serialization and default block file size.
- assert_equal(pruneheight_new, 249)
+ assert_equal(pruneheight_new, 248)
self.log.info("check if we can access the tips blockfilter and coinstats when we have pruned some blocks")
tip = self.nodes[0].getbestblockhash()
@@ -108,7 +108,7 @@ class FeatureIndexPruneTest(BitcoinTestFramework):
self.log.info("prune exactly up to the indices best blocks while the indices are disabled")
for i in range(3):
pruneheight_2 = self.nodes[i].pruneblockchain(1000)
- assert_equal(pruneheight_2, 751)
+ assert_equal(pruneheight_2, 750)
# Restart the nodes again with the indices activated
self.restart_node(i, extra_args=self.extra_args[i])
@@ -142,7 +142,7 @@ class FeatureIndexPruneTest(BitcoinTestFramework):
for node in self.nodes[:2]:
with node.assert_debug_log(['limited pruning to height 2489']):
pruneheight_new = node.pruneblockchain(2500)
- assert_equal(pruneheight_new, 2006)
+ assert_equal(pruneheight_new, 2005)
self.log.info("ensure that prune locks don't prevent indices from failing in a reorg scenario")
with self.nodes[0].assert_debug_log(['basic block filter index prune lock moved back to 2480']):
diff --git a/test/functional/feature_minchainwork.py b/test/functional/feature_minchainwork.py
index 489a729cfc..fa10855a98 100755
--- a/test/functional/feature_minchainwork.py
+++ b/test/functional/feature_minchainwork.py
@@ -17,6 +17,7 @@ only succeeds past a given node once its nMinimumChainWork has been exceeded.
import time
+from test_framework.p2p import P2PInterface, msg_getheaders
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_equal
@@ -41,6 +42,9 @@ class MinimumChainWorkTest(BitcoinTestFramework):
for i in range(self.num_nodes-1):
self.connect_nodes(i+1, i)
+ # Set clock of node2 2 days ahead, to keep it in IBD during this test.
+ self.nodes[2].setmocktime(int(time.time()) + 48*60*60)
+
def run_test(self):
# Start building a chain on node0. node2 shouldn't be able to sync until node1's
# minchainwork is exceeded
@@ -71,6 +75,15 @@ class MinimumChainWorkTest(BitcoinTestFramework):
assert self.nodes[1].getbestblockhash() != self.nodes[0].getbestblockhash()
assert_equal(self.nodes[2].getblockcount(), starting_blockcount)
+ self.log.info("Check that getheaders requests to node2 are ignored")
+ peer = self.nodes[2].add_p2p_connection(P2PInterface())
+ msg = msg_getheaders()
+ msg.locator.vHave = [int(self.nodes[2].getbestblockhash(), 16)]
+ msg.hashstop = 0
+ peer.send_and_ping(msg)
+ time.sleep(5)
+ assert "headers" not in peer.last_message
+
self.log.info("Generating one more block")
self.generate(self.nodes[0], 1)
@@ -85,5 +98,21 @@ class MinimumChainWorkTest(BitcoinTestFramework):
self.sync_all()
self.log.info(f"Blockcounts: {[n.getblockcount() for n in self.nodes]}")
+ self.log.info("Test that getheaders requests to node2 are not ignored")
+ peer.send_and_ping(msg)
+ assert "headers" in peer.last_message
+
+ # Verify that node2 is in fact still in IBD (otherwise this test may
+ # not be exercising the logic we want!)
+ assert_equal(self.nodes[2].getblockchaininfo()['initialblockdownload'], True)
+
+ self.log.info("Test -minimumchainwork with a non-hex value")
+ self.stop_node(0)
+ self.nodes[0].assert_start_raises_init_error(
+ ["-minimumchainwork=test"],
+ expected_msg='Error: Invalid non-hex (test) minimum chain work value specified',
+ )
+
+
if __name__ == '__main__':
MinimumChainWorkTest().main()
diff --git a/test/functional/feature_pruning.py b/test/functional/feature_pruning.py
index 77524e85a3..7dbeccbc09 100755
--- a/test/functional/feature_pruning.py
+++ b/test/functional/feature_pruning.py
@@ -291,7 +291,7 @@ class PruneTest(BitcoinTestFramework):
def prune(index):
ret = node.pruneblockchain(height=height(index))
- assert_equal(ret, node.getblockchaininfo()['pruneheight'])
+ assert_equal(ret + 1, node.getblockchaininfo()['pruneheight'])
def has_block(index):
return os.path.isfile(os.path.join(self.nodes[node_number].datadir, self.chain, "blocks", f"blk{index:05}.dat"))
diff --git a/test/functional/mempool_accept.py b/test/functional/mempool_accept.py
index d3961e753d..85464b8d0d 100755
--- a/test/functional/mempool_accept.py
+++ b/test/functional/mempool_accept.py
@@ -76,7 +76,7 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
tx.vout[0].nValue = int(0.3 * COIN)
tx.vout[1].nValue = int(49 * COIN)
raw_tx_in_block = tx.serialize().hex()
- txid_in_block = self.wallet.sendrawtransaction(from_node=node, tx_hex=raw_tx_in_block, maxfeerate=0)
+ txid_in_block = self.wallet.sendrawtransaction(from_node=node, tx_hex=raw_tx_in_block)
self.generate(node, 1)
self.mempool_size = 0
self.check_mempool_result(
@@ -166,7 +166,7 @@ class MempoolAcceptanceTest(BitcoinTestFramework):
tx.vin[1].prevout = COutPoint(hash=int(txid_1, 16), n=0)
tx.vout[0].nValue = int(0.1 * COIN)
raw_tx_spend_both = tx.serialize().hex()
- txid_spend_both = self.wallet.sendrawtransaction(from_node=node, tx_hex=raw_tx_spend_both, maxfeerate=0)
+ txid_spend_both = self.wallet.sendrawtransaction(from_node=node, tx_hex=raw_tx_spend_both)
self.generate(node, 1)
self.mempool_size = 0
# Now see if we can add the coins back to the utxo set by sending the exact txs again
diff --git a/test/functional/mempool_packages.py b/test/functional/mempool_packages.py
index 068fdc0b65..a2a2caf324 100755
--- a/test/functional/mempool_packages.py
+++ b/test/functional/mempool_packages.py
@@ -100,6 +100,12 @@ class MempoolPackagesTest(BitcoinTestFramework):
entry = self.nodes[0].getmempoolentry(x)
assert_equal(entry, mempool[x])
+ # Check that gettxspendingprevout is consistent with getrawmempool
+ witnesstx = self.nodes[0].gettransaction(txid=x, verbose=True)['decoded']
+ for tx_in in witnesstx["vin"]:
+ spending_result = self.nodes[0].gettxspendingprevout([ {'txid' : tx_in["txid"], 'vout' : tx_in["vout"]} ])
+ assert_equal(spending_result, [ {'txid' : tx_in["txid"], 'vout' : tx_in["vout"], 'spendingtxid' : x} ])
+
# Check that the descendant calculations are correct
assert_equal(entry['descendantcount'], descendant_count)
descendant_fees += entry['fees']['base']
diff --git a/test/functional/p2p_block_sync.py b/test/functional/p2p_block_sync.py
new file mode 100755
index 0000000000..d821edc1b1
--- /dev/null
+++ b/test/functional/p2p_block_sync.py
@@ -0,0 +1,37 @@
+#!/usr/bin/env python3
+# Copyright (c) 2022 The Bitcoin Core developers
+# Distributed under the MIT software license, see the accompanying
+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+"""Test block download
+
+Ensure that even in IBD, we'll eventually sync chain from inbound peers
+(whether we have only inbound peers or both inbound and outbound peers).
+"""
+
+from test_framework.test_framework import BitcoinTestFramework
+
+class BlockSyncTest(BitcoinTestFramework):
+
+ def set_test_params(self):
+ self.setup_clean_chain = True
+ self.num_nodes = 3
+
+ def setup_network(self):
+ self.setup_nodes()
+ # Construct a network:
+ # node0 -> node1 -> node2
+ # So node1 has both an inbound and outbound peer.
+ # In our test, we will mine a block on node0, and ensure that it makes
+ # to to both node1 and node2.
+ self.connect_nodes(0, 1)
+ self.connect_nodes(1, 2)
+
+ def run_test(self):
+ self.log.info("Setup network: node0->node1->node2")
+ self.log.info("Mining one block on node0 and verify all nodes sync")
+ self.generate(self.nodes[0], 1)
+ self.log.info("Success!")
+
+
+if __name__ == '__main__':
+ BlockSyncTest().main()
diff --git a/test/functional/rpc_createmultisig.py b/test/functional/rpc_createmultisig.py
index 1695acaaa8..716ee8f7ef 100755
--- a/test/functional/rpc_createmultisig.py
+++ b/test/functional/rpc_createmultisig.py
@@ -91,15 +91,17 @@ class RpcCreateMultiSigTest(BitcoinTestFramework):
assert 'warnings' not in result
# Generate addresses with the segwit types. These should all make legacy addresses
+ err_msg = ["Unable to make chosen address type, please ensure no uncompressed public keys are present."]
+
for addr_type in ['bech32', 'p2sh-segwit']:
- result = self.nodes[0].createmultisig(2, keys, addr_type)
+ result = self.nodes[0].createmultisig(nrequired=2, keys=keys, address_type=addr_type)
assert_equal(legacy_addr, result['address'])
- assert_equal(result['warnings'], ["Unable to make chosen address type, please ensure no uncompressed public keys are present."])
+ assert_equal(result['warnings'], err_msg)
if self.is_bdb_compiled():
- result = wmulti0.addmultisigaddress(2, keys, '', addr_type)
+ result = wmulti0.addmultisigaddress(nrequired=2, keys=keys, address_type=addr_type)
assert_equal(legacy_addr, result['address'])
- assert_equal(result['warnings'], ["Unable to make chosen address type, please ensure no uncompressed public keys are present."])
+ assert_equal(result['warnings'], err_msg)
self.log.info('Testing sortedmulti descriptors with BIP 67 test vectors')
with open(os.path.join(os.path.dirname(os.path.realpath(__file__)), 'data/rpc_bip67.json'), encoding='utf-8') as f:
@@ -173,6 +175,7 @@ class RpcCreateMultiSigTest(BitcoinTestFramework):
desc = descsum_create(desc)
msig = node2.createmultisig(self.nsigs, self.pub, self.output_type)
+ assert 'warnings' not in msig
madd = msig["address"]
mredeem = msig["redeemScript"]
assert_equal(desc, msig['descriptor'])
diff --git a/test/functional/rpc_getblockfrompeer.py b/test/functional/rpc_getblockfrompeer.py
index b65322d920..a7628b5591 100755
--- a/test/functional/rpc_getblockfrompeer.py
+++ b/test/functional/rpc_getblockfrompeer.py
@@ -5,6 +5,11 @@
"""Test the getblockfrompeer RPC."""
from test_framework.authproxy import JSONRPCException
+from test_framework.messages import NODE_WITNESS
+from test_framework.p2p import (
+ P2P_SERVICES,
+ P2PInterface,
+)
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
assert_equal,
@@ -58,6 +63,13 @@ class GetBlockFromPeerTest(BitcoinTestFramework):
self.log.info("Non-existent peer generates error")
assert_raises_rpc_error(-1, "Peer does not exist", self.nodes[0].getblockfrompeer, short_tip, peer_0_peer_1_id + 1)
+ self.log.info("Fetching from pre-segwit peer generates error")
+ self.nodes[0].add_p2p_connection(P2PInterface(), services=P2P_SERVICES & ~NODE_WITNESS)
+ peers = self.nodes[0].getpeerinfo()
+ assert_equal(len(peers), 2)
+ presegwit_peer_id = peers[1]["id"]
+ assert_raises_rpc_error(-1, "Pre-SegWit peer", self.nodes[0].getblockfrompeer, short_tip, presegwit_peer_id)
+
self.log.info("Successful fetch")
result = self.nodes[0].getblockfrompeer(short_tip, peer_0_peer_1_id)
self.wait_until(lambda: self.check_for_block(short_tip), timeout=1)
@@ -66,5 +78,6 @@ class GetBlockFromPeerTest(BitcoinTestFramework):
self.log.info("Don't fetch blocks we already have")
assert_raises_rpc_error(-1, "Block already downloaded", self.nodes[0].getblockfrompeer, short_tip, peer_0_peer_1_id)
+
if __name__ == '__main__':
GetBlockFromPeerTest().main()
diff --git a/test/functional/rpc_mempool_entry_fee_fields_deprecation.py b/test/functional/rpc_mempool_entry_fee_fields_deprecation.py
deleted file mode 100755
index 82761ff7c8..0000000000
--- a/test/functional/rpc_mempool_entry_fee_fields_deprecation.py
+++ /dev/null
@@ -1,67 +0,0 @@
-#!/usr/bin/env python3
-# Copyright (c) 2021 The Bitcoin Core developers
-# Distributed under the MIT software license, see the accompanying
-# file COPYING or http://www.opensource.org/licenses/mit-license.php.
-"""Test deprecation of fee fields from top level mempool entry object"""
-
-from test_framework.blocktools import COIN
-from test_framework.test_framework import BitcoinTestFramework
-from test_framework.util import assert_equal
-from test_framework.wallet import MiniWallet
-
-
-def assertions_helper(new_object, deprecated_object, deprecated_fields):
- for field in deprecated_fields:
- assert field in deprecated_object
- assert field not in new_object
-
-
-class MempoolFeeFieldsDeprecationTest(BitcoinTestFramework):
- def set_test_params(self):
- self.num_nodes = 2
- self.extra_args = [[], ["-deprecatedrpc=fees"]]
-
- def run_test(self):
- # we get spendable outputs from the premined chain starting
- # at block 76. see BitcoinTestFramework._initialize_chain() for details
- self.wallet = MiniWallet(self.nodes[0])
- self.wallet.rescan_utxos()
-
- # we create the tx on the first node and wait until it syncs to node_deprecated
- # thus, any differences must be coming from getmempoolentry or getrawmempool
- tx = self.wallet.send_self_transfer(from_node=self.nodes[0])
- self.nodes[1].sendrawtransaction(tx["hex"])
-
- deprecated_fields = ["ancestorfees", "descendantfees", "modifiedfee", "fee"]
- self.test_getmempoolentry(tx["txid"], deprecated_fields)
- self.test_getrawmempool(tx["txid"], deprecated_fields)
- self.test_deprecated_fields_match(tx["txid"])
-
- def test_getmempoolentry(self, txid, deprecated_fields):
-
- self.log.info("Test getmempoolentry rpc")
- entry = self.nodes[0].getmempoolentry(txid)
- deprecated_entry = self.nodes[1].getmempoolentry(txid)
- assertions_helper(entry, deprecated_entry, deprecated_fields)
-
- def test_getrawmempool(self, txid, deprecated_fields):
-
- self.log.info("Test getrawmempool rpc")
- entry = self.nodes[0].getrawmempool(verbose=True)[txid]
- deprecated_entry = self.nodes[1].getrawmempool(verbose=True)[txid]
- assertions_helper(entry, deprecated_entry, deprecated_fields)
-
- def test_deprecated_fields_match(self, txid):
-
- self.log.info("Test deprecated fee fields match new fees object")
- entry = self.nodes[0].getmempoolentry(txid)
- deprecated_entry = self.nodes[1].getmempoolentry(txid)
-
- assert_equal(deprecated_entry["fee"], entry["fees"]["base"])
- assert_equal(deprecated_entry["modifiedfee"], entry["fees"]["modified"])
- assert_equal(deprecated_entry["descendantfees"], entry["fees"]["descendant"] * COIN)
- assert_equal(deprecated_entry["ancestorfees"], entry["fees"]["ancestor"] * COIN)
-
-
-if __name__ == "__main__":
- MempoolFeeFieldsDeprecationTest().main()
diff --git a/test/functional/rpc_mempool_info.py b/test/functional/rpc_mempool_info.py
new file mode 100755
index 0000000000..cd7a48d387
--- /dev/null
+++ b/test/functional/rpc_mempool_info.py
@@ -0,0 +1,102 @@
+#!/usr/bin/env python3
+# Copyright (c) 2014-2022 The Bitcoin Core developers
+# Distributed under the MIT software license, see the accompanying
+# file COPYING or http://www.opensource.org/licenses/mit-license.php.
+"""Test RPCs that retrieve information from the mempool."""
+
+from test_framework.blocktools import COINBASE_MATURITY
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import (
+ assert_equal,
+ assert_raises_rpc_error,
+)
+from test_framework.wallet import MiniWallet
+
+
+class RPCMempoolInfoTest(BitcoinTestFramework):
+ def set_test_params(self):
+ self.num_nodes = 1
+
+ def run_test(self):
+ self.wallet = MiniWallet(self.nodes[0])
+ self.generate(self.wallet, COINBASE_MATURITY + 1)
+ self.wallet.rescan_utxos()
+ confirmed_utxo = self.wallet.get_utxo()
+
+ # Create a tree of unconfirmed transactions in the mempool:
+ # txA
+ # / \
+ # / \
+ # / \
+ # / \
+ # / \
+ # txB txC
+ # / \ / \
+ # / \ / \
+ # txD txE txF txG
+ # \ /
+ # \ /
+ # txH
+
+ def create_tx(**kwargs):
+ return self.wallet.send_self_transfer_multi(
+ from_node=self.nodes[0],
+ **kwargs,
+ )
+
+ txA = create_tx(utxos_to_spend=[confirmed_utxo], num_outputs=2)
+ txB = create_tx(utxos_to_spend=[txA["new_utxos"][0]], num_outputs=2)
+ txC = create_tx(utxos_to_spend=[txA["new_utxos"][1]], num_outputs=2)
+ txD = create_tx(utxos_to_spend=[txB["new_utxos"][0]], num_outputs=1)
+ txE = create_tx(utxos_to_spend=[txB["new_utxos"][1]], num_outputs=1)
+ txF = create_tx(utxos_to_spend=[txC["new_utxos"][0]], num_outputs=2)
+ txG = create_tx(utxos_to_spend=[txC["new_utxos"][1]], num_outputs=1)
+ txH = create_tx(utxos_to_spend=[txE["new_utxos"][0],txF["new_utxos"][0]], num_outputs=1)
+ txidA, txidB, txidC, txidD, txidE, txidF, txidG, txidH = [
+ tx["txid"] for tx in [txA, txB, txC, txD, txE, txF, txG, txH]
+ ]
+
+ mempool = self.nodes[0].getrawmempool()
+ assert_equal(len(mempool), 8)
+ for txid in [txidA, txidB, txidC, txidD, txidE, txidF, txidG, txidH]:
+ assert_equal(txid in mempool, True)
+
+ self.log.info("Find transactions spending outputs")
+ result = self.nodes[0].gettxspendingprevout([ {'txid' : confirmed_utxo['txid'], 'vout' : 0}, {'txid' : txidA, 'vout' : 1} ])
+ assert_equal(result, [ {'txid' : confirmed_utxo['txid'], 'vout' : 0, 'spendingtxid' : txidA}, {'txid' : txidA, 'vout' : 1, 'spendingtxid' : txidC} ])
+
+ self.log.info("Find transaction spending multiple outputs")
+ result = self.nodes[0].gettxspendingprevout([ {'txid' : txidE, 'vout' : 0}, {'txid' : txidF, 'vout' : 0} ])
+ assert_equal(result, [ {'txid' : txidE, 'vout' : 0, 'spendingtxid' : txidH}, {'txid' : txidF, 'vout' : 0, 'spendingtxid' : txidH} ])
+
+ self.log.info("Find no transaction when output is unspent")
+ result = self.nodes[0].gettxspendingprevout([ {'txid' : txidH, 'vout' : 0} ])
+ assert_equal(result, [ {'txid' : txidH, 'vout' : 0} ])
+ result = self.nodes[0].gettxspendingprevout([ {'txid' : txidA, 'vout' : 5} ])
+ assert_equal(result, [ {'txid' : txidA, 'vout' : 5} ])
+
+ self.log.info("Mixed spent and unspent outputs")
+ result = self.nodes[0].gettxspendingprevout([ {'txid' : txidB, 'vout' : 0}, {'txid' : txidG, 'vout' : 3} ])
+ assert_equal(result, [ {'txid' : txidB, 'vout' : 0, 'spendingtxid' : txidD}, {'txid' : txidG, 'vout' : 3} ])
+
+ self.log.info("Unknown input fields")
+ assert_raises_rpc_error(-3, "Unexpected key unknown", self.nodes[0].gettxspendingprevout, [{'txid' : txidC, 'vout' : 1, 'unknown' : 42}])
+
+ self.log.info("Invalid vout provided")
+ assert_raises_rpc_error(-8, "Invalid parameter, vout cannot be negative", self.nodes[0].gettxspendingprevout, [{'txid' : txidA, 'vout' : -1}])
+
+ self.log.info("Invalid txid provided")
+ assert_raises_rpc_error(-3, "Expected type string for txid, got number", self.nodes[0].gettxspendingprevout, [{'txid' : 42, 'vout' : 0}])
+
+ self.log.info("Missing outputs")
+ assert_raises_rpc_error(-8, "Invalid parameter, outputs are missing", self.nodes[0].gettxspendingprevout, [])
+
+ self.log.info("Missing vout")
+ assert_raises_rpc_error(-3, "Missing vout", self.nodes[0].gettxspendingprevout, [{'txid' : txidA}])
+
+ self.log.info("Missing txid")
+ assert_raises_rpc_error(-3, "Missing txid", self.nodes[0].gettxspendingprevout, [{'vout' : 3}])
+
+
+if __name__ == '__main__':
+ RPCMempoolInfoTest().main()
diff --git a/test/functional/rpc_rawtransaction.py b/test/functional/rpc_rawtransaction.py
index a839af0288..1f95814e18 100755
--- a/test/functional/rpc_rawtransaction.py
+++ b/test/functional/rpc_rawtransaction.py
@@ -17,6 +17,7 @@ from decimal import Decimal
from test_framework.blocktools import COINBASE_MATURITY
from test_framework.messages import (
+ BIP125_SEQUENCE_NUMBER,
CTransaction,
tx_from_hex,
)
@@ -24,7 +25,10 @@ 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 (
+ getnewdestination,
+ MiniWallet,
)
@@ -52,79 +56,67 @@ class multidict(dict):
class RawTransactionsTest(BitcoinTestFramework):
def set_test_params(self):
self.setup_clean_chain = True
- self.num_nodes = 4
+ self.num_nodes = 3
self.extra_args = [
["-txindex"],
["-txindex"],
- ["-txindex"],
[],
]
# whitelist all peers to speed up tx relay / mempool sync
for args in self.extra_args:
args.append("-whitelist=noban@127.0.0.1")
+ self.requires_wallet = self.is_specified_wallet_compiled()
self.supports_cli = False
- def skip_test_if_missing_module(self):
- self.skip_if_no_wallet()
-
def setup_network(self):
super().setup_network()
self.connect_nodes(0, 2)
def run_test(self):
+ self.wallet = MiniWallet(self.nodes[0])
self.log.info("Prepare some coins for multiple *rawtransaction commands")
- self.generate(self.nodes[2], 1)
+ self.generate(self.wallet, 10)
self.generate(self.nodes[0], COINBASE_MATURITY + 1)
- for amount in [1.5, 1.0, 5.0]:
- self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), amount)
- self.sync_all()
- self.generate(self.nodes[0], 5)
self.getrawtransaction_tests()
self.createrawtransaction_tests()
- self.signrawtransactionwithwallet_tests()
self.sendrawtransaction_tests()
self.sendrawtransaction_testmempoolaccept_tests()
self.decoderawtransaction_tests()
self.transaction_version_number_tests()
- if not self.options.descriptors:
+ if self.requires_wallet and not self.options.descriptors:
self.raw_multisig_transaction_legacy_tests()
def getrawtransaction_tests(self):
- addr = self.nodes[1].getnewaddress()
- txid = self.nodes[0].sendtoaddress(addr, 10)
+ tx = self.wallet.send_self_transfer(from_node=self.nodes[0])
self.generate(self.nodes[0], 1)
- vout = find_vout_for_address(self.nodes[1], txid, addr)
- rawTx = self.nodes[1].createrawtransaction([{'txid': txid, 'vout': vout}], {self.nodes[1].getnewaddress(): 9.999})
- rawTxSigned = self.nodes[1].signrawtransactionwithwallet(rawTx)
- txId = self.nodes[1].sendrawtransaction(rawTxSigned['hex'])
- self.generateblock(self.nodes[0], output=self.nodes[0].getnewaddress(), transactions=[rawTxSigned['hex']])
+ txId = tx['txid']
err_msg = (
"No such mempool transaction. Use -txindex or provide a block hash to enable"
" blockchain transaction queries. Use gettransaction for wallet transactions."
)
- for n in [0, 3]:
+ for n in [0, 2]:
self.log.info(f"Test getrawtransaction {'with' if n == 0 else 'without'} -txindex")
if n == 0:
# With -txindex.
# 1. valid parameters - only supply txid
- assert_equal(self.nodes[n].getrawtransaction(txId), rawTxSigned['hex'])
+ assert_equal(self.nodes[n].getrawtransaction(txId), tx['hex'])
# 2. valid parameters - supply txid and 0 for non-verbose
- assert_equal(self.nodes[n].getrawtransaction(txId, 0), rawTxSigned['hex'])
+ assert_equal(self.nodes[n].getrawtransaction(txId, 0), tx['hex'])
# 3. valid parameters - supply txid and False for non-verbose
- assert_equal(self.nodes[n].getrawtransaction(txId, False), rawTxSigned['hex'])
+ assert_equal(self.nodes[n].getrawtransaction(txId, False), tx['hex'])
# 4. valid parameters - supply txid and 1 for verbose.
# We only check the "hex" field of the output so we don't need to update this test every time the output format changes.
- assert_equal(self.nodes[n].getrawtransaction(txId, 1)["hex"], rawTxSigned['hex'])
+ assert_equal(self.nodes[n].getrawtransaction(txId, 1)["hex"], tx['hex'])
# 5. valid parameters - supply txid and True for non-verbose
- assert_equal(self.nodes[n].getrawtransaction(txId, True)["hex"], rawTxSigned['hex'])
+ assert_equal(self.nodes[n].getrawtransaction(txId, True)["hex"], tx['hex'])
else:
# Without -txindex, expect to raise.
for verbose in [None, 0, False, 1, True]:
@@ -141,9 +133,9 @@ class RawTransactionsTest(BitcoinTestFramework):
assert_raises_rpc_error(-1, "not a boolean", self.nodes[n].getrawtransaction, txId, {})
# Make a tx by sending, then generate 2 blocks; block1 has the tx in it
- tx = self.nodes[2].sendtoaddress(self.nodes[1].getnewaddress(), 1)
+ tx = self.wallet.send_self_transfer(from_node=self.nodes[2])['txid']
block1, block2 = self.generate(self.nodes[2], 2)
- for n in [0, 3]:
+ for n in [0, 2]:
self.log.info(f"Test getrawtransaction {'with' if n == 0 else 'without'} -txindex, with blockhash")
# We should be able to get the raw transaction by providing the correct block
gottx = self.nodes[n].getrawtransaction(txid=tx, verbose=True, blockhash=block1)
@@ -200,20 +192,21 @@ class RawTransactionsTest(BitcoinTestFramework):
# sequence number out of range
for invalid_seq in [-1, 4294967296]:
inputs = [{'txid': TXID, 'vout': 1, 'sequence': invalid_seq}]
- outputs = {self.nodes[0].getnewaddress(): 1}
+ address = getnewdestination()[2]
+ outputs = {address: 1}
assert_raises_rpc_error(-8, 'Invalid parameter, sequence number is out of range',
self.nodes[0].createrawtransaction, inputs, outputs)
# with valid sequence number
for valid_seq in [1000, 4294967294]:
inputs = [{'txid': TXID, 'vout': 1, 'sequence': valid_seq}]
- outputs = {self.nodes[0].getnewaddress(): 1}
+ address = getnewdestination()[2]
+ outputs = {address: 1}
rawtx = self.nodes[0].createrawtransaction(inputs, outputs)
decrawtx = self.nodes[0].decoderawtransaction(rawtx)
assert_equal(decrawtx['vin'][0]['sequence'], valid_seq)
# Test `createrawtransaction` invalid `outputs`
- address = self.nodes[0].getnewaddress()
- address2 = self.nodes[0].getnewaddress()
+ address = getnewdestination()[2]
assert_raises_rpc_error(-1, "JSON value is not an array as expected", self.nodes[0].createrawtransaction, [], 'foo')
self.nodes[0].createrawtransaction(inputs=[], outputs={}) # Should not throw for backwards compatibility
self.nodes[0].createrawtransaction(inputs=[], outputs=[])
@@ -228,6 +221,10 @@ class RawTransactionsTest(BitcoinTestFramework):
assert_raises_rpc_error(-8, "Invalid parameter, key-value pair must contain exactly one key", self.nodes[0].createrawtransaction, [], [{'a': 1, 'b': 2}])
assert_raises_rpc_error(-8, "Invalid parameter, key-value pair not an object as expected", self.nodes[0].createrawtransaction, [], [['key-value pair1'], ['2']])
+ # Test `createrawtransaction` mismatch between sequence number(s) and `replaceable` option
+ assert_raises_rpc_error(-8, "Invalid parameter combination: Sequence number(s) contradict replaceable option",
+ self.nodes[0].createrawtransaction, [{'txid': TXID, 'vout': 0, 'sequence': BIP125_SEQUENCE_NUMBER+1}], {}, 0, True)
+
# Test `createrawtransaction` invalid `locktime`
assert_raises_rpc_error(-3, "Expected type number", self.nodes[0].createrawtransaction, [], {}, 'foo')
assert_raises_rpc_error(-8, "Invalid parameter, locktime out of range", self.nodes[0].createrawtransaction, [], {}, -1)
@@ -245,6 +242,7 @@ class RawTransactionsTest(BitcoinTestFramework):
self.nodes[2].createrawtransaction(inputs=[{'txid': TXID, 'vout': 9}], outputs=[{address: 99}]),
)
# Two outputs
+ address2 = getnewdestination()[2]
tx = tx_from_hex(self.nodes[2].createrawtransaction(inputs=[{'txid': TXID, 'vout': 9}], outputs=OrderedDict([(address, 99), (address2, 99)])))
assert_equal(len(tx.vout), 2)
assert_equal(
@@ -259,122 +257,53 @@ class RawTransactionsTest(BitcoinTestFramework):
self.nodes[2].createrawtransaction(inputs=[{'txid': TXID, 'vout': 9}], outputs=[{address: 99}, {address2: 99}, {'data': '99'}]),
)
- def signrawtransactionwithwallet_tests(self):
- for type in ["bech32", "p2sh-segwit", "legacy"]:
- self.log.info(f"Test signrawtransactionwithwallet with missing prevtx info ({type})")
- addr = self.nodes[0].getnewaddress("", type)
- addrinfo = self.nodes[0].getaddressinfo(addr)
- pubkey = addrinfo["scriptPubKey"]
- inputs = [{'txid': TXID, 'vout': 3, 'sequence': 1000}]
- outputs = {self.nodes[0].getnewaddress(): 1}
- rawtx = self.nodes[0].createrawtransaction(inputs, outputs)
-
- prevtx = dict(txid=TXID, scriptPubKey=pubkey, vout=3, amount=1)
- succ = self.nodes[0].signrawtransactionwithwallet(rawtx, [prevtx])
- assert succ["complete"]
-
- if type == "legacy":
- del prevtx["amount"]
- succ = self.nodes[0].signrawtransactionwithwallet(rawtx, [prevtx])
- assert succ["complete"]
- else:
- assert_raises_rpc_error(-3, "Missing amount", self.nodes[0].signrawtransactionwithwallet, rawtx, [
- {
- "txid": TXID,
- "scriptPubKey": pubkey,
- "vout": 3,
- }
- ])
-
- assert_raises_rpc_error(-3, "Missing vout", self.nodes[0].signrawtransactionwithwallet, rawtx, [
- {
- "txid": TXID,
- "scriptPubKey": pubkey,
- "amount": 1,
- }
- ])
- assert_raises_rpc_error(-3, "Missing txid", self.nodes[0].signrawtransactionwithwallet, rawtx, [
- {
- "scriptPubKey": pubkey,
- "vout": 3,
- "amount": 1,
- }
- ])
- assert_raises_rpc_error(-3, "Missing scriptPubKey", self.nodes[0].signrawtransactionwithwallet, rawtx, [
- {
- "txid": TXID,
- "vout": 3,
- "amount": 1
- }
- ])
-
def sendrawtransaction_tests(self):
self.log.info("Test sendrawtransaction with missing input")
inputs = [{'txid': TXID, 'vout': 1}] # won't exist
- outputs = {self.nodes[0].getnewaddress(): 4.998}
+ address = getnewdestination()[2]
+ outputs = {address: 4.998}
rawtx = self.nodes[2].createrawtransaction(inputs, outputs)
- rawtx = self.nodes[2].signrawtransactionwithwallet(rawtx)
- assert_raises_rpc_error(-25, "bad-txns-inputs-missingorspent", self.nodes[2].sendrawtransaction, rawtx['hex'])
+ assert_raises_rpc_error(-25, "bad-txns-inputs-missingorspent", self.nodes[2].sendrawtransaction, rawtx)
def sendrawtransaction_testmempoolaccept_tests(self):
self.log.info("Test sendrawtransaction/testmempoolaccept with maxfeerate")
fee_exceeds_max = "Fee exceeds maximum configured by user (e.g. -maxtxfee, maxfeerate)"
# Test a transaction with a small fee.
- txId = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 1.0)
- rawTx = self.nodes[0].getrawtransaction(txId, True)
- vout = next(o for o in rawTx['vout'] if o['value'] == Decimal('1.00000000'))
-
- self.sync_all()
- inputs = [{"txid": txId, "vout": vout['n']}]
- # Fee 10,000 satoshis, (1 - (10000 sat * 0.00000001 BTC/sat)) = 0.9999
- outputs = {self.nodes[0].getnewaddress(): Decimal("0.99990000")}
- rawTx = self.nodes[2].createrawtransaction(inputs, outputs)
- rawTxSigned = self.nodes[2].signrawtransactionwithwallet(rawTx)
- assert_equal(rawTxSigned['complete'], True)
- # Fee 10,000 satoshis, ~100 b transaction, fee rate should land around 100 sat/byte = 0.00100000 BTC/kB
+ # Fee rate is 0.00100000 BTC/kvB
+ tx = self.wallet.create_self_transfer(fee_rate=Decimal('0.00100000'))
# Thus, testmempoolaccept should reject
- testres = self.nodes[2].testmempoolaccept([rawTxSigned['hex']], 0.00001000)[0]
+ testres = self.nodes[2].testmempoolaccept([tx['hex']], 0.00001000)[0]
assert_equal(testres['allowed'], False)
assert_equal(testres['reject-reason'], 'max-fee-exceeded')
# and sendrawtransaction should throw
- assert_raises_rpc_error(-25, fee_exceeds_max, self.nodes[2].sendrawtransaction, rawTxSigned['hex'], 0.00001000)
+ assert_raises_rpc_error(-25, fee_exceeds_max, self.nodes[2].sendrawtransaction, tx['hex'], 0.00001000)
# and the following calls should both succeed
- testres = self.nodes[2].testmempoolaccept(rawtxs=[rawTxSigned['hex']])[0]
+ testres = self.nodes[2].testmempoolaccept(rawtxs=[tx['hex']])[0]
assert_equal(testres['allowed'], True)
- self.nodes[2].sendrawtransaction(hexstring=rawTxSigned['hex'])
+ self.nodes[2].sendrawtransaction(hexstring=tx['hex'])
# Test a transaction with a large fee.
- txId = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 1.0)
- rawTx = self.nodes[0].getrawtransaction(txId, True)
- vout = next(o for o in rawTx['vout'] if o['value'] == Decimal('1.00000000'))
-
- self.sync_all()
- inputs = [{"txid": txId, "vout": vout['n']}]
- # Fee 2,000,000 satoshis, (1 - (2000000 sat * 0.00000001 BTC/sat)) = 0.98
- outputs = {self.nodes[0].getnewaddress() : Decimal("0.98000000")}
- rawTx = self.nodes[2].createrawtransaction(inputs, outputs)
- rawTxSigned = self.nodes[2].signrawtransactionwithwallet(rawTx)
- assert_equal(rawTxSigned['complete'], True)
- # Fee 2,000,000 satoshis, ~100 b transaction, fee rate should land around 20,000 sat/byte = 0.20000000 BTC/kB
+ # Fee rate is 0.20000000 BTC/kvB
+ tx = self.wallet.create_self_transfer(mempool_valid=False, from_node=self.nodes[0], fee_rate=Decimal('0.20000000'))
# Thus, testmempoolaccept should reject
- testres = self.nodes[2].testmempoolaccept([rawTxSigned['hex']])[0]
+ testres = self.nodes[2].testmempoolaccept([tx['hex']])[0]
assert_equal(testres['allowed'], False)
assert_equal(testres['reject-reason'], 'max-fee-exceeded')
# and sendrawtransaction should throw
- assert_raises_rpc_error(-25, fee_exceeds_max, self.nodes[2].sendrawtransaction, rawTxSigned['hex'])
+ assert_raises_rpc_error(-25, fee_exceeds_max, self.nodes[2].sendrawtransaction, tx['hex'])
# and the following calls should both succeed
- testres = self.nodes[2].testmempoolaccept(rawtxs=[rawTxSigned['hex']], maxfeerate='0.20000000')[0]
+ testres = self.nodes[2].testmempoolaccept(rawtxs=[tx['hex']], maxfeerate='0.20000000')[0]
assert_equal(testres['allowed'], True)
- self.nodes[2].sendrawtransaction(hexstring=rawTxSigned['hex'], maxfeerate='0.20000000')
+ self.nodes[2].sendrawtransaction(hexstring=tx['hex'], maxfeerate='0.20000000')
self.log.info("Test sendrawtransaction/testmempoolaccept with tx already in the chain")
self.generate(self.nodes[2], 1)
for node in self.nodes:
- testres = node.testmempoolaccept([rawTxSigned['hex']])[0]
+ testres = node.testmempoolaccept([tx['hex']])[0]
assert_equal(testres['allowed'], False)
assert_equal(testres['reject-reason'], 'txn-already-known')
- assert_raises_rpc_error(-27, 'Transaction already in block chain', node.sendrawtransaction, rawTxSigned['hex'])
+ assert_raises_rpc_error(-27, 'Transaction already in block chain', node.sendrawtransaction, tx['hex'])
def decoderawtransaction_tests(self):
self.log.info("Test decoderawtransaction")
diff --git a/test/functional/rpc_signrawtransaction.py b/test/functional/rpc_signrawtransaction.py
index a2091b4ece..8da2cfa72b 100755
--- a/test/functional/rpc_signrawtransaction.py
+++ b/test/functional/rpc_signrawtransaction.py
@@ -334,6 +334,56 @@ class SignRawTransactionsTest(BitcoinTestFramework):
assert_equal(signed["complete"], True)
self.nodes[0].sendrawtransaction(signed["hex"])
+ def test_signing_with_missing_prevtx_info(self):
+ txid = "1d1d4e24ed99057e84c3f80fd8fbec79ed9e1acee37da269356ecea000000000"
+ for type in ["bech32", "p2sh-segwit", "legacy"]:
+ self.log.info(f"Test signing with missing prevtx info ({type})")
+ addr = self.nodes[0].getnewaddress("", type)
+ addrinfo = self.nodes[0].getaddressinfo(addr)
+ pubkey = addrinfo["scriptPubKey"]
+ inputs = [{'txid': txid, 'vout': 3, 'sequence': 1000}]
+ outputs = {self.nodes[0].getnewaddress(): 1}
+ rawtx = self.nodes[0].createrawtransaction(inputs, outputs)
+
+ prevtx = dict(txid=txid, scriptPubKey=pubkey, vout=3, amount=1)
+ succ = self.nodes[0].signrawtransactionwithwallet(rawtx, [prevtx])
+ assert succ["complete"]
+
+ if type == "legacy":
+ del prevtx["amount"]
+ succ = self.nodes[0].signrawtransactionwithwallet(rawtx, [prevtx])
+ assert succ["complete"]
+ else:
+ assert_raises_rpc_error(-3, "Missing amount", self.nodes[0].signrawtransactionwithwallet, rawtx, [
+ {
+ "txid": txid,
+ "scriptPubKey": pubkey,
+ "vout": 3,
+ }
+ ])
+
+ assert_raises_rpc_error(-3, "Missing vout", self.nodes[0].signrawtransactionwithwallet, rawtx, [
+ {
+ "txid": txid,
+ "scriptPubKey": pubkey,
+ "amount": 1,
+ }
+ ])
+ assert_raises_rpc_error(-3, "Missing txid", self.nodes[0].signrawtransactionwithwallet, rawtx, [
+ {
+ "scriptPubKey": pubkey,
+ "vout": 3,
+ "amount": 1,
+ }
+ ])
+ assert_raises_rpc_error(-3, "Missing scriptPubKey", self.nodes[0].signrawtransactionwithwallet, rawtx, [
+ {
+ "txid": txid,
+ "vout": 3,
+ "amount": 1
+ }
+ ])
+
def run_test(self):
self.successful_signing_test()
self.script_verification_error_test()
@@ -343,6 +393,7 @@ class SignRawTransactionsTest(BitcoinTestFramework):
self.test_fully_signed_tx()
self.test_signing_with_csv()
self.test_signing_with_cltv()
+ self.test_signing_with_missing_prevtx_info()
if __name__ == '__main__':
diff --git a/test/functional/test_framework/wallet.py b/test/functional/test_framework/wallet.py
index 857c779adf..e43dd9f61a 100644
--- a/test/functional/test_framework/wallet.py
+++ b/test/functional/test_framework/wallet.py
@@ -168,6 +168,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)
@@ -278,8 +285,8 @@ class MiniWallet:
return {'txid': tx.rehash(), 'wtxid': tx.getwtxid(), 'hex': tx_hex, 'tx': tx}
- def sendrawtransaction(self, *, from_node, tx_hex, **kwargs):
- txid = from_node.sendrawtransaction(hexstring=tx_hex, **kwargs)
+ def sendrawtransaction(self, *, from_node, tx_hex, maxfeerate=0, **kwargs):
+ txid = from_node.sendrawtransaction(hexstring=tx_hex, maxfeerate=maxfeerate, **kwargs)
self.scan_tx(from_node.decoderawtransaction(tx_hex))
return txid
diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py
index 8416a5881d..6a44f9d21d 100755
--- a/test/functional/test_runner.py
+++ b/test/functional/test_runner.py
@@ -157,6 +157,7 @@ BASE_SCRIPTS = [
'wallet_avoidreuse.py --descriptors',
'mempool_reorg.py',
'mempool_persist.py',
+ 'p2p_block_sync.py',
'wallet_multiwallet.py --legacy-wallet',
'wallet_multiwallet.py --descriptors',
'wallet_multiwallet.py --usecli',
@@ -183,7 +184,6 @@ BASE_SCRIPTS = [
'rpc_signrawtransaction.py --legacy-wallet',
'rpc_signrawtransaction.py --descriptors',
'rpc_rawtransaction.py --legacy-wallet',
- 'rpc_rawtransaction.py --descriptors',
'wallet_groups.py --legacy-wallet',
'wallet_transactiontime_rescan.py --descriptors',
'wallet_transactiontime_rescan.py --legacy-wallet',
@@ -328,7 +328,7 @@ BASE_SCRIPTS = [
'feature_presegwit_node_upgrade.py',
'feature_settings.py',
'rpc_getdescriptorinfo.py',
- 'rpc_mempool_entry_fee_fields_deprecation.py',
+ 'rpc_mempool_info.py',
'rpc_help.py',
'feature_dirsymlinks.py',
'feature_help.py',
diff --git a/test/lint/README.md b/test/lint/README.md
index 1f683c10b3..a23211a72b 100644
--- a/test/lint/README.md
+++ b/test/lint/README.md
@@ -39,6 +39,6 @@ To do so, add the upstream repository as remote:
git remote add --fetch secp256k1 https://github.com/bitcoin-core/secp256k1.git
```
-lint-all.py
+all-lint.py
===========
Calls other scripts with the `lint-` prefix.
diff --git a/test/lint/lint-all.py b/test/lint/all-lint.py
index c280ba2db2..34a7b9742a 100755
--- a/test/lint/lint-all.py
+++ b/test/lint/all-lint.py
@@ -13,11 +13,10 @@ from subprocess import run
exit_code = 0
mod_path = Path(__file__).parent
-for lint in glob(f"{mod_path}/lint-*"):
- if lint != __file__:
- result = run([lint])
- if result.returncode != 0:
- print(f"^---- failure generated from {lint.split('/')[-1]}")
- exit_code |= result.returncode
+for lint in glob(f"{mod_path}/lint-*.py"):
+ result = run([lint])
+ if result.returncode != 0:
+ print(f"^---- failure generated from {lint.split('/')[-1]}")
+ exit_code |= result.returncode
exit(exit_code)
diff --git a/test/lint/lint-logs.py b/test/lint/lint-logs.py
index e6c4c068fb..de53729b4e 100755
--- a/test/lint/lint-logs.py
+++ b/test/lint/lint-logs.py
@@ -16,12 +16,12 @@ from subprocess import check_output
def main():
- logs_list = check_output(["git", "grep", "--extended-regexp", r"LogPrintf?\(", "--", "*.cpp"], universal_newlines=True, encoding="utf8").splitlines()
+ logs_list = check_output(["git", "grep", "--extended-regexp", r"(LogPrintLevel|LogPrintf?)\(", "--", "*.cpp"], universal_newlines=True, encoding="utf8").splitlines()
unterminated_logs = [line for line in logs_list if not re.search(r'(\\n"|/\* Continued \*/)', line)]
if unterminated_logs != []:
- print("All calls to LogPrintf() and LogPrint() should be terminated with \\n")
+ print("All calls to LogPrintf(), LogPrint(), LogPrintLevel(), and WalletLogPrintf() should be terminated with \"\\n\".")
print("")
for line in unterminated_logs:
diff --git a/test/lint/spelling.ignore-words.txt b/test/lint/spelling.ignore-words.txt
index afdb0692d8..c931a0aae1 100644
--- a/test/lint/spelling.ignore-words.txt
+++ b/test/lint/spelling.ignore-words.txt
@@ -11,6 +11,7 @@ inout
invokable
keypair
mor
+nd
nin
ser
unparseable