aboutsummaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rwxr-xr-xtest/functional/feature_bip68_sequence.py5
-rwxr-xr-xtest/functional/feature_maxuploadtarget.py17
-rwxr-xr-xtest/functional/p2p_blocksonly.py17
-rwxr-xr-xtest/functional/p2p_leak.py23
-rwxr-xr-xtest/functional/p2p_permissions.py25
-rwxr-xr-xtest/functional/p2p_ping.py123
-rwxr-xr-xtest/functional/p2p_unrequested_blocks.py12
-rwxr-xr-xtest/functional/rpc_blockchain.py11
-rwxr-xr-xtest/functional/rpc_getpeerinfo_banscore_deprecation.py24
-rwxr-xr-xtest/functional/rpc_psbt.py8
-rwxr-xr-xtest/functional/rpc_rawtransaction.py3
-rw-r--r--test/functional/test_framework/authproxy.py2
-rwxr-xr-xtest/functional/test_framework/messages.py14
-rwxr-xr-xtest/functional/test_runner.py9
-rwxr-xr-xtest/functional/tool_wallet.py3
-rwxr-xr-xtest/functional/wallet_basic.py7
-rwxr-xr-xtest/functional/wallet_dump.py5
-rwxr-xr-xtest/functional/wallet_encryption.py16
-rwxr-xr-xtest/functional/wallet_fallbackfee.py2
-rwxr-xr-xtest/functional/wallet_importdescriptors.py12
-rw-r--r--test/lint/README.md6
-rwxr-xr-xtest/lint/git-subtree-check.sh2
-rwxr-xr-xtest/lint/lint-assertions.sh2
-rwxr-xr-xtest/lint/lint-includes.sh2
-rwxr-xr-xtest/lint/lint-locale-dependence.sh1
-rw-r--r--test/sanitizer_suppressions/tsan2
26 files changed, 282 insertions, 71 deletions
diff --git a/test/functional/feature_bip68_sequence.py b/test/functional/feature_bip68_sequence.py
index 549e8b2029..19cdc10935 100755
--- a/test/functional/feature_bip68_sequence.py
+++ b/test/functional/feature_bip68_sequence.py
@@ -30,7 +30,10 @@ class BIP68Test(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 2
self.extra_args = [
- ["-acceptnonstdtxn=1"],
+ [
+ "-acceptnonstdtxn=1",
+ "-peertimeout=9999", # bump because mocktime might cause a disconnect otherwise
+ ],
["-acceptnonstdtxn=0"],
]
diff --git a/test/functional/feature_maxuploadtarget.py b/test/functional/feature_maxuploadtarget.py
index 7eabf86cad..5538d6d3b4 100755
--- a/test/functional/feature_maxuploadtarget.py
+++ b/test/functional/feature_maxuploadtarget.py
@@ -35,7 +35,11 @@ class MaxUploadTest(BitcoinTestFramework):
def set_test_params(self):
self.setup_clean_chain = True
self.num_nodes = 1
- self.extra_args = [["-maxuploadtarget=800", "-acceptnonstdtxn=1"]]
+ self.extra_args = [[
+ "-maxuploadtarget=800",
+ "-acceptnonstdtxn=1",
+ "-peertimeout=9999", # bump because mocktime might cause a disconnect otherwise
+ ]]
self.supports_cli = False
# Cache for utxos, as the listunspent may take a long time later in the test
@@ -137,8 +141,8 @@ class MaxUploadTest(BitcoinTestFramework):
self.nodes[0].disconnect_p2ps()
- self.log.info("Restarting node 0 with noban permission and 1MB maxuploadtarget")
- self.restart_node(0, ["-whitelist=noban@127.0.0.1", "-maxuploadtarget=1"])
+ self.log.info("Restarting node 0 with download permission and 1MB maxuploadtarget")
+ self.restart_node(0, ["-whitelist=download@127.0.0.1", "-maxuploadtarget=1"])
# Reconnect to self.nodes[0]
self.nodes[0].add_p2p_connection(TestP2PConn())
@@ -151,9 +155,12 @@ class MaxUploadTest(BitcoinTestFramework):
getdata_request.inv = [CInv(MSG_BLOCK, big_old_block)]
self.nodes[0].p2p.send_and_ping(getdata_request)
- assert_equal(len(self.nodes[0].getpeerinfo()), 1) #node is still connected because of the noban permission
- self.log.info("Peer still connected after trying to download old block (noban permission)")
+ self.log.info("Peer still connected after trying to download old block (download permission)")
+ peer_info = self.nodes[0].getpeerinfo()
+ assert_equal(len(peer_info), 1) # node is still connected
+ assert_equal(peer_info[0]['permissions'], ['download'])
+
if __name__ == '__main__':
MaxUploadTest().main()
diff --git a/test/functional/p2p_blocksonly.py b/test/functional/p2p_blocksonly.py
index c155dda664..f42a343042 100755
--- a/test/functional/p2p_blocksonly.py
+++ b/test/functional/p2p_blocksonly.py
@@ -57,29 +57,30 @@ class P2PBlocksOnly(BitcoinTestFramework):
self.nodes[0].p2p.wait_for_tx(txid)
assert_equal(self.nodes[0].getmempoolinfo()['size'], 1)
- self.log.info('Check that txs from whitelisted peers are not rejected and relayed to others')
- self.log.info("Restarting node 0 with whitelist permission and blocksonly")
+ self.log.info('Check that txs from forcerelay peers are not rejected and relayed to others')
+ self.log.info("Restarting node 0 with forcerelay permission and blocksonly")
self.restart_node(0, ["-persistmempool=0", "-whitelist=127.0.0.1", "-whitelistforcerelay", "-blocksonly"])
- assert_equal(self.nodes[0].getrawmempool(),[])
+ assert_equal(self.nodes[0].getrawmempool(), [])
first_peer = self.nodes[0].add_p2p_connection(P2PInterface())
second_peer = self.nodes[0].add_p2p_connection(P2PInterface())
peer_1_info = self.nodes[0].getpeerinfo()[0]
assert_equal(peer_1_info['whitelisted'], True)
- assert_equal(peer_1_info['permissions'], ['noban', 'forcerelay', 'relay', 'mempool'])
+ assert_equal(peer_1_info['permissions'], ['noban', 'forcerelay', 'relay', 'mempool', 'download'])
peer_2_info = self.nodes[0].getpeerinfo()[1]
assert_equal(peer_2_info['whitelisted'], True)
- assert_equal(peer_2_info['permissions'], ['noban', 'forcerelay', 'relay', 'mempool'])
+ assert_equal(peer_2_info['permissions'], ['noban', 'forcerelay', 'relay', 'mempool', 'download'])
assert_equal(self.nodes[0].testmempoolaccept([sigtx])[0]['allowed'], True)
txid = self.nodes[0].testmempoolaccept([sigtx])[0]['txid']
- self.log.info('Check that the tx from whitelisted first_peer is relayed to others (ie.second_peer)')
+ self.log.info('Check that the tx from forcerelay first_peer is relayed to others (ie.second_peer)')
with self.nodes[0].assert_debug_log(["received getdata"]):
first_peer.send_message(msg_tx(FromHex(CTransaction(), sigtx)))
- self.log.info('Check that the whitelisted peer is still connected after sending the transaction')
+ self.log.info('Check that the forcerelay peer is still connected after sending the transaction')
assert_equal(first_peer.is_connected, True)
second_peer.wait_for_tx(txid)
assert_equal(self.nodes[0].getmempoolinfo()['size'], 1)
- self.log.info("Whitelisted peer's transaction is accepted and relayed")
+ self.log.info("Forcerelay peer's transaction is accepted and relayed")
+
if __name__ == '__main__':
P2PBlocksOnly().main()
diff --git a/test/functional/p2p_leak.py b/test/functional/p2p_leak.py
index 3b3dbd08f2..fe6e236fc4 100755
--- a/test/functional/p2p_leak.py
+++ b/test/functional/p2p_leak.py
@@ -26,7 +26,7 @@ from test_framework.util import (
wait_until,
)
-banscore = 10
+DISCOURAGEMENT_THRESHOLD = 100
class CLazyNode(P2PInterface):
@@ -65,12 +65,13 @@ class CLazyNode(P2PInterface):
# Node that never sends a version. We'll use this to send a bunch of messages
# anyway, and eventually get disconnected.
-class CNodeNoVersionBan(CLazyNode):
- # send a bunch of veracks without sending a message. This should get us disconnected.
- # NOTE: implementation-specific check here. Remove if bitcoind ban behavior changes
+class CNodeNoVersionMisbehavior(CLazyNode):
+ # Send enough veracks without a message to reach the peer discouragement
+ # threshold. This should get us disconnected. NOTE: implementation-specific
+ # test; update if our discouragement policy for peer misbehavior changes.
def on_open(self):
super().on_open()
- for i in range(banscore):
+ for _ in range(DISCOURAGEMENT_THRESHOLD):
self.send_message(msg_verack())
# Node that never sends a version. This one just sits idle and hopes to receive
@@ -106,10 +107,10 @@ class P2PVersionStore(P2PInterface):
class P2PLeakTest(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 1
- self.extra_args = [['-banscore=' + str(banscore)]]
def run_test(self):
- no_version_bannode = self.nodes[0].add_p2p_connection(CNodeNoVersionBan(), send_version=False, wait_for_verack=False)
+ no_version_disconnect_node = self.nodes[0].add_p2p_connection(
+ CNodeNoVersionMisbehavior(), send_version=False, wait_for_verack=False)
no_version_idlenode = self.nodes[0].add_p2p_connection(CNodeNoVersionIdle(), send_version=False, wait_for_verack=False)
no_verack_idlenode = self.nodes[0].add_p2p_connection(CNodeNoVerackIdle(), wait_for_verack=False)
@@ -117,7 +118,7 @@ class P2PLeakTest(BitcoinTestFramework):
# verack, since we never sent one
no_verack_idlenode.wait_for_verack()
- wait_until(lambda: no_version_bannode.ever_connected, timeout=10, lock=mininode_lock)
+ wait_until(lambda: no_version_disconnect_node.ever_connected, timeout=10, lock=mininode_lock)
wait_until(lambda: no_version_idlenode.ever_connected, timeout=10, lock=mininode_lock)
wait_until(lambda: no_verack_idlenode.version_received, timeout=10, lock=mininode_lock)
@@ -127,13 +128,13 @@ class P2PLeakTest(BitcoinTestFramework):
#Give the node enough time to possibly leak out a message
time.sleep(5)
- #This node should have been banned
- assert not no_version_bannode.is_connected
+ # Expect this node to be disconnected for misbehavior
+ assert not no_version_disconnect_node.is_connected
self.nodes[0].disconnect_p2ps()
# Make sure no unexpected messages came in
- assert no_version_bannode.unexpected_msg == False
+ assert no_version_disconnect_node.unexpected_msg == False
assert no_version_idlenode.unexpected_msg == False
assert no_verack_idlenode.unexpected_msg == False
diff --git a/test/functional/p2p_permissions.py b/test/functional/p2p_permissions.py
index bea202855d..32a795e345 100755
--- a/test/functional/p2p_permissions.py
+++ b/test/functional/p2p_permissions.py
@@ -39,7 +39,8 @@ class P2PPermissionsTests(BitcoinTestFramework):
self.checkpermission(
# default permissions (no specific permissions)
["-whitelist=127.0.0.1"],
- ["relay", "noban", "mempool"],
+ # Make sure the default values in the command line documentation match the ones here
+ ["relay", "noban", "mempool", "download"],
True)
self.checkpermission(
@@ -51,7 +52,7 @@ class P2PPermissionsTests(BitcoinTestFramework):
self.checkpermission(
# relay permission removed (no specific permissions)
["-whitelist=127.0.0.1", "-whitelistrelay=0"],
- ["noban", "mempool"],
+ ["noban", "mempool", "download"],
True)
self.checkpermission(
@@ -59,7 +60,7 @@ class P2PPermissionsTests(BitcoinTestFramework):
# Legacy parameter interaction which set whitelistrelay to true
# if whitelistforcerelay is true
["-whitelist=127.0.0.1", "-whitelistforcerelay"],
- ["forcerelay", "relay", "noban", "mempool"],
+ ["forcerelay", "relay", "noban", "mempool", "download"],
True)
# Let's make sure permissions are merged correctly
@@ -70,32 +71,32 @@ class P2PPermissionsTests(BitcoinTestFramework):
self.checkpermission(
["-whitelist=noban@127.0.0.1"],
# Check parameter interaction forcerelay should activate relay
- ["noban", "bloomfilter", "forcerelay", "relay"],
+ ["noban", "bloomfilter", "forcerelay", "relay", "download"],
False)
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"],
+ ["noban", "mempool", "download"],
False)
self.checkpermission(
# legacy whitelistforcerelay should be ignored
["-whitelist=noban,mempool@127.0.0.1", "-whitelistforcerelay"],
- ["noban", "mempool"],
+ ["noban", "mempool", "download"],
False)
self.checkpermission(
# missing mempool permission to be considered legacy whitelisted
["-whitelist=noban@127.0.0.1"],
- ["noban"],
+ ["noban", "download"],
False)
self.checkpermission(
# all permission added
["-whitelist=all@127.0.0.1"],
- ["forcerelay", "noban", "mempool", "bloomfilter", "relay"],
+ ["forcerelay", "noban", "mempool", "bloomfilter", "relay", "download"],
False)
self.stop_node(1)
@@ -107,9 +108,9 @@ class P2PPermissionsTests(BitcoinTestFramework):
block_op_true = self.nodes[0].getblock(self.nodes[0].generatetoaddress(100, ADDRESS_BCRT1_P2WSH_OP_TRUE)[0])
self.sync_all()
- self.log.debug("Create a connection from a whitelisted wallet that rebroadcasts raw txs")
+ self.log.debug("Create a connection from a forcerelay peer that rebroadcasts raw txs")
# A python mininode is needed to send the raw transaction directly. If a full node was used, it could only
- # rebroadcast via the inv-getdata mechanism. However, even for whitelisted connections, a full node would
+ # rebroadcast via the inv-getdata mechanism. However, even for forcerelay connections, a full node would
# currently not request a txid that is already in the mempool.
self.restart_node(1, extra_args=["-whitelist=forcerelay@127.0.0.1"])
p2p_rebroadcast_wallet = self.nodes[1].add_p2p_connection(P2PDataStore())
@@ -134,7 +135,7 @@ class P2PPermissionsTests(BitcoinTestFramework):
self.log.debug("Check that node[1] will send the tx to node[0] even though it is already in the mempool")
connect_nodes(self.nodes[1], 0)
- with self.nodes[1].assert_debug_log(["Force relaying tx {} from whitelisted peer=0".format(txid)]):
+ with self.nodes[1].assert_debug_log(["Force relaying tx {} from peer=0".format(txid)]):
p2p_rebroadcast_wallet.send_txs_and_test([tx], self.nodes[1])
wait_until(lambda: txid in self.nodes[0].getrawmempool())
@@ -145,7 +146,7 @@ class P2PPermissionsTests(BitcoinTestFramework):
[tx],
self.nodes[1],
success=False,
- reject_reason='Not relaying non-mempool transaction {} from whitelisted peer=0'.format(txid),
+ reject_reason='Not relaying non-mempool transaction {} from forcerelay peer=0'.format(txid),
)
def checkpermission(self, args, expectedPermissions, whitelisted):
diff --git a/test/functional/p2p_ping.py b/test/functional/p2p_ping.py
new file mode 100755
index 0000000000..e00af88cc4
--- /dev/null
+++ b/test/functional/p2p_ping.py
@@ -0,0 +1,123 @@
+#!/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 ping message
+"""
+
+import time
+
+from test_framework.messages import (
+ msg_pong,
+)
+from test_framework.mininode import (
+ P2PInterface,
+ wait_until,
+)
+from test_framework.test_framework import BitcoinTestFramework
+from test_framework.util import assert_equal
+
+PING_INTERVAL = 2 * 60
+
+
+class msg_pong_corrupt(msg_pong):
+ def serialize(self):
+ return b""
+
+
+class NodePongAdd1(P2PInterface):
+ def on_ping(self, message):
+ self.send_message(msg_pong(message.nonce + 1))
+
+
+class NodeNoPong(P2PInterface):
+ def on_ping(self, message):
+ pass
+
+
+class PingPongTest(BitcoinTestFramework):
+ def set_test_params(self):
+ self.setup_clean_chain = True
+ self.num_nodes = 1
+ self.extra_args = [['-peertimeout=3']]
+
+ def check_peer_info(self, *, pingtime, minping, pingwait):
+ stats = self.nodes[0].getpeerinfo()[0]
+ assert_equal(stats.pop('pingtime', None), pingtime)
+ assert_equal(stats.pop('minping', None), minping)
+ assert_equal(stats.pop('pingwait', None), pingwait)
+
+ def mock_forward(self, delta):
+ self.mock_time += delta
+ self.nodes[0].setmocktime(self.mock_time)
+
+ def run_test(self):
+ self.mock_time = int(time.time())
+ self.mock_forward(0)
+
+ self.log.info('Check that ping is sent after connection is established')
+ no_pong_node = self.nodes[0].add_p2p_connection(NodeNoPong())
+ self.mock_forward(3)
+ assert no_pong_node.last_message.pop('ping').nonce != 0
+ self.check_peer_info(pingtime=None, minping=None, pingwait=3)
+
+ self.log.info('Reply without nonce cancels ping')
+ with self.nodes[0].assert_debug_log(['pong peer=0: Short payload']):
+ no_pong_node.send_and_ping(msg_pong_corrupt())
+ self.check_peer_info(pingtime=None, minping=None, pingwait=None)
+
+ self.log.info('Reply without ping')
+ with self.nodes[0].assert_debug_log([
+ 'pong peer=0: Unsolicited pong without ping, 0 expected, 0 received, 8 bytes',
+ ]):
+ no_pong_node.send_and_ping(msg_pong())
+ self.check_peer_info(pingtime=None, minping=None, pingwait=None)
+
+ self.log.info('Reply with wrong nonce does not cancel ping')
+ assert 'ping' not in no_pong_node.last_message
+ with self.nodes[0].assert_debug_log(['pong peer=0: Nonce mismatch']):
+ # mock time PING_INTERVAL ahead to trigger node into sending a ping
+ self.mock_forward(PING_INTERVAL + 1)
+ wait_until(lambda: 'ping' in no_pong_node.last_message)
+ self.mock_forward(9)
+ # Send the wrong pong
+ no_pong_node.send_and_ping(msg_pong(no_pong_node.last_message.pop('ping').nonce - 1))
+ self.check_peer_info(pingtime=None, minping=None, pingwait=9)
+
+ self.log.info('Reply with zero nonce does cancel ping')
+ with self.nodes[0].assert_debug_log(['pong peer=0: Nonce zero']):
+ no_pong_node.send_and_ping(msg_pong(0))
+ self.check_peer_info(pingtime=None, minping=None, pingwait=None)
+
+ self.log.info('Check that ping is properly reported on RPC')
+ assert 'ping' not in no_pong_node.last_message
+ # mock time PING_INTERVAL ahead to trigger node into sending a ping
+ self.mock_forward(PING_INTERVAL + 1)
+ wait_until(lambda: 'ping' in no_pong_node.last_message)
+ ping_delay = 29
+ self.mock_forward(ping_delay)
+ wait_until(lambda: 'ping' in no_pong_node.last_message)
+ no_pong_node.send_and_ping(msg_pong(no_pong_node.last_message.pop('ping').nonce))
+ self.check_peer_info(pingtime=ping_delay, minping=ping_delay, pingwait=None)
+
+ self.log.info('Check that minping is decreased after a fast roundtrip')
+ # mock time PING_INTERVAL ahead to trigger node into sending a ping
+ self.mock_forward(PING_INTERVAL + 1)
+ wait_until(lambda: 'ping' in no_pong_node.last_message)
+ ping_delay = 9
+ self.mock_forward(ping_delay)
+ wait_until(lambda: 'ping' in no_pong_node.last_message)
+ no_pong_node.send_and_ping(msg_pong(no_pong_node.last_message.pop('ping').nonce))
+ self.check_peer_info(pingtime=ping_delay, minping=ping_delay, pingwait=None)
+
+ self.log.info('Check that peer is disconnected after ping timeout')
+ assert 'ping' not in no_pong_node.last_message
+ self.nodes[0].ping()
+ wait_until(lambda: 'ping' in no_pong_node.last_message)
+ with self.nodes[0].assert_debug_log(['ping timeout: 1201.000000s']):
+ self.mock_forward(20 * 60 + 1)
+ time.sleep(4) # peertimeout + 1
+
+
+if __name__ == '__main__':
+ PingPongTest().main()
diff --git a/test/functional/p2p_unrequested_blocks.py b/test/functional/p2p_unrequested_blocks.py
index c323168848..71b0b0f63a 100755
--- a/test/functional/p2p_unrequested_blocks.py
+++ b/test/functional/p2p_unrequested_blocks.py
@@ -4,7 +4,7 @@
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
"""Test processing of unrequested blocks.
-Setup: two nodes, node0+node1, not connected to each other. Node1 will have
+Setup: two nodes, node0 + node1, not connected to each other. Node1 will have
nMinimumChainWork set to 0x10, so it won't process low-work unrequested blocks.
We have one P2PInterface connection to node0 called test_node, and one to node1
@@ -71,18 +71,10 @@ class AcceptBlockTest(BitcoinTestFramework):
self.extra_args = [[], ["-minimumchainwork=0x10"]]
def setup_network(self):
- # Node0 will be used to test behavior of processing unrequested blocks
- # from peers which are not whitelisted, while Node1 will be used for
- # the whitelisted case.
- # Node2 will be used for non-whitelisted peers to test the interaction
- # with nMinimumChainWork.
self.setup_nodes()
def run_test(self):
- # Setup the p2p connections
- # test_node connects to node0 (not whitelisted)
test_node = self.nodes[0].add_p2p_connection(P2PInterface())
- # min_work_node connects to node1 (whitelisted)
min_work_node = self.nodes[1].add_p2p_connection(P2PInterface())
# 1. Have nodes mine a block (leave IBD)
@@ -226,7 +218,7 @@ class AcceptBlockTest(BitcoinTestFramework):
self.nodes[0].getblock(all_blocks[286].hash)
assert_equal(self.nodes[0].getbestblockhash(), all_blocks[286].hash)
assert_raises_rpc_error(-1, "Block not found on disk", self.nodes[0].getblock, all_blocks[287].hash)
- self.log.info("Successfully reorged to longer chain from non-whitelisted peer")
+ self.log.info("Successfully reorged to longer chain")
# 8. Create a chain which is invalid at a height longer than the
# current chain, but which has more blocks on top of that
diff --git a/test/functional/rpc_blockchain.py b/test/functional/rpc_blockchain.py
index 6273c229ae..7c70f30ca3 100755
--- a/test/functional/rpc_blockchain.py
+++ b/test/functional/rpc_blockchain.py
@@ -241,6 +241,17 @@ class BlockchainTest(BitcoinTestFramework):
del res['disk_size'], res3['disk_size']
assert_equal(res, res3)
+ self.log.info("Test hash_type option for gettxoutsetinfo()")
+ # Adding hash_type 'hash_serialized_2', which is the default, should
+ # not change the result.
+ res4 = node.gettxoutsetinfo(hash_type='hash_serialized_2')
+ del res4['disk_size']
+ assert_equal(res, res4)
+
+ # hash_type none should not return a UTXO set hash.
+ res5 = node.gettxoutsetinfo(hash_type='none')
+ assert 'hash_serialized_2' not in res5
+
def _test_getblockheader(self):
node = self.nodes[0]
diff --git a/test/functional/rpc_getpeerinfo_banscore_deprecation.py b/test/functional/rpc_getpeerinfo_banscore_deprecation.py
new file mode 100755
index 0000000000..b830248e1e
--- /dev/null
+++ b/test/functional/rpc_getpeerinfo_banscore_deprecation.py
@@ -0,0 +1,24 @@
+#!/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 banscore field."""
+
+from test_framework.test_framework import BitcoinTestFramework
+
+
+class GetpeerinfoBanscoreDeprecationTest(BitcoinTestFramework):
+ def set_test_params(self):
+ self.num_nodes = 2
+ self.extra_args = [[], ["-deprecatedrpc=banscore"]]
+
+ def run_test(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()
+
+
+if __name__ == "__main__":
+ GetpeerinfoBanscoreDeprecationTest().main()
diff --git a/test/functional/rpc_psbt.py b/test/functional/rpc_psbt.py
index 660953be9b..e5e62fd646 100755
--- a/test/functional/rpc_psbt.py
+++ b/test/functional/rpc_psbt.py
@@ -38,6 +38,7 @@ class PSBTTest(BitcoinTestFramework):
def skip_test_if_missing_module(self):
self.skip_if_no_wallet()
+ # TODO: Re-enable this test with segwit v1
def test_utxo_conversion(self):
mining_node = self.nodes[2]
offline_node = self.nodes[0]
@@ -156,6 +157,10 @@ class PSBTTest(BitcoinTestFramework):
# spend single key from node 1
rawtx = self.nodes[1].walletcreatefundedpsbt([{"txid":txid,"vout":p2wpkh_pos},{"txid":txid,"vout":p2sh_p2wpkh_pos},{"txid":txid,"vout":p2pkh_pos}], {self.nodes[1].getnewaddress():29.99})['psbt']
walletprocesspsbt_out = self.nodes[1].walletprocesspsbt(rawtx)
+ # Make sure it has both types of UTXOs
+ decoded = self.nodes[1].decodepsbt(walletprocesspsbt_out['psbt'])
+ assert 'non_witness_utxo' in decoded['inputs'][0]
+ assert 'witness_utxo' in decoded['inputs'][0]
assert_equal(walletprocesspsbt_out['complete'], True)
self.nodes[1].sendrawtransaction(self.nodes[1].finalizepsbt(walletprocesspsbt_out['psbt'])['hex'])
@@ -352,7 +357,8 @@ class PSBTTest(BitcoinTestFramework):
for i, signer in enumerate(signers):
self.nodes[2].unloadwallet("wallet{}".format(i))
- self.test_utxo_conversion()
+ # TODO: Re-enable this for segwit v1
+ # self.test_utxo_conversion()
# Test that psbts with p2pkh outputs are created properly
p2pkh = self.nodes[0].getnewaddress(address_type='legacy')
diff --git a/test/functional/rpc_rawtransaction.py b/test/functional/rpc_rawtransaction.py
index 14cad3d1b8..23b5e647d6 100755
--- a/test/functional/rpc_rawtransaction.py
+++ b/test/functional/rpc_rawtransaction.py
@@ -424,11 +424,12 @@ class RawTransactionsTest(BitcoinTestFramework):
####################################
# Test the minimum transaction version number that fits in a signed 32-bit integer.
+ # As transaction version is unsigned, this should convert to its unsigned equivalent.
tx = CTransaction()
tx.nVersion = -0x80000000
rawtx = ToHex(tx)
decrawtx = self.nodes[0].decoderawtransaction(rawtx)
- assert_equal(decrawtx['version'], -0x80000000)
+ assert_equal(decrawtx['version'], 0x80000000)
# Test the maximum transaction version number that fits in a signed 32-bit integer.
tx = CTransaction()
diff --git a/test/functional/test_framework/authproxy.py b/test/functional/test_framework/authproxy.py
index 05308931e3..81eb881234 100644
--- a/test/functional/test_framework/authproxy.py
+++ b/test/functional/test_framework/authproxy.py
@@ -115,6 +115,8 @@ class AuthServiceProxy():
except OSError as e:
retry = (
'[WinError 10053] An established connection was aborted by the software in your host machine' in str(e))
+ # Workaround for a bug on macOS. See https://bugs.python.org/issue33450
+ retry = retry or ('[Errno 41] Protocol wrong type for socket' in str(e))
if retry:
self.__conn.close()
self.__conn.request(method, path, postdata, headers)
diff --git a/test/functional/test_framework/messages.py b/test/functional/test_framework/messages.py
index eb1244035f..12302cdbc3 100755
--- a/test/functional/test_framework/messages.py
+++ b/test/functional/test_framework/messages.py
@@ -207,17 +207,19 @@ class CAddress:
self.ip = "0.0.0.0"
self.port = 0
- def deserialize(self, f, with_time=True):
+ def deserialize(self, f, *, with_time=True):
if with_time:
+ # VERSION messages serialize CAddress objects without time
self.time = struct.unpack("<i", f.read(4))[0]
self.nServices = struct.unpack("<Q", f.read(8))[0]
self.pchReserved = f.read(12)
self.ip = socket.inet_ntoa(f.read(4))
self.port = struct.unpack(">H", f.read(2))[0]
- def serialize(self, with_time=True):
+ def serialize(self, *, with_time=True):
r = b""
if with_time:
+ # VERSION messages serialize CAddress objects without time
r += struct.pack("<i", self.time)
r += struct.pack("<Q", self.nServices)
r += self.pchReserved
@@ -973,10 +975,10 @@ class msg_version:
self.nServices = struct.unpack("<Q", f.read(8))[0]
self.nTime = struct.unpack("<q", f.read(8))[0]
self.addrTo = CAddress()
- self.addrTo.deserialize(f, False)
+ self.addrTo.deserialize(f, with_time=False)
self.addrFrom = CAddress()
- self.addrFrom.deserialize(f, False)
+ self.addrFrom.deserialize(f, with_time=False)
self.nNonce = struct.unpack("<Q", f.read(8))[0]
self.strSubVer = deser_string(f)
@@ -996,8 +998,8 @@ class msg_version:
r += struct.pack("<i", self.nVersion)
r += struct.pack("<Q", self.nServices)
r += struct.pack("<q", self.nTime)
- r += self.addrTo.serialize(False)
- r += self.addrFrom.serialize(False)
+ r += self.addrTo.serialize(with_time=False)
+ r += self.addrFrom.serialize(with_time=False)
r += struct.pack("<Q", self.nNonce)
r += ser_string(self.strSubVer)
r += struct.pack("<i", self.nStartingHeight)
diff --git a/test/functional/test_runner.py b/test/functional/test_runner.py
index b9e8757497..2a360bd38a 100755
--- a/test/functional/test_runner.py
+++ b/test/functional/test_runner.py
@@ -236,6 +236,7 @@ BASE_SCRIPTS = [
'mempool_compatibility.py',
'rpc_deriveaddresses.py',
'rpc_deriveaddresses.py --usecli',
+ 'p2p_ping.py',
'rpc_scantxoutset.py',
'feature_logging.py',
'p2p_node_network_limited.py',
@@ -243,6 +244,7 @@ BASE_SCRIPTS = [
'feature_blocksdir.py',
'feature_config_args.py',
'rpc_getdescriptorinfo.py',
+ 'rpc_getpeerinfo_banscore_deprecation.py',
'rpc_help.py',
'feature_help.py',
'feature_shutdown.py',
@@ -397,11 +399,12 @@ def run_tests(*, test_list, src_dir, build_dir, tmpdir, jobs=1, enable_coverage=
args = args or []
# Warn if bitcoind is already running
- # pidof might fail or return an empty string if bitcoind is not running
try:
- if subprocess.check_output(["pidof", "bitcoind"]) not in [b'']:
+ # pgrep exits with code zero when one or more matching processes found
+ if subprocess.run(["pgrep", "-x", "bitcoind"], stdout=subprocess.DEVNULL).returncode == 0:
print("%sWARNING!%s There is already a bitcoind process running on this system. Tests may fail unexpectedly due to resource contention!" % (BOLD[1], BOLD[0]))
- except (OSError, subprocess.SubprocessError):
+ except OSError:
+ # pgrep not supported
pass
# Warn if there is a cache directory
diff --git a/test/functional/tool_wallet.py b/test/functional/tool_wallet.py
index 524e1593ba..18f0beb598 100755
--- a/test/functional/tool_wallet.py
+++ b/test/functional/tool_wallet.py
@@ -71,8 +71,7 @@ class ToolWalletTest(BitcoinTestFramework):
self.assert_raises_tool_error('Error: two methods provided (info and create). Only one method should be provided.', 'info', 'create')
self.assert_raises_tool_error('Error parsing command line arguments: Invalid parameter -foo', '-foo')
self.assert_raises_tool_error(
- 'Error initializing wallet database environment "{}"!\nError loading wallet.dat. Is wallet being used by other process?'
- .format(os.path.join(self.nodes[0].datadir, self.chain, 'wallets')),
+ 'Error loading wallet.dat. Is wallet being used by another process?',
'-wallet=wallet.dat',
'info',
)
diff --git a/test/functional/wallet_basic.py b/test/functional/wallet_basic.py
index 8962362276..81382d94ad 100755
--- a/test/functional/wallet_basic.py
+++ b/test/functional/wallet_basic.py
@@ -119,7 +119,7 @@ class WalletTest(BitcoinTestFramework):
assert_raises_rpc_error(-8, "Invalid parameter, expected locked output", self.nodes[2].lockunspent, True, [unspent_0])
self.nodes[2].lockunspent(False, [unspent_0])
assert_raises_rpc_error(-8, "Invalid parameter, output already locked", self.nodes[2].lockunspent, False, [unspent_0])
- assert_raises_rpc_error(-4, "Insufficient funds", self.nodes[2].sendtoaddress, self.nodes[2].getnewaddress(), 20)
+ assert_raises_rpc_error(-6, "Insufficient funds", self.nodes[2].sendtoaddress, self.nodes[2].getnewaddress(), 20)
assert_equal([unspent_0], self.nodes[2].listlockunspent())
self.nodes[2].lockunspent(True, [unspent_0])
assert_equal(len(self.nodes[2].listlockunspent()), 0)
@@ -363,6 +363,9 @@ class WalletTest(BitcoinTestFramework):
assert_equal(tx_obj['amount'], Decimal('-0.0001'))
# General checks for errors from incorrect inputs
+ # This will raise an exception because the amount is negative
+ assert_raises_rpc_error(-3, "Amount out of range", self.nodes[0].sendtoaddress, self.nodes[2].getnewaddress(), "-1")
+
# This will raise an exception because the amount type is wrong
assert_raises_rpc_error(-3, "Invalid amount", self.nodes[0].sendtoaddress, self.nodes[2].getnewaddress(), "1f-4")
@@ -590,7 +593,7 @@ class WalletTest(BitcoinTestFramework):
node0_balance = self.nodes[0].getbalance()
# With walletrejectlongchains we will not create the tx and store it in our wallet.
- assert_raises_rpc_error(-4, "Transaction has too long of a mempool chain", self.nodes[0].sendtoaddress, sending_addr, node0_balance - Decimal('0.01'))
+ assert_raises_rpc_error(-6, "Transaction has too long of a mempool chain", self.nodes[0].sendtoaddress, sending_addr, node0_balance - Decimal('0.01'))
# Verify nothing new in wallet
assert_equal(total_txs, len(self.nodes[0].listtransactions("*", 99999)))
diff --git a/test/functional/wallet_dump.py b/test/functional/wallet_dump.py
index ba1e494d9a..6bfb468823 100755
--- a/test/functional/wallet_dump.py
+++ b/test/functional/wallet_dump.py
@@ -202,5 +202,10 @@ class WalletDumpTest(BitcoinTestFramework):
result = self.nodes[0].getaddressinfo(multisig_addr)
assert result['ismine']
+ self.log.info('Check that wallet is flushed')
+ with self.nodes[0].assert_debug_log(['Flushing wallet.dat'], timeout=20):
+ self.nodes[0].getnewaddress()
+
+
if __name__ == '__main__':
WalletDumpTest().main()
diff --git a/test/functional/wallet_encryption.py b/test/functional/wallet_encryption.py
index 6cd82ad250..4509c1e0b2 100755
--- a/test/functional/wallet_encryption.py
+++ b/test/functional/wallet_encryption.py
@@ -13,6 +13,7 @@ from test_framework.util import (
assert_greater_than_or_equal,
)
+
class WalletEncryptionTest(BitcoinTestFramework):
def set_test_params(self):
self.setup_clean_chain = True
@@ -72,20 +73,25 @@ class WalletEncryptionTest(BitcoinTestFramework):
# Test timeout bounds
assert_raises_rpc_error(-8, "Timeout cannot be negative.", self.nodes[0].walletpassphrase, passphrase2, -10)
- # Check the timeout
- # Check a time less than the limit
+
+ self.log.info('Check a timeout less than the limit')
MAX_VALUE = 100000000
expected_time = int(time.time()) + MAX_VALUE - 600
self.nodes[0].walletpassphrase(passphrase2, MAX_VALUE - 600)
+ # give buffer for walletpassphrase, since it iterates over all crypted keys
+ expected_time_with_buffer = time.time() + MAX_VALUE - 600
actual_time = self.nodes[0].getwalletinfo()['unlocked_until']
assert_greater_than_or_equal(actual_time, expected_time)
- assert_greater_than(expected_time + 5, actual_time) # 5 second buffer
- # Check a time greater than the limit
+ assert_greater_than(expected_time_with_buffer, actual_time)
+
+ self.log.info('Check a timeout greater than the limit')
expected_time = int(time.time()) + MAX_VALUE - 1
self.nodes[0].walletpassphrase(passphrase2, MAX_VALUE + 1000)
+ expected_time_with_buffer = time.time() + MAX_VALUE
actual_time = self.nodes[0].getwalletinfo()['unlocked_until']
assert_greater_than_or_equal(actual_time, expected_time)
- assert_greater_than(expected_time + 5, actual_time) # 5 second buffer
+ assert_greater_than(expected_time_with_buffer, actual_time)
+
if __name__ == '__main__':
WalletEncryptionTest().main()
diff --git a/test/functional/wallet_fallbackfee.py b/test/functional/wallet_fallbackfee.py
index 0c67982bbe..dbf853b35c 100755
--- a/test/functional/wallet_fallbackfee.py
+++ b/test/functional/wallet_fallbackfee.py
@@ -22,7 +22,7 @@ class WalletRBFTest(BitcoinTestFramework):
# test sending a tx with disabled fallback fee (must fail)
self.restart_node(0, extra_args=["-fallbackfee=0"])
- assert_raises_rpc_error(-4, "Fee estimation failed", lambda: self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 1))
+ assert_raises_rpc_error(-6, "Fee estimation failed", lambda: self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 1))
assert_raises_rpc_error(-4, "Fee estimation failed", lambda: self.nodes[0].fundrawtransaction(self.nodes[0].createrawtransaction([], {self.nodes[0].getnewaddress(): 1})))
assert_raises_rpc_error(-6, "Fee estimation failed", lambda: self.nodes[0].sendmany("", {self.nodes[0].getnewaddress(): 1}))
diff --git a/test/functional/wallet_importdescriptors.py b/test/functional/wallet_importdescriptors.py
index fc5d653a91..2d982edef8 100755
--- a/test/functional/wallet_importdescriptors.py
+++ b/test/functional/wallet_importdescriptors.py
@@ -146,6 +146,14 @@ class ImportDescriptorsTest(BitcoinTestFramework):
ismine=True,
solvable=True)
+ # Check persistence of data and that loading works correctly
+ w1.unloadwallet()
+ self.nodes[1].loadwallet('w1')
+ test_address(w1,
+ key.p2sh_p2wpkh_addr,
+ ismine=True,
+ solvable=True)
+
# # Test importing of a multisig descriptor
key1 = get_generate_key()
key2 = get_generate_key()
@@ -370,6 +378,10 @@ class ImportDescriptorsTest(BitcoinTestFramework):
self.sync_all()
assert_equal(wmulti_pub.getbalance(), wmulti_priv.getbalance())
+ # Make sure that descriptor wallets containing multiple xpubs in a single descriptor load correctly
+ wmulti_pub.unloadwallet()
+ self.nodes[1].loadwallet('wmulti_pub')
+
self.log.info("Multisig with distributed keys")
self.nodes[1].createwallet(wallet_name="wmulti_priv1", descriptors=True)
wmulti_priv1 = self.nodes[1].get_wallet_rpc("wmulti_priv1")
diff --git a/test/lint/README.md b/test/lint/README.md
index 6b95cc3540..d15c061288 100644
--- a/test/lint/README.md
+++ b/test/lint/README.md
@@ -23,6 +23,12 @@ maintained:
* for `src/crypto/ctaes`: https://github.com/bitcoin-core/ctaes.git (branch master)
* for `src/crc32c`: https://github.com/google/crc32c.git (branch master)
+To do so, add the upstream repository as remote:
+
+```
+git remote add --fetch secp256k1 https://github.com/bitcoin-core/secp256k1.git
+```
+
Usage: `git-subtree-check.sh DIR (COMMIT)`
`COMMIT` may be omitted, in which case `HEAD` is used.
diff --git a/test/lint/git-subtree-check.sh b/test/lint/git-subtree-check.sh
index caa7affc63..5a0500df25 100755
--- a/test/lint/git-subtree-check.sh
+++ b/test/lint/git-subtree-check.sh
@@ -81,7 +81,7 @@ fi
# get the tree in the subtree commit referred to
if [ "d$(git cat-file -t $rev 2>/dev/null)" != dcommit ]; then
- echo "subtree commit $rev unavailable: cannot compare" >&2
+ echo "subtree commit $rev unavailable: cannot compare. Did you add and fetch the remote?" >&2
exit
fi
tree_subtree=$(git show -s --format="%T" $rev)
diff --git a/test/lint/lint-assertions.sh b/test/lint/lint-assertions.sh
index 1aacc09bcc..d30a8ca231 100755
--- a/test/lint/lint-assertions.sh
+++ b/test/lint/lint-assertions.sh
@@ -23,7 +23,7 @@ fi
# Macro CHECK_NONFATAL(condition) should be used instead of assert for RPC code, where it
# is undesirable to crash the whole program. See: src/util/check.h
# src/rpc/server.cpp is excluded from this check since it's mostly meta-code.
-OUTPUT=$(git grep -nE 'assert *\(.*\);' -- "src/rpc/" "src/wallet/rpc*" ":(exclude)src/rpc/server.cpp")
+OUTPUT=$(git grep -nE '\<(A|a)ssert *\(.*\);' -- "src/rpc/" "src/wallet/rpc*" ":(exclude)src/rpc/server.cpp")
if [[ ${OUTPUT} != "" ]]; then
echo "CHECK_NONFATAL(condition) should be used instead of assert for RPC code."
echo
diff --git a/test/lint/lint-includes.sh b/test/lint/lint-includes.sh
index 5404565b94..611bd4a8c4 100755
--- a/test/lint/lint-includes.sh
+++ b/test/lint/lint-includes.sh
@@ -64,7 +64,7 @@ EXPECTED_BOOST_INCLUDES=(
boost/preprocessor/cat.hpp
boost/preprocessor/stringize.hpp
boost/signals2/connection.hpp
- boost/signals2/last_value.hpp
+ boost/signals2/optional_last_value.hpp
boost/signals2/signal.hpp
boost/test/unit_test.hpp
boost/thread/condition_variable.hpp
diff --git a/test/lint/lint-locale-dependence.sh b/test/lint/lint-locale-dependence.sh
index e2bb403c4d..2e5b801849 100755
--- a/test/lint/lint-locale-dependence.sh
+++ b/test/lint/lint-locale-dependence.sh
@@ -97,6 +97,7 @@ LOCALE_DEPENDENT_FUNCTIONS=(
snprintf
sprintf
sscanf
+ std::locale::global
std::to_string
stod
stof
diff --git a/test/sanitizer_suppressions/tsan b/test/sanitizer_suppressions/tsan
index b8fe75c5c5..cb33dd6232 100644
--- a/test/sanitizer_suppressions/tsan
+++ b/test/sanitizer_suppressions/tsan
@@ -19,7 +19,9 @@ race:CConnman::ThreadMessageHandler
race:fHaveGenesis
race:ProcessNewBlock
race:ThreadImport
+race:LoadWallet
race:WalletBatch::WriteHDChain
+race:BerkeleyBatch
race:BerkeleyDatabase
race:zmq::*
race:bitcoin-qt