aboutsummaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rw-r--r--test/functional/README.md2
-rwxr-xr-xtest/functional/mempool_expiry.py52
-rwxr-xr-xtest/functional/mempool_resurrect.py61
-rwxr-xr-xtest/functional/p2p_blocksonly.py2
-rwxr-xr-xtest/functional/p2p_permissions.py50
-rwxr-xr-xtest/functional/p2p_segwit.py10
-rwxr-xr-xtest/functional/p2p_tx_download.py53
-rwxr-xr-xtest/functional/rpc_blockchain.py44
-rwxr-xr-xtest/functional/rpc_getpeerinfo_deprecation.py38
-rwxr-xr-xtest/functional/test_framework/p2p.py7
-rw-r--r--test/functional/test_framework/script.py2
-rwxr-xr-xtest/functional/test_framework/test_framework.py5
-rwxr-xr-xtest/functional/test_framework/test_node.py5
-rwxr-xr-xtest/functional/test_runner.py1
-rwxr-xr-xtest/functional/tool_wallet.py285
-rwxr-xr-xtest/functional/wallet_multiwallet.py8
-rwxr-xr-xtest/fuzz/test_runner.py4
-rwxr-xr-xtest/lint/lint-git-commit-check.sh7
-rwxr-xr-xtest/lint/lint-includes.sh1
-rwxr-xr-xtest/lint/lint-python.sh2
-rwxr-xr-xtest/lint/lint-shell.sh8
-rwxr-xr-xtest/lint/lint-whitespace.sh7
-rw-r--r--test/sanitizer_suppressions/tsan23
23 files changed, 400 insertions, 277 deletions
diff --git a/test/functional/README.md b/test/functional/README.md
index 2764acbf18..2d04413eb2 100644
--- a/test/functional/README.md
+++ b/test/functional/README.md
@@ -23,7 +23,7 @@ don't have test cases for.
- The oldest supported Python version is specified in [doc/dependencies.md](/doc/dependencies.md).
Consider using [pyenv](https://github.com/pyenv/pyenv), which checks [.python-version](/.python-version),
to prevent accidentally introducing modern syntax from an unsupported Python version.
- The Travis linter also checks this, but [possibly not in all cases](https://github.com/bitcoin/bitcoin/pull/14884#discussion_r239585126).
+ The CI linter job also checks this, but [possibly not in all cases](https://github.com/bitcoin/bitcoin/pull/14884#discussion_r239585126).
- See [the python lint script](/test/lint/lint-python.sh) that checks for violations that
could lead to bugs and issues in the test code.
- Use [type hints](https://docs.python.org/3/library/typing.html) in your code to improve code readability
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)
diff --git a/test/functional/mempool_resurrect.py b/test/functional/mempool_resurrect.py
index 187c9026f6..bc0c8279a6 100755
--- a/test/functional/mempool_resurrect.py
+++ b/test/functional/mempool_resurrect.py
@@ -4,66 +4,59 @@
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test resurrection of mined transactions when the blockchain is re-organized."""
-from test_framework.blocktools import create_raw_transaction
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_equal
+from test_framework.wallet import MiniWallet
class MempoolCoinbaseTest(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 run_test(self):
- node0_address = self.nodes[0].getnewaddress()
+ node = self.nodes[0]
+ wallet = MiniWallet(node)
+
+ # Add enough mature utxos to the wallet so that all txs spend confirmed coins
+ wallet.generate(3)
+ node.generate(100)
+
# Spend block 1/2/3's coinbase transactions
- # Mine a block.
+ # Mine a block
# Create three more transactions, spending the spends
- # Mine another block.
+ # Mine another block
# ... make sure all the transactions are confirmed
# Invalidate both blocks
# ... make sure all the transactions are put back in the mempool
# Mine a new block
- # ... make sure all the transactions are confirmed again.
-
- b = [self.nodes[0].getblockhash(n) for n in range(1, 4)]
- coinbase_txids = [self.nodes[0].getblock(h)['tx'][0] for h in b]
- spends1_raw = [create_raw_transaction(self.nodes[0], txid, node0_address, amount=49.99) for txid in coinbase_txids]
- spends1_id = [self.nodes[0].sendrawtransaction(tx) for tx in spends1_raw]
-
+ # ... make sure all the transactions are confirmed again
blocks = []
- blocks.extend(self.nodes[0].generate(1))
-
- spends2_raw = [create_raw_transaction(self.nodes[0], txid, node0_address, amount=49.98) for txid in spends1_id]
- spends2_id = [self.nodes[0].sendrawtransaction(tx) for tx in spends2_raw]
+ spends1_ids = [wallet.send_self_transfer(from_node=node)['txid'] for _ in range(3)]
+ blocks.extend(node.generate(1))
+ spends2_ids = [wallet.send_self_transfer(from_node=node)['txid'] for _ in range(3)]
+ blocks.extend(node.generate(1))
- blocks.extend(self.nodes[0].generate(1))
+ spends_ids = set(spends1_ids + spends2_ids)
# mempool should be empty, all txns confirmed
- assert_equal(set(self.nodes[0].getrawmempool()), set())
- for txid in spends1_id+spends2_id:
- tx = self.nodes[0].gettransaction(txid)
- assert tx["confirmations"] > 0
+ assert_equal(set(node.getrawmempool()), set())
+ confirmed_txns = set(node.getblock(blocks[0])['tx'] + node.getblock(blocks[1])['tx'])
+ # Checks that all spend txns are contained in the mined blocks
+ assert spends_ids < confirmed_txns
# Use invalidateblock to re-org back
- for node in self.nodes:
- node.invalidateblock(blocks[0])
+ node.invalidateblock(blocks[0])
# All txns should be back in mempool with 0 confirmations
- assert_equal(set(self.nodes[0].getrawmempool()), set(spends1_id+spends2_id))
- for txid in spends1_id+spends2_id:
- tx = self.nodes[0].gettransaction(txid)
- assert tx["confirmations"] == 0
+ assert_equal(set(node.getrawmempool()), spends_ids)
# Generate another block, they should all get mined
- self.nodes[0].generate(1)
+ blocks = node.generate(1)
# mempool should be empty, all txns confirmed
- assert_equal(set(self.nodes[0].getrawmempool()), set())
- for txid in spends1_id+spends2_id:
- tx = self.nodes[0].gettransaction(txid)
- assert tx["confirmations"] > 0
+ assert_equal(set(node.getrawmempool()), set())
+ confirmed_txns = set(node.getblock(blocks[0])['tx'])
+ assert spends_ids < confirmed_txns
if __name__ == '__main__':
diff --git a/test/functional/p2p_blocksonly.py b/test/functional/p2p_blocksonly.py
index e80422d1cf..646baa1550 100755
--- a/test/functional/p2p_blocksonly.py
+++ b/test/functional/p2p_blocksonly.py
@@ -59,7 +59,7 @@ class P2PBlocksOnly(BitcoinTestFramework):
self.log.info('Check that txs from peers with relay-permission are not rejected and relayed to others')
self.log.info("Restarting node 0 with relay permission and blocksonly")
- self.restart_node(0, ["-persistmempool=0", "-whitelist=relay@127.0.0.1", "-blocksonly", '-deprecatedrpc=whitelisted'])
+ self.restart_node(0, ["-persistmempool=0", "-whitelist=relay@127.0.0.1", "-blocksonly"])
assert_equal(self.nodes[0].getrawmempool(), [])
first_peer = self.nodes[0].add_p2p_connection(P2PInterface())
second_peer = self.nodes[0].add_p2p_connection(P2PInterface())
diff --git a/test/functional/p2p_permissions.py b/test/functional/p2p_permissions.py
index ed82e6a2e2..62652d949d 100755
--- a/test/functional/p2p_permissions.py
+++ b/test/functional/p2p_permissions.py
@@ -38,35 +38,24 @@ class P2PPermissionsTests(BitcoinTestFramework):
# default permissions (no specific permissions)
["-whitelist=127.0.0.1"],
# Make sure the default values in the command line documentation match the ones here
- ["relay", "noban", "mempool", "download"],
- True)
-
- self.checkpermission(
- # check without deprecatedrpc=whitelisted
- ["-whitelist=127.0.0.1"],
- # Make sure the default values in the command line documentation match the ones here
- ["relay", "noban", "mempool", "download"],
- None)
+ ["relay", "noban", "mempool", "download"])
self.checkpermission(
# no permission (even with forcerelay)
["-whitelist=@127.0.0.1", "-whitelistforcerelay=1"],
- [],
- False)
+ [])
self.checkpermission(
# relay permission removed (no specific permissions)
["-whitelist=127.0.0.1", "-whitelistrelay=0"],
- ["noban", "mempool", "download"],
- True)
+ ["noban", "mempool", "download"])
self.checkpermission(
# forcerelay and relay permission added
# Legacy parameter interaction which set whitelistrelay to true
# if whitelistforcerelay is true
["-whitelist=127.0.0.1", "-whitelistforcerelay"],
- ["forcerelay", "relay", "noban", "mempool", "download"],
- True)
+ ["forcerelay", "relay", "noban", "mempool", "download"])
# Let's make sure permissions are merged correctly
# For this, we need to use whitebind instead of bind
@@ -76,39 +65,28 @@ class P2PPermissionsTests(BitcoinTestFramework):
self.checkpermission(
["-whitelist=noban@127.0.0.1"],
# Check parameter interaction forcerelay should activate relay
- ["noban", "bloomfilter", "forcerelay", "relay", "download"],
- False)
+ ["noban", "bloomfilter", "forcerelay", "relay", "download"])
self.replaceinconfig(1, "whitebind=bloomfilter,forcerelay@" + ip_port, "bind=127.0.0.1")
self.checkpermission(
# legacy whitelistrelay should be ignored
["-whitelist=noban,mempool@127.0.0.1", "-whitelistrelay"],
- ["noban", "mempool", "download"],
- False)
-
- self.checkpermission(
- # check without deprecatedrpc=whitelisted
- ["-whitelist=noban,mempool@127.0.0.1", "-whitelistrelay"],
- ["noban", "mempool", "download"],
- None)
+ ["noban", "mempool", "download"])
self.checkpermission(
# legacy whitelistforcerelay should be ignored
["-whitelist=noban,mempool@127.0.0.1", "-whitelistforcerelay"],
- ["noban", "mempool", "download"],
- False)
+ ["noban", "mempool", "download"])
self.checkpermission(
# missing mempool permission to be considered legacy whitelisted
["-whitelist=noban@127.0.0.1"],
- ["noban", "download"],
- False)
+ ["noban", "download"])
self.checkpermission(
# all permission added
["-whitelist=all@127.0.0.1"],
- ["forcerelay", "noban", "mempool", "bloomfilter", "relay", "download", "addr"],
- False)
+ ["forcerelay", "noban", "mempool", "bloomfilter", "relay", "download", "addr"])
self.stop_node(1)
self.nodes[1].assert_start_raises_init_error(["-whitelist=oopsie@127.0.0.1"], "Invalid P2P permission", match=ErrorMatch.PARTIAL_REGEX)
@@ -169,19 +147,13 @@ class P2PPermissionsTests(BitcoinTestFramework):
reject_reason='Not relaying non-mempool transaction {} from forcerelay peer=0'.format(txid)
)
- def checkpermission(self, args, expectedPermissions, whitelisted):
- if whitelisted is not None:
- args = [*args, '-deprecatedrpc=whitelisted']
+ def checkpermission(self, args, expectedPermissions):
self.restart_node(1, args)
self.connect_nodes(0, 1)
peerinfo = self.nodes[1].getpeerinfo()[0]
- if whitelisted is None:
- assert 'whitelisted' not in peerinfo
- else:
- assert_equal(peerinfo['whitelisted'], whitelisted)
assert_equal(len(expectedPermissions), len(peerinfo['permissions']))
for p in expectedPermissions:
- if not p in peerinfo['permissions']:
+ if p not in peerinfo['permissions']:
raise AssertionError("Expected permissions %r is not granted." % p)
def replaceinconfig(self, nodeid, old, new):
diff --git a/test/functional/p2p_segwit.py b/test/functional/p2p_segwit.py
index e99ecd8026..a9d8b12d70 100755
--- a/test/functional/p2p_segwit.py
+++ b/test/functional/p2p_segwit.py
@@ -37,7 +37,6 @@ from test_framework.messages import (
msg_tx,
msg_block,
msg_no_witness_tx,
- msg_verack,
ser_uint256,
ser_vector,
sha256,
@@ -146,7 +145,7 @@ def test_witness_block(node, p2p, block, accepted, with_witness=True, reason=Non
class TestP2PConn(P2PInterface):
def __init__(self, wtxidrelay=False):
- super().__init__()
+ super().__init__(wtxidrelay=wtxidrelay)
self.getdataset = set()
self.last_wtxidrelay = []
self.lastgetdata = []
@@ -157,13 +156,6 @@ class TestP2PConn(P2PInterface):
def on_inv(self, message):
pass
- def on_version(self, message):
- if self.wtxidrelay:
- super().on_version(message)
- else:
- self.send_message(msg_verack())
- self.nServices = message.nServices
-
def on_getdata(self, message):
self.lastgetdata = message.inv
for inv in message.inv:
diff --git a/test/functional/p2p_tx_download.py b/test/functional/p2p_tx_download.py
index 16d9302db8..8a751c6b54 100755
--- a/test/functional/p2p_tx_download.py
+++ b/test/functional/p2p_tx_download.py
@@ -30,8 +30,8 @@ import time
class TestP2PConn(P2PInterface):
- def __init__(self):
- super().__init__()
+ def __init__(self, wtxidrelay=True):
+ super().__init__(wtxidrelay=wtxidrelay)
self.tx_getdata_count = 0
def on_getdata(self, message):
@@ -47,6 +47,7 @@ TXID_RELAY_DELAY = 2 # seconds
OVERLOADED_PEER_DELAY = 2 # seconds
MAX_GETDATA_IN_FLIGHT = 100
MAX_PEER_TX_ANNOUNCEMENTS = 5000
+NONPREF_PEER_TX_DELAY = 2
# Python test constants
NUM_INBOUND = 10
@@ -168,8 +169,6 @@ class TxDownloadTest(BitcoinTestFramework):
assert_equal(peer_fallback.tx_getdata_count, 0)
self.nodes[0].setmocktime(int(time.time()) + GETDATA_TX_INTERVAL + 1) # Wait for request to peer_expiry to expire
peer_fallback.wait_until(lambda: peer_fallback.tx_getdata_count >= 1, timeout=1)
- with p2p_lock:
- assert_equal(peer_fallback.tx_getdata_count, 1)
self.restart_node(0) # reset mocktime
def test_disconnect_fallback(self):
@@ -187,8 +186,6 @@ class TxDownloadTest(BitcoinTestFramework):
peer_disconnect.peer_disconnect()
peer_disconnect.wait_for_disconnect()
peer_fallback.wait_until(lambda: peer_fallback.tx_getdata_count >= 1, timeout=1)
- with p2p_lock:
- assert_equal(peer_fallback.tx_getdata_count, 1)
def test_notfound_fallback(self):
self.log.info('Check that notfounds will select another peer for download immediately')
@@ -204,17 +201,42 @@ class TxDownloadTest(BitcoinTestFramework):
assert_equal(peer_fallback.tx_getdata_count, 0)
peer_notfound.send_and_ping(msg_notfound(vec=[CInv(MSG_WTX, WTXID)])) # Send notfound, so that fallback peer is selected
peer_fallback.wait_until(lambda: peer_fallback.tx_getdata_count >= 1, timeout=1)
- with p2p_lock:
- assert_equal(peer_fallback.tx_getdata_count, 1)
- def test_preferred_inv(self):
- self.log.info('Check that invs from preferred peers are downloaded immediately')
- self.restart_node(0, extra_args=['-whitelist=noban@127.0.0.1'])
+ def test_preferred_inv(self, preferred=False):
+ if preferred:
+ self.log.info('Check invs from preferred peers are downloaded immediately')
+ self.restart_node(0, extra_args=['-whitelist=noban@127.0.0.1'])
+ else:
+ self.log.info('Check invs from non-preferred peers are downloaded after {} s'.format(NONPREF_PEER_TX_DELAY))
+ mock_time = int(time.time() + 1)
+ self.nodes[0].setmocktime(mock_time)
peer = self.nodes[0].add_p2p_connection(TestP2PConn())
peer.send_message(msg_inv([CInv(t=MSG_WTX, h=0xff00ff00)]))
- peer.wait_until(lambda: peer.tx_getdata_count >= 1, timeout=1)
+ peer.sync_with_ping()
+ if preferred:
+ peer.wait_until(lambda: peer.tx_getdata_count >= 1, timeout=1)
+ else:
+ with p2p_lock:
+ assert_equal(peer.tx_getdata_count, 0)
+ self.nodes[0].setmocktime(mock_time + NONPREF_PEER_TX_DELAY)
+ peer.wait_until(lambda: peer.tx_getdata_count >= 1, timeout=1)
+
+ def test_txid_inv_delay(self, glob_wtxid=False):
+ self.log.info('Check that inv from a txid-relay peers are delayed by {} s, with a wtxid peer {}'.format(TXID_RELAY_DELAY, glob_wtxid))
+ self.restart_node(0, extra_args=['-whitelist=noban@127.0.0.1'])
+ mock_time = int(time.time() + 1)
+ self.nodes[0].setmocktime(mock_time)
+ peer = self.nodes[0].add_p2p_connection(TestP2PConn(wtxidrelay=False))
+ if glob_wtxid:
+ # Add a second wtxid-relay connection otherwise TXID_RELAY_DELAY is waived in
+ # lack of wtxid-relay peers
+ self.nodes[0].add_p2p_connection(TestP2PConn(wtxidrelay=True))
+ peer.send_message(msg_inv([CInv(t=MSG_TX, h=0xff11ff11)]))
+ peer.sync_with_ping()
with p2p_lock:
- assert_equal(peer.tx_getdata_count, 1)
+ assert_equal(peer.tx_getdata_count, 0 if glob_wtxid else 1)
+ self.nodes[0].setmocktime(mock_time + TXID_RELAY_DELAY)
+ peer.wait_until(lambda: peer.tx_getdata_count >= 1, timeout=1)
def test_large_inv_batch(self):
self.log.info('Test how large inv batches are handled with relay permission')
@@ -229,8 +251,6 @@ class TxDownloadTest(BitcoinTestFramework):
peer.send_message(msg_inv([CInv(t=MSG_WTX, h=wtxid) for wtxid in range(MAX_PEER_TX_ANNOUNCEMENTS + 1)]))
peer.wait_until(lambda: peer.tx_getdata_count == MAX_PEER_TX_ANNOUNCEMENTS)
peer.sync_with_ping()
- with p2p_lock:
- assert_equal(peer.tx_getdata_count, MAX_PEER_TX_ANNOUNCEMENTS)
def test_spurious_notfound(self):
self.log.info('Check that spurious notfound is ignored')
@@ -242,6 +262,9 @@ class TxDownloadTest(BitcoinTestFramework):
self.test_disconnect_fallback()
self.test_notfound_fallback()
self.test_preferred_inv()
+ self.test_preferred_inv(True)
+ self.test_txid_inv_delay()
+ self.test_txid_inv_delay(True)
self.test_large_inv_batch()
self.test_spurious_notfound()
diff --git a/test/functional/rpc_blockchain.py b/test/functional/rpc_blockchain.py
index f965677408..99be6b7b8e 100755
--- a/test/functional/rpc_blockchain.py
+++ b/test/functional/rpc_blockchain.py
@@ -20,6 +20,7 @@ Tests correspond to code in rpc/blockchain.cpp.
from decimal import Decimal
import http.client
+import os
import subprocess
from test_framework.blocktools import (
@@ -42,7 +43,9 @@ from test_framework.util import (
assert_raises_rpc_error,
assert_is_hex_string,
assert_is_hash_string,
+ get_datadir_path,
)
+from test_framework.wallet import MiniWallet
class BlockchainTest(BitcoinTestFramework):
@@ -63,6 +66,7 @@ class BlockchainTest(BitcoinTestFramework):
self._test_getnetworkhashps()
self._test_stopatheight()
self._test_waitforblockheight()
+ self._test_getblock()
assert self.nodes[0].verifychain(4, 0)
def mine_chain(self):
@@ -364,6 +368,46 @@ class BlockchainTest(BitcoinTestFramework):
assert_waitforheight(current_height)
assert_waitforheight(current_height + 1)
+ def _test_getblock(self):
+ node = self.nodes[0]
+
+ miniwallet = MiniWallet(node)
+ miniwallet.generate(5)
+ node.generate(100)
+
+ fee_per_byte = Decimal('0.00000010')
+ fee_per_kb = 1000 * fee_per_byte
+
+ miniwallet.send_self_transfer(fee_rate=fee_per_kb, from_node=node)
+ blockhash = node.generate(1)[0]
+
+ self.log.info("Test that getblock with verbosity 1 doesn't include fee")
+ block = node.getblock(blockhash, 1)
+ assert 'fee' not in block['tx'][1]
+
+ self.log.info('Test that getblock with verbosity 2 includes expected fee')
+ block = node.getblock(blockhash, 2)
+ tx = block['tx'][1]
+ assert 'fee' in tx
+ assert_equal(tx['fee'], tx['vsize'] * fee_per_byte)
+
+ self.log.info("Test that getblock with verbosity 2 still works with pruned Undo data")
+ datadir = get_datadir_path(self.options.tmpdir, 0)
+
+ def move_block_file(old, new):
+ old_path = os.path.join(datadir, self.chain, 'blocks', old)
+ new_path = os.path.join(datadir, self.chain, 'blocks', new)
+ os.rename(old_path, new_path)
+
+ # Move instead of deleting so we can restore chain state afterwards
+ move_block_file('rev00000.dat', 'rev_wrong')
+
+ block = node.getblock(blockhash, 2)
+ assert 'fee' not in block['tx'][1]
+
+ # Restore chain state
+ move_block_file('rev_wrong', 'rev00000.dat')
+
if __name__ == '__main__':
BlockchainTest().main()
diff --git a/test/functional/rpc_getpeerinfo_deprecation.py b/test/functional/rpc_getpeerinfo_deprecation.py
deleted file mode 100755
index 340a66e12f..0000000000
--- a/test/functional/rpc_getpeerinfo_deprecation.py
+++ /dev/null
@@ -1,38 +0,0 @@
-#!/usr/bin/env python3
-# Copyright (c) 2020 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 getpeerinfo RPC fields."""
-
-from test_framework.test_framework import BitcoinTestFramework
-
-
-class GetpeerinfoDeprecationTest(BitcoinTestFramework):
- def set_test_params(self):
- self.num_nodes = 2
- self.extra_args = [[], ["-deprecatedrpc=banscore"]]
-
- def run_test(self):
- self.test_banscore_deprecation()
- self.test_addnode_deprecation()
-
- def test_banscore_deprecation(self):
- self.log.info("Test getpeerinfo by default no longer returns a banscore field")
- assert "banscore" not in self.nodes[0].getpeerinfo()[0].keys()
-
- self.log.info("Test getpeerinfo returns banscore with -deprecatedrpc=banscore")
- assert "banscore" in self.nodes[1].getpeerinfo()[0].keys()
-
- def test_addnode_deprecation(self):
- self.restart_node(1, ["-deprecatedrpc=getpeerinfo_addnode"])
- self.connect_nodes(0, 1)
-
- self.log.info("Test getpeerinfo by default no longer returns an addnode field")
- assert "addnode" not in self.nodes[0].getpeerinfo()[0].keys()
-
- self.log.info("Test getpeerinfo returns addnode with -deprecatedrpc=addnode")
- assert "addnode" in self.nodes[1].getpeerinfo()[0].keys()
-
-
-if __name__ == "__main__":
- GetpeerinfoDeprecationTest().main()
diff --git a/test/functional/test_framework/p2p.py b/test/functional/test_framework/p2p.py
index 8b79a4dc2f..ea769ddfa2 100755
--- a/test/functional/test_framework/p2p.py
+++ b/test/functional/test_framework/p2p.py
@@ -289,7 +289,7 @@ class P2PInterface(P2PConnection):
Individual testcases should subclass this and override the on_* methods
if they want to alter message handling behaviour."""
- def __init__(self, support_addrv2=False):
+ def __init__(self, support_addrv2=False, wtxidrelay=True):
super().__init__()
# Track number of messages of each type received.
@@ -309,6 +309,9 @@ class P2PInterface(P2PConnection):
self.support_addrv2 = support_addrv2
+ # If the peer supports wtxid-relay
+ self.wtxidrelay = wtxidrelay
+
def peer_connect(self, *args, services=NODE_NETWORK|NODE_WITNESS, send_version=True, **kwargs):
create_conn = super().peer_connect(*args, **kwargs)
@@ -394,7 +397,7 @@ class P2PInterface(P2PConnection):
def on_version(self, message):
assert message.nVersion >= MIN_VERSION_SUPPORTED, "Version {} received. Test framework only supports versions greater than {}".format(message.nVersion, MIN_VERSION_SUPPORTED)
- if message.nVersion >= 70016:
+ if message.nVersion >= 70016 and self.wtxidrelay:
self.send_message(msg_wtxidrelay())
if self.support_addrv2:
self.send_message(msg_sendaddrv2())
diff --git a/test/functional/test_framework/script.py b/test/functional/test_framework/script.py
index 26ccab3039..be0e9f24e2 100644
--- a/test/functional/test_framework/script.py
+++ b/test/functional/test_framework/script.py
@@ -787,7 +787,7 @@ def TaprootSignatureHash(txTo, spent_utxos, hash_type, input_index = 0, scriptpa
def taproot_tree_helper(scripts):
if len(scripts) == 0:
- return ([], bytes(0 for _ in range(32)))
+ return ([], bytes())
if len(scripts) == 1:
# One entry: treat as a leaf
script = scripts[0]
diff --git a/test/functional/test_framework/test_framework.py b/test/functional/test_framework/test_framework.py
index bf047c5f68..9e6e584dc8 100755
--- a/test/functional/test_framework/test_framework.py
+++ b/test/functional/test_framework/test_framework.py
@@ -332,7 +332,7 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
# Methods to override in subclass test scripts.
def set_test_params(self):
- """Tests must this method to change default values for number of nodes, topology, etc"""
+ """Tests must override this method to change default values for number of nodes, topology, etc"""
raise NotImplementedError
def add_options(self, parser):
@@ -517,13 +517,12 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass):
def stop_node(self, i, expected_stderr='', wait=0):
"""Stop a bitcoind test node"""
self.nodes[i].stop_node(expected_stderr, wait=wait)
- self.nodes[i].wait_until_stopped()
def stop_nodes(self, wait=0):
"""Stop multiple bitcoind test nodes"""
for node in self.nodes:
# Issue RPC to stop nodes
- node.stop_node(wait=wait)
+ node.stop_node(wait=wait, wait_until_stopped=False)
for node in self.nodes:
# Wait for nodes to stop
diff --git a/test/functional/test_framework/test_node.py b/test/functional/test_framework/test_node.py
index a618706a77..e10ec1328b 100755
--- a/test/functional/test_framework/test_node.py
+++ b/test/functional/test_framework/test_node.py
@@ -308,7 +308,7 @@ class TestNode():
def version_is_at_least(self, ver):
return self.version is None or self.version >= ver
- def stop_node(self, expected_stderr='', wait=0):
+ def stop_node(self, expected_stderr='', *, wait=0, wait_until_stopped=True):
"""Stop the node."""
if not self.running:
return
@@ -337,6 +337,9 @@ class TestNode():
del self.p2ps[:]
+ if wait_until_stopped:
+ self.wait_until_stopped()
+
def is_node_stopped(self):
"""Checks whether the node has stopped.
diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py
index 5b3db282e1..261c1f0a1b 100755
--- a/test/functional/test_runner.py
+++ b/test/functional/test_runner.py
@@ -279,7 +279,6 @@ BASE_SCRIPTS = [
'feature_config_args.py',
'feature_settings.py',
'rpc_getdescriptorinfo.py',
- 'rpc_getpeerinfo_deprecation.py',
'rpc_help.py',
'feature_help.py',
'feature_shutdown.py',
diff --git a/test/functional/tool_wallet.py b/test/functional/tool_wallet.py
index 615b772dc8..8a1af24dcf 100755
--- a/test/functional/tool_wallet.py
+++ b/test/functional/tool_wallet.py
@@ -10,6 +10,8 @@ import stat
import subprocess
import textwrap
+from collections import OrderedDict
+
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import assert_equal
@@ -28,8 +30,11 @@ class ToolWalletTest(BitcoinTestFramework):
def bitcoin_wallet_process(self, *args):
binary = self.config["environment"]["BUILDDIR"] + '/src/bitcoin-wallet' + self.config["environment"]["EXEEXT"]
- args = ['-datadir={}'.format(self.nodes[0].datadir), '-chain=%s' % self.chain] + list(args)
- return subprocess.Popen([binary] + args, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True)
+ default_args = ['-datadir={}'.format(self.nodes[0].datadir), '-chain=%s' % self.chain]
+ if self.options.descriptors and 'create' in args:
+ default_args.append('-descriptors')
+
+ return subprocess.Popen([binary] + default_args + list(args), stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True)
def assert_raises_tool_error(self, error, *args):
p = self.bitcoin_wallet_process(*args)
@@ -63,6 +68,119 @@ class ToolWalletTest(BitcoinTestFramework):
result = 'unchanged' if new == old else 'increased!'
self.log.debug('Wallet file timestamp {}'.format(result))
+ def get_expected_info_output(self, name="", transactions=0, keypool=2, address=0):
+ wallet_name = self.default_wallet_name if name == "" else name
+ output_types = 3 # p2pkh, p2sh, segwit
+ if self.options.descriptors:
+ return textwrap.dedent('''\
+ Wallet info
+ ===========
+ Name: %s
+ Format: sqlite
+ Descriptors: yes
+ Encrypted: no
+ HD (hd seed available): yes
+ Keypool Size: %d
+ Transactions: %d
+ Address Book: %d
+ ''' % (wallet_name, keypool * output_types, transactions, address))
+ else:
+ return textwrap.dedent('''\
+ Wallet info
+ ===========
+ Name: %s
+ Format: bdb
+ Descriptors: no
+ Encrypted: no
+ HD (hd seed available): yes
+ Keypool Size: %d
+ Transactions: %d
+ Address Book: %d
+ ''' % (wallet_name, keypool, transactions, address * output_types))
+
+ def read_dump(self, filename):
+ dump = OrderedDict()
+ with open(filename, "r", encoding="utf8") as f:
+ for row in f:
+ row = row.strip()
+ key, value = row.split(',')
+ dump[key] = value
+ return dump
+
+ def assert_is_sqlite(self, filename):
+ with open(filename, 'rb') as f:
+ file_magic = f.read(16)
+ assert file_magic == b'SQLite format 3\x00'
+
+ def assert_is_bdb(self, filename):
+ with open(filename, 'rb') as f:
+ f.seek(12, 0)
+ file_magic = f.read(4)
+ assert file_magic == b'\x00\x05\x31\x62' or file_magic == b'\x62\x31\x05\x00'
+
+ def write_dump(self, dump, filename, magic=None, skip_checksum=False):
+ if magic is None:
+ magic = "BITCOIN_CORE_WALLET_DUMP"
+ with open(filename, "w", encoding="utf8") as f:
+ row = ",".join([magic, dump[magic]]) + "\n"
+ f.write(row)
+ for k, v in dump.items():
+ if k == magic or k == "checksum":
+ continue
+ row = ",".join([k, v]) + "\n"
+ f.write(row)
+ if not skip_checksum:
+ row = ",".join(["checksum", dump["checksum"]]) + "\n"
+ f.write(row)
+
+ def assert_dump(self, expected, received):
+ e = expected.copy()
+ r = received.copy()
+
+ # BDB will add a "version" record that is not present in sqlite
+ # In that case, we should ignore this record in both
+ # But because this also effects the checksum, we also need to drop that.
+ v_key = "0776657273696f6e" # Version key
+ if v_key in e and v_key not in r:
+ del e[v_key]
+ del e["checksum"]
+ del r["checksum"]
+ if v_key not in e and v_key in r:
+ del r[v_key]
+ del e["checksum"]
+ del r["checksum"]
+
+ assert_equal(len(e), len(r))
+ for k, v in e.items():
+ assert_equal(v, r[k])
+
+ def do_tool_createfromdump(self, wallet_name, dumpfile, file_format=None):
+ dumppath = os.path.join(self.nodes[0].datadir, dumpfile)
+ rt_dumppath = os.path.join(self.nodes[0].datadir, "rt-{}.dump".format(wallet_name))
+
+ dump_data = self.read_dump(dumppath)
+
+ args = ["-wallet={}".format(wallet_name),
+ "-dumpfile={}".format(dumppath)]
+ if file_format is not None:
+ args.append("-format={}".format(file_format))
+ args.append("createfromdump")
+
+ load_output = ""
+ if file_format is not None and file_format != dump_data["format"]:
+ load_output += "Warning: Dumpfile wallet format \"{}\" does not match command line specified format \"{}\".\n".format(dump_data["format"], file_format)
+ self.assert_tool_output(load_output, *args)
+ assert os.path.isdir(os.path.join(self.nodes[0].datadir, "regtest/wallets", wallet_name))
+
+ self.assert_tool_output("The dumpfile may contain private keys. To ensure the safety of your Bitcoin, do not share the dumpfile.\n", '-wallet={}'.format(wallet_name), '-dumpfile={}'.format(rt_dumppath), 'dump')
+
+ rt_dump_data = self.read_dump(rt_dumppath)
+ wallet_dat = os.path.join(self.nodes[0].datadir, "regtest/wallets/", wallet_name, "wallet.dat")
+ if rt_dump_data["format"] == "bdb":
+ self.assert_is_bdb(wallet_dat)
+ else:
+ self.assert_is_sqlite(wallet_dat)
+
def test_invalid_tool_commands_and_args(self):
self.log.info('Testing that various invalid commands raise with specific error messages')
self.assert_raises_tool_error('Invalid command: foo', 'foo')
@@ -98,33 +216,7 @@ class ToolWalletTest(BitcoinTestFramework):
# shasum_before = self.wallet_shasum()
timestamp_before = self.wallet_timestamp()
self.log.debug('Wallet file timestamp before calling info: {}'.format(timestamp_before))
- if self.options.descriptors:
- out = textwrap.dedent('''\
- Wallet info
- ===========
- Name: default_wallet
- Format: sqlite
- Descriptors: yes
- Encrypted: no
- HD (hd seed available): yes
- Keypool Size: 6
- Transactions: 0
- Address Book: 1
- ''')
- else:
- out = textwrap.dedent('''\
- Wallet info
- ===========
- Name: \
-
- Format: bdb
- Descriptors: no
- Encrypted: no
- HD (hd seed available): yes
- Keypool Size: 2
- Transactions: 0
- Address Book: 3
- ''')
+ out = self.get_expected_info_output(address=1)
self.assert_tool_output(out, '-wallet=' + self.default_wallet_name, 'info')
timestamp_after = self.wallet_timestamp()
self.log.debug('Wallet file timestamp after calling info: {}'.format(timestamp_after))
@@ -155,33 +247,7 @@ class ToolWalletTest(BitcoinTestFramework):
shasum_before = self.wallet_shasum()
timestamp_before = self.wallet_timestamp()
self.log.debug('Wallet file timestamp before calling info: {}'.format(timestamp_before))
- if self.options.descriptors:
- out = textwrap.dedent('''\
- Wallet info
- ===========
- Name: default_wallet
- Format: sqlite
- Descriptors: yes
- Encrypted: no
- HD (hd seed available): yes
- Keypool Size: 6
- Transactions: 1
- Address Book: 1
- ''')
- else:
- out = textwrap.dedent('''\
- Wallet info
- ===========
- Name: \
-
- Format: bdb
- Descriptors: no
- Encrypted: no
- HD (hd seed available): yes
- Keypool Size: 2
- Transactions: 1
- Address Book: 3
- ''')
+ out = self.get_expected_info_output(transactions=1, address=1)
self.assert_tool_output(out, '-wallet=' + self.default_wallet_name, 'info')
shasum_after = self.wallet_shasum()
timestamp_after = self.wallet_timestamp()
@@ -199,19 +265,7 @@ class ToolWalletTest(BitcoinTestFramework):
shasum_before = self.wallet_shasum()
timestamp_before = self.wallet_timestamp()
self.log.debug('Wallet file timestamp before calling create: {}'.format(timestamp_before))
- out = textwrap.dedent('''\
- Topping up keypool...
- Wallet info
- ===========
- Name: foo
- Format: bdb
- Descriptors: no
- Encrypted: no
- HD (hd seed available): yes
- Keypool Size: 2000
- Transactions: 0
- Address Book: 0
- ''')
+ out = "Topping up keypool...\n" + self.get_expected_info_output(name="foo", keypool=2000)
self.assert_tool_output(out, '-wallet=foo', 'create')
shasum_after = self.wallet_shasum()
timestamp_after = self.wallet_timestamp()
@@ -237,9 +291,13 @@ class ToolWalletTest(BitcoinTestFramework):
self.log.debug('Wallet file timestamp after calling getwalletinfo: {}'.format(timestamp_after))
assert_equal(0, out['txcount'])
- assert_equal(1000, out['keypoolsize'])
- assert_equal(1000, out['keypoolsize_hd_internal'])
- assert_equal(True, 'hdseedid' in out)
+ if not self.options.descriptors:
+ assert_equal(1000, out['keypoolsize'])
+ assert_equal(1000, out['keypoolsize_hd_internal'])
+ assert_equal(True, 'hdseedid' in out)
+ else:
+ assert_equal(3000, out['keypoolsize'])
+ assert_equal(3000, out['keypoolsize_hd_internal'])
self.log_wallet_timestamp_comparison(timestamp_before, timestamp_after)
assert_equal(timestamp_before, timestamp_after)
@@ -255,18 +313,95 @@ class ToolWalletTest(BitcoinTestFramework):
self.assert_tool_output('', '-wallet=salvage', 'salvage')
+ def test_dump_createfromdump(self):
+ self.start_node(0)
+ self.nodes[0].createwallet("todump")
+ file_format = self.nodes[0].get_wallet_rpc("todump").getwalletinfo()["format"]
+ self.nodes[0].createwallet("todump2")
+ self.stop_node(0)
+
+ self.log.info('Checking dump arguments')
+ self.assert_raises_tool_error('No dump file provided. To use dump, -dumpfile=<filename> must be provided.', '-wallet=todump', 'dump')
+
+ self.log.info('Checking basic dump')
+ wallet_dump = os.path.join(self.nodes[0].datadir, "wallet.dump")
+ self.assert_tool_output('The dumpfile may contain private keys. To ensure the safety of your Bitcoin, do not share the dumpfile.\n', '-wallet=todump', '-dumpfile={}'.format(wallet_dump), 'dump')
+
+ dump_data = self.read_dump(wallet_dump)
+ orig_dump = dump_data.copy()
+ # Check the dump magic
+ assert_equal(dump_data['BITCOIN_CORE_WALLET_DUMP'], '1')
+ # Check the file format
+ assert_equal(dump_data["format"], file_format)
+
+ self.log.info('Checking that a dumpfile cannot be overwritten')
+ self.assert_raises_tool_error('File {} already exists. If you are sure this is what you want, move it out of the way first.'.format(wallet_dump), '-wallet=todump2', '-dumpfile={}'.format(wallet_dump), 'dump')
+
+ self.log.info('Checking createfromdump arguments')
+ self.assert_raises_tool_error('No dump file provided. To use createfromdump, -dumpfile=<filename> must be provided.', '-wallet=todump', 'createfromdump')
+ non_exist_dump = os.path.join(self.nodes[0].datadir, "wallet.nodump")
+ self.assert_raises_tool_error('Unknown wallet file format "notaformat" provided. Please provide one of "bdb" or "sqlite".', '-wallet=todump', '-format=notaformat', '-dumpfile={}'.format(wallet_dump), 'createfromdump')
+ self.assert_raises_tool_error('Dump file {} does not exist.'.format(non_exist_dump), '-wallet=todump', '-dumpfile={}'.format(non_exist_dump), 'createfromdump')
+ wallet_path = os.path.join(self.nodes[0].datadir, 'regtest/wallets/todump2')
+ self.assert_raises_tool_error('Failed to create database path \'{}\'. Database already exists.'.format(wallet_path), '-wallet=todump2', '-dumpfile={}'.format(wallet_dump), 'createfromdump')
+ self.assert_raises_tool_error("The -descriptors option can only be used with the 'create' command.", '-descriptors', '-wallet=todump2', '-dumpfile={}'.format(wallet_dump), 'createfromdump')
+
+ self.log.info('Checking createfromdump')
+ self.do_tool_createfromdump("load", "wallet.dump")
+ self.do_tool_createfromdump("load-bdb", "wallet.dump", "bdb")
+ if self.is_sqlite_compiled():
+ self.do_tool_createfromdump("load-sqlite", "wallet.dump", "sqlite")
+
+ self.log.info('Checking createfromdump handling of magic and versions')
+ bad_ver_wallet_dump = os.path.join(self.nodes[0].datadir, "wallet-bad_ver1.dump")
+ dump_data["BITCOIN_CORE_WALLET_DUMP"] = "0"
+ self.write_dump(dump_data, bad_ver_wallet_dump)
+ self.assert_raises_tool_error('Error: Dumpfile version is not supported. This version of bitcoin-wallet only supports version 1 dumpfiles. Got dumpfile with version 0', '-wallet=badload', '-dumpfile={}'.format(bad_ver_wallet_dump), 'createfromdump')
+ assert not os.path.isdir(os.path.join(self.nodes[0].datadir, "regtest/wallets", "badload"))
+ bad_ver_wallet_dump = os.path.join(self.nodes[0].datadir, "wallet-bad_ver2.dump")
+ dump_data["BITCOIN_CORE_WALLET_DUMP"] = "2"
+ self.write_dump(dump_data, bad_ver_wallet_dump)
+ self.assert_raises_tool_error('Error: Dumpfile version is not supported. This version of bitcoin-wallet only supports version 1 dumpfiles. Got dumpfile with version 2', '-wallet=badload', '-dumpfile={}'.format(bad_ver_wallet_dump), 'createfromdump')
+ assert not os.path.isdir(os.path.join(self.nodes[0].datadir, "regtest/wallets", "badload"))
+ bad_magic_wallet_dump = os.path.join(self.nodes[0].datadir, "wallet-bad_magic.dump")
+ del dump_data["BITCOIN_CORE_WALLET_DUMP"]
+ dump_data["not_the_right_magic"] = "1"
+ self.write_dump(dump_data, bad_magic_wallet_dump, "not_the_right_magic")
+ self.assert_raises_tool_error('Error: Dumpfile identifier record is incorrect. Got "not_the_right_magic", expected "BITCOIN_CORE_WALLET_DUMP".', '-wallet=badload', '-dumpfile={}'.format(bad_magic_wallet_dump), 'createfromdump')
+ assert not os.path.isdir(os.path.join(self.nodes[0].datadir, "regtest/wallets", "badload"))
+
+ self.log.info('Checking createfromdump handling of checksums')
+ bad_sum_wallet_dump = os.path.join(self.nodes[0].datadir, "wallet-bad_sum1.dump")
+ dump_data = orig_dump.copy()
+ checksum = dump_data["checksum"]
+ dump_data["checksum"] = "1" * 64
+ self.write_dump(dump_data, bad_sum_wallet_dump)
+ self.assert_raises_tool_error('Error: Dumpfile checksum does not match. Computed {}, expected {}'.format(checksum, "1" * 64), '-wallet=bad', '-dumpfile={}'.format(bad_sum_wallet_dump), 'createfromdump')
+ assert not os.path.isdir(os.path.join(self.nodes[0].datadir, "regtest/wallets", "badload"))
+ bad_sum_wallet_dump = os.path.join(self.nodes[0].datadir, "wallet-bad_sum2.dump")
+ del dump_data["checksum"]
+ self.write_dump(dump_data, bad_sum_wallet_dump, skip_checksum=True)
+ self.assert_raises_tool_error('Error: Missing checksum', '-wallet=badload', '-dumpfile={}'.format(bad_sum_wallet_dump), 'createfromdump')
+ assert not os.path.isdir(os.path.join(self.nodes[0].datadir, "regtest/wallets", "badload"))
+ bad_sum_wallet_dump = os.path.join(self.nodes[0].datadir, "wallet-bad_sum3.dump")
+ dump_data["checksum"] = "2" * 10
+ self.write_dump(dump_data, bad_sum_wallet_dump)
+ self.assert_raises_tool_error('Error: Dumpfile checksum does not match. Computed {}, expected {}{}'.format(checksum, "2" * 10, "0" * 54), '-wallet=badload', '-dumpfile={}'.format(bad_sum_wallet_dump), 'createfromdump')
+ assert not os.path.isdir(os.path.join(self.nodes[0].datadir, "regtest/wallets", "badload"))
+
+
def run_test(self):
self.wallet_path = os.path.join(self.nodes[0].datadir, self.chain, 'wallets', self.default_wallet_name, self.wallet_data_filename)
self.test_invalid_tool_commands_and_args()
# Warning: The following tests are order-dependent.
self.test_tool_wallet_info()
self.test_tool_wallet_info_after_transaction()
+ self.test_tool_wallet_create_on_existing_wallet()
+ self.test_getwalletinfo_on_different_wallet()
if not self.options.descriptors:
- # TODO: Wallet tool needs more create options at which point these can be enabled.
- self.test_tool_wallet_create_on_existing_wallet()
- self.test_getwalletinfo_on_different_wallet()
# Salvage is a legacy wallet only thing
self.test_salvage()
+ self.test_dump_createfromdump()
if __name__ == '__main__':
ToolWalletTest().main()
diff --git a/test/functional/wallet_multiwallet.py b/test/functional/wallet_multiwallet.py
index fb4532bcf6..bb89e76a9a 100755
--- a/test/functional/wallet_multiwallet.py
+++ b/test/functional/wallet_multiwallet.py
@@ -23,9 +23,11 @@ from test_framework.util import (
)
got_loading_error = False
+
+
def test_load_unload(node, name):
global got_loading_error
- for _ in range(10):
+ while True:
if got_loading_error:
return
try:
@@ -68,7 +70,7 @@ class MultiWalletTest(BitcoinTestFramework):
return wallet_dir(name, "wallet.dat")
return wallet_dir(name)
- assert_equal(self.nodes[0].listwalletdir(), { 'wallets': [{ 'name': self.default_wallet_name }] })
+ assert_equal(self.nodes[0].listwalletdir(), {'wallets': [{'name': self.default_wallet_name}]})
# check wallet.dat is created
self.stop_nodes()
@@ -278,7 +280,7 @@ class MultiWalletTest(BitcoinTestFramework):
threads = []
for _ in range(3):
n = node.cli if self.options.usecli else get_rpc_proxy(node.url, 1, timeout=600, coveragedir=node.coverage_dir)
- t = Thread(target=test_load_unload, args=(n, wallet_names[2], ))
+ t = Thread(target=test_load_unload, args=(n, wallet_names[2]))
t.start()
threads.append(t)
for t in threads:
diff --git a/test/fuzz/test_runner.py b/test/fuzz/test_runner.py
index 3a2cefbe2b..3c743603bb 100755
--- a/test/fuzz/test_runner.py
+++ b/test/fuzz/test_runner.py
@@ -54,7 +54,7 @@ def main():
)
parser.add_argument(
'--m_dir',
- help='Merge inputs from this directory into the seed_dir. Needs /target subdirectory.',
+ help='Merge inputs from this directory into the seed_dir.',
)
parser.add_argument(
'-g',
@@ -210,7 +210,7 @@ def generate_corpus_seeds(*, fuzz_pool, build_dir, seed_dir, targets):
def merge_inputs(*, fuzz_pool, corpus, test_list, build_dir, merge_dir):
- logging.info("Merge the inputs in the passed dir into the seed_dir. Passed dir {}".format(merge_dir))
+ logging.info("Merge the inputs from the passed dir into the seed_dir. Passed dir {}".format(merge_dir))
jobs = []
for t in test_list:
args = [
diff --git a/test/lint/lint-git-commit-check.sh b/test/lint/lint-git-commit-check.sh
index ecaad215c4..2b3a9b87c2 100755
--- a/test/lint/lint-git-commit-check.sh
+++ b/test/lint/lint-git-commit-check.sh
@@ -23,13 +23,6 @@ while getopts "?" opt; do
esac
done
-# TRAVIS_BRANCH will be present in a Travis environment. For builds triggered
-# by a pull request this is the name of the branch targeted by the pull request.
-# https://docs.travis-ci.com/user/environment-variables/
-if [ -n "${TRAVIS_BRANCH}" ]; then
- COMMIT_RANGE="$TRAVIS_BRANCH..HEAD"
-fi
-
if [ -z "${COMMIT_RANGE}" ]; then
if [ -n "$1" ]; then
COMMIT_RANGE="HEAD~$1...HEAD"
diff --git a/test/lint/lint-includes.sh b/test/lint/lint-includes.sh
index fde77aea2d..393f734abe 100755
--- a/test/lint/lint-includes.sh
+++ b/test/lint/lint-includes.sh
@@ -60,7 +60,6 @@ EXPECTED_BOOST_INCLUDES=(
boost/multi_index/ordered_index.hpp
boost/multi_index/sequenced_index.hpp
boost/multi_index_container.hpp
- boost/optional.hpp
boost/preprocessor/cat.hpp
boost/preprocessor/stringize.hpp
boost/process.hpp
diff --git a/test/lint/lint-python.sh b/test/lint/lint-python.sh
index 4fc130497b..f83c33cb32 100755
--- a/test/lint/lint-python.sh
+++ b/test/lint/lint-python.sh
@@ -102,7 +102,7 @@ if ! PYTHONWARNINGS="ignore" flake8 --ignore=B,C,E,F,I,N,W --select=$(IFS=","; e
EXIT_CODE=1
fi
-if ! mypy --ignore-missing-imports $(git ls-files "test/functional/*.py"); then
+if ! mypy --ignore-missing-imports $(git ls-files "test/functional/*.py" "contrib/devtools/*.py"); then
EXIT_CODE=1
fi
diff --git a/test/lint/lint-shell.sh b/test/lint/lint-shell.sh
index 351b65dea6..4dbf5ed28e 100755
--- a/test/lint/lint-shell.sh
+++ b/test/lint/lint-shell.sh
@@ -8,14 +8,6 @@
export LC_ALL=C
-# The shellcheck binary segfault/coredumps in Travis with LC_ALL=C
-# It does not do so in Ubuntu 14.04, 16.04, 18.04 in versions 0.3.3, 0.3.7, 0.4.6
-# respectively. So export LC_ALL=C is set as required by lint-shell-locale.sh
-# but unset here in case of running in Travis.
-if [ "$TRAVIS" = "true" ]; then
- unset LC_ALL
-fi
-
# Disabled warnings:
disabled=(
SC2046 # Quote this to prevent word splitting.
diff --git a/test/lint/lint-whitespace.sh b/test/lint/lint-whitespace.sh
index 80af0a439d..2c42846e67 100755
--- a/test/lint/lint-whitespace.sh
+++ b/test/lint/lint-whitespace.sh
@@ -22,13 +22,6 @@ while getopts "?" opt; do
esac
done
-# TRAVIS_BRANCH will be present in a Travis environment. For builds triggered
-# by a pull request this is the name of the branch targeted by the pull request.
-# https://docs.travis-ci.com/user/environment-variables/
-if [ -n "${TRAVIS_BRANCH}" ]; then
- COMMIT_RANGE="$TRAVIS_BRANCH..HEAD"
-fi
-
if [ -z "${COMMIT_RANGE}" ]; then
if [ -n "$1" ]; then
COMMIT_RANGE="HEAD~$1...HEAD"
diff --git a/test/sanitizer_suppressions/tsan b/test/sanitizer_suppressions/tsan
index 986e096056..29221a94f2 100644
--- a/test/sanitizer_suppressions/tsan
+++ b/test/sanitizer_suppressions/tsan
@@ -1,5 +1,7 @@
# ThreadSanitizer suppressions
# ============================
+#
+# https://github.com/google/sanitizers/wiki/ThreadSanitizerSuppressions
# double locks (TODO fix)
mutex:g_genesis_wait_mutex
@@ -13,6 +15,7 @@ mutex:CConnman::SocketHandler
mutex:UpdateTip
mutex:PeerManager::UpdatedBlockTip
mutex:g_best_block_mutex
+
# race (TODO fix)
race:CConnman::WakeMessageHandler
race:CConnman::ThreadMessageHandler
@@ -27,14 +30,9 @@ race:DatabaseBatch
race:leveldb::DBImpl::DeleteObsoleteFiles
race:zmq::*
race:bitcoin-qt
+
# deadlock (TODO fix)
-deadlock:CConnman::ForNode
-deadlock:CConnman::GetNodeStats
deadlock:CChainState::ConnectTip
-deadlock:UpdateTip
-
-# WalletBatch (unidentified deadlock)
-deadlock:WalletBatch
# Intentional deadlock in tests
deadlock:TestPotentialDeadLockDetected
@@ -46,4 +44,15 @@ deadlock:src/qt/test/*
# External libraries
deadlock:libdb
race:libzmq
-race:epoll_ctl # https://github.com/bitcoin/bitcoin/pull/20218
+
+# Intermittent issues
+# -------------------
+#
+# Suppressions that follow might only happen intermittently, thus they are not
+# reproducible. Make sure to include a link to a full trace.
+
+# https://github.com/bitcoin/bitcoin/issues/20618
+race:CZMQAbstractPublishNotifier::SendZmqMessage
+
+# https://github.com/bitcoin/bitcoin/pull/20218, https://github.com/bitcoin/bitcoin/pull/20745
+race:epoll_ctl