diff --git a/test/functional/feature_notifications.py b/test/functional/feature_notifications.py index 38509ad95e..a96760b891 100755 --- a/test/functional/feature_notifications.py +++ b/test/functional/feature_notifications.py @@ -7,7 +7,11 @@ import os from test_framework.address import ADDRESS_BCRT1_UNSPENDABLE from test_framework.test_framework import BitcoinTestFramework -from test_framework.util import assert_equal, wait_until, connect_nodes_bi +from test_framework.util import ( + assert_equal, + wait_until, + connect_nodes, +) class NotificationsTest(BitcoinTestFramework): @@ -59,7 +63,7 @@ class NotificationsTest(BitcoinTestFramework): self.log.info("test -walletnotify after rescan") # restart node to rescan to force wallet notifications self.start_node(1) - connect_nodes_bi(self.nodes, 0, 1) + connect_nodes(self.nodes[0], 1) wait_until(lambda: len(os.listdir(self.walletnotify_dir)) == block_count, timeout=10) diff --git a/test/functional/p2p_connect_to_devnet.py b/test/functional/p2p_connect_to_devnet.py index e53be9ee0e..99b82ec244 100755 --- a/test/functional/p2p_connect_to_devnet.py +++ b/test/functional/p2p_connect_to_devnet.py @@ -6,7 +6,7 @@ from test_framework.mininode import P2PInterface from test_framework.test_framework import BitcoinTestFramework -from test_framework.util import assert_equal, connect_nodes_bi +from test_framework.util import assert_equal, connect_nodes class ConnectDevnetNodes(BitcoinTestFramework): def set_test_params(self): @@ -18,13 +18,13 @@ class ConnectDevnetNodes(BitcoinTestFramework): self.add_nodes(self.num_nodes) self.start_node(0) self.start_node(1) - connect_nodes_bi(self.nodes, 0, 1) + connect_nodes(self.nodes[0], 1) self.sync_all() def run_test(self): self.nodes[0].add_p2p_connection(P2PInterface()) - assert_equal(self.nodes[0].getconnectioncount(), 3) # 2 in/out dashd + 1 p2p + assert_equal(self.nodes[0].getconnectioncount(), 2) # 1 out dashd + 1 p2p if __name__ == '__main__': diff --git a/test/functional/p2p_disconnect_ban.py b/test/functional/p2p_disconnect_ban.py index febffb71ca..e388d554cb 100755 --- a/test/functional/p2p_disconnect_ban.py +++ b/test/functional/p2p_disconnect_ban.py @@ -8,7 +8,7 @@ from test_framework.test_framework import BitcoinTestFramework from test_framework.util import ( assert_equal, assert_raises_rpc_error, - connect_nodes_bi, + connect_nodes, wait_until, ) @@ -17,6 +17,10 @@ class DisconnectBanTest(BitcoinTestFramework): self.num_nodes = 2 def run_test(self): + self.log.info("Connect nodes both way") + connect_nodes(self.nodes[0], 1) + connect_nodes(self.nodes[1], 0) + self.log.info("Test setban and listbanned RPCs") self.log.info("setban: successfully ban single IP address") @@ -69,7 +73,9 @@ class DisconnectBanTest(BitcoinTestFramework): # Clear ban lists self.nodes[1].clearbanned() - connect_nodes_bi(self.nodes, 0, 1) + self.log.info("Connect nodes both way") + connect_nodes(self.nodes[0], 1) + connect_nodes(self.nodes[1], 0) self.log.info("Test disconnectnode RPCs") @@ -88,7 +94,7 @@ class DisconnectBanTest(BitcoinTestFramework): assert not [node for node in self.nodes[0].getpeerinfo() if node['addr'] == address1] self.log.info("disconnectnode: successfully reconnect node") - connect_nodes_bi(self.nodes, 0, 1) # reconnect the node + connect_nodes(self.nodes[0], 1) # reconnect the node assert_equal(len(self.nodes[0].getpeerinfo()), 2) assert [node for node in self.nodes[0].getpeerinfo() if node['addr'] == address1] diff --git a/test/functional/p2p_node_network_limited.py b/test/functional/p2p_node_network_limited.py index f83248381f..91fe1f23b6 100755 --- a/test/functional/p2p_node_network_limited.py +++ b/test/functional/p2p_node_network_limited.py @@ -11,7 +11,7 @@ and that it responds to getdata requests for blocks correctly: from test_framework.messages import CInv, msg_getdata, NODE_BLOOM, NODE_NETWORK_LIMITED, msg_verack from test_framework.mininode import P2PInterface, mininode_lock from test_framework.test_framework import BitcoinTestFramework -from test_framework.util import assert_equal, disconnect_nodes, connect_nodes_bi, sync_blocks, wait_until +from test_framework.util import assert_equal, disconnect_nodes, connect_nodes, sync_blocks, wait_until class P2PIgnoreInv(P2PInterface): firstAddrnServices = 0 @@ -58,7 +58,7 @@ class NodeNetworkLimitedTest(BitcoinTestFramework): assert_equal(int(self.nodes[0].getnetworkinfo()['localservices'], 16), expected_services) self.log.info("Mine enough blocks to reach the NODE_NETWORK_LIMITED range.") - connect_nodes_bi(self.nodes, 0, 1) + connect_nodes(self.nodes[0], 1) blocks = self.nodes[1].generatetoaddress(292, self.nodes[1].get_deterministic_priv_key().address) sync_blocks([self.nodes[0], self.nodes[1]]) @@ -84,7 +84,7 @@ class NodeNetworkLimitedTest(BitcoinTestFramework): # connect unsynced node 2 with pruned NODE_NETWORK_LIMITED peer # because node 2 is in IBD and node 0 is a NODE_NETWORK_LIMITED peer, sync must not be possible - connect_nodes_bi(self.nodes, 0, 2) + connect_nodes(self.nodes[0], 2) try: sync_blocks([self.nodes[0], self.nodes[2]], timeout=5) except: @@ -93,7 +93,7 @@ class NodeNetworkLimitedTest(BitcoinTestFramework): assert_equal(self.nodes[2].getblockheader(self.nodes[2].getbestblockhash())['height'], 0) # now connect also to node 1 (non pruned) - connect_nodes_bi(self.nodes, 1, 2) + connect_nodes(self.nodes[1], 2) # sync must be possible sync_blocks(self.nodes) @@ -105,7 +105,7 @@ class NodeNetworkLimitedTest(BitcoinTestFramework): self.nodes[0].generatetoaddress(10, self.nodes[0].get_deterministic_priv_key().address) # connect node1 (non pruned) with node0 (pruned) and check if the can sync - connect_nodes_bi(self.nodes, 0, 1) + connect_nodes(self.nodes[0], 1) # sync must be possible, node 1 is no longer in IBD and should therefore connect to node 0 (NODE_NETWORK_LIMITED) sync_blocks([self.nodes[0], self.nodes[1]]) diff --git a/test/functional/rpc_fundrawtransaction.py b/test/functional/rpc_fundrawtransaction.py index d78c05d7a9..cc55f0d2f2 100755 --- a/test/functional/rpc_fundrawtransaction.py +++ b/test/functional/rpc_fundrawtransaction.py @@ -12,7 +12,7 @@ from test_framework.util import ( assert_greater_than, assert_greater_than_or_equal, assert_raises_rpc_error, - connect_nodes_bi, + connect_nodes, count_bytes, find_vout_for_address, ) @@ -36,10 +36,10 @@ class RawTransactionsTest(BitcoinTestFramework): def setup_network(self): self.setup_nodes() - connect_nodes_bi(self.nodes, 0, 1) - connect_nodes_bi(self.nodes, 1, 2) - connect_nodes_bi(self.nodes, 0, 2) - connect_nodes_bi(self.nodes, 0, 3) + connect_nodes(self.nodes[0], 1) + connect_nodes(self.nodes[1], 2) + connect_nodes(self.nodes[0], 2) + connect_nodes(self.nodes[0], 3) def run_test(self): min_relay_tx_fee = self.nodes[0].getnetworkinfo()['relayfee'] @@ -475,10 +475,10 @@ class RawTransactionsTest(BitcoinTestFramework): for node in self.nodes: node.settxfee(min_relay_tx_fee) - connect_nodes_bi(self.nodes,0,1) - connect_nodes_bi(self.nodes,1,2) - connect_nodes_bi(self.nodes,0,2) - connect_nodes_bi(self.nodes,0,3) + connect_nodes(self.nodes[0], 1) + connect_nodes(self.nodes[1], 2) + connect_nodes(self.nodes[0], 2) + connect_nodes(self.nodes[0], 3) # Again lock the watchonly UTXO or nodes[0] may spend it, because # lockunspent is memory-only and thus lost on restart self.nodes[0].lockunspent(False, [{"txid": watchonly_txid, "vout": watchonly_vout}]) diff --git a/test/functional/rpc_fundrawtransaction_hd.py b/test/functional/rpc_fundrawtransaction_hd.py index 493187273b..b417a7a05b 100755 --- a/test/functional/rpc_fundrawtransaction_hd.py +++ b/test/functional/rpc_fundrawtransaction_hd.py @@ -7,7 +7,7 @@ from decimal import Decimal from test_framework.authproxy import JSONRPCException from test_framework.test_framework import BitcoinTestFramework -from test_framework.util import assert_equal, assert_greater_than, connect_nodes_bi +from test_framework.util import assert_equal, assert_greater_than, connect_nodes # Create one-input, one-output, no-fee transaction: class RawTransactionsTest(BitcoinTestFramework): @@ -22,10 +22,10 @@ class RawTransactionsTest(BitcoinTestFramework): def setup_network(self): super().setup_network() - connect_nodes_bi(self.nodes,0,1) - connect_nodes_bi(self.nodes,1,2) - connect_nodes_bi(self.nodes,0,2) - connect_nodes_bi(self.nodes,0,3) + connect_nodes(self.nodes[0],1) + connect_nodes(self.nodes[1],2) + connect_nodes(self.nodes[0],2) + connect_nodes(self.nodes[0],3) def run_test(self): self.log.info("Mining blocks...") @@ -451,10 +451,10 @@ class RawTransactionsTest(BitcoinTestFramework): for node in self.nodes: node.settxfee(min_relay_tx_fee) - connect_nodes_bi(self.nodes,0,1) - connect_nodes_bi(self.nodes,1,2) - connect_nodes_bi(self.nodes,0,2) - connect_nodes_bi(self.nodes,0,3) + connect_nodes(self.nodes[0],1) + connect_nodes(self.nodes[1],2) + connect_nodes(self.nodes[0],2) + connect_nodes(self.nodes[0],3) self.sync_all() # drain the keypool diff --git a/test/functional/rpc_net.py b/test/functional/rpc_net.py index 97050708c0..0a7593a95c 100755 --- a/test/functional/rpc_net.py +++ b/test/functional/rpc_net.py @@ -13,7 +13,7 @@ from test_framework.util import ( assert_greater_than_or_equal, assert_greater_than, assert_raises_rpc_error, - connect_nodes_bi, + connect_nodes, p2p_port, wait_until, ) @@ -50,13 +50,16 @@ class NetTest(BitcoinTestFramework): def setup_network(self): self.disable_mocktime() self.setup_nodes() - connect_nodes_bi(self.nodes, 0, 1) + connect_nodes(self.nodes[0], 1) def run_test(self): # Wait for one ping/pong to finish so that we can be sure that there is no chatter between nodes for some time # Especially the exchange of messages like getheaders and friends causes test failures here self.nodes[0].ping() wait_until(lambda: all(['pingtime' in n for n in self.nodes[0].getpeerinfo()])) + self.log.info('Connect nodes both way') + connect_nodes(self.nodes[0], 1) + connect_nodes(self.nodes[1], 0) self._test_connection_count() self._test_getnettotals() @@ -66,7 +69,7 @@ class NetTest(BitcoinTestFramework): self._test_getnodeaddresses() def _test_connection_count(self): - # connect_nodes_bi connects each node to the other + # connect_nodes connects each node to the other assert_equal(self.nodes[0].getconnectioncount(), 2) def _test_getnettotals(self): @@ -110,7 +113,10 @@ class NetTest(BitcoinTestFramework): wait_until(lambda: self.nodes[1].getnetworkinfo()['connections'] == 0, timeout=3) self.nodes[0].setnetworkactive(state=True) - connect_nodes_bi(self.nodes, 0, 1) + self.log.info('Connect nodes both way') + connect_nodes(self.nodes[0], 1) + connect_nodes(self.nodes[1], 0) + assert_equal(self.nodes[0].getnetworkinfo()['networkactive'], True) assert_equal(self.nodes[0].getnetworkinfo()['connections'], 2) diff --git a/test/functional/rpc_preciousblock.py b/test/functional/rpc_preciousblock.py index 224cf7d5f4..41c46c0154 100755 --- a/test/functional/rpc_preciousblock.py +++ b/test/functional/rpc_preciousblock.py @@ -7,7 +7,7 @@ from test_framework.test_framework import BitcoinTestFramework from test_framework.util import ( assert_equal, - connect_nodes_bi, + connect_nodes, sync_blocks, ) @@ -61,7 +61,7 @@ class PreciousTest(BitcoinTestFramework): self.log.info("Connect nodes and check no reorg occurs") # Submit competing blocks via RPC so any reorg should occur before we proceed (no way to wait on inaction for p2p sync) node_sync_via_rpc(self.nodes[0:2]) - connect_nodes_bi(self.nodes,0,1) + connect_nodes(self.nodes[0], 1) assert_equal(self.nodes[0].getbestblockhash(), hashC) assert_equal(self.nodes[1].getbestblockhash(), hashG) self.log.info("Make Node0 prefer block G") @@ -98,8 +98,8 @@ class PreciousTest(BitcoinTestFramework): hashL = self.nodes[2].getbestblockhash() self.log.info("Connect nodes and check no reorg occurs") node_sync_via_rpc(self.nodes[1:3]) - connect_nodes_bi(self.nodes,1,2) - connect_nodes_bi(self.nodes,0,2) + connect_nodes(self.nodes[1], 2) + connect_nodes(self.nodes[0], 2) assert_equal(self.nodes[0].getbestblockhash(), hashH) assert_equal(self.nodes[1].getbestblockhash(), hashH) assert_equal(self.nodes[2].getbestblockhash(), hashL) diff --git a/test/functional/rpc_rawtransaction.py b/test/functional/rpc_rawtransaction.py index 86d3e6ad1b..6bf0158824 100755 --- a/test/functional/rpc_rawtransaction.py +++ b/test/functional/rpc_rawtransaction.py @@ -17,7 +17,13 @@ from decimal import Decimal from io import BytesIO from test_framework.messages import CTransaction, ToHex from test_framework.test_framework import BitcoinTestFramework -from test_framework.util import assert_equal, assert_raises_rpc_error, connect_nodes_bi, hex_str_to_bytes +from test_framework.util import ( + assert_equal, + assert_raises_rpc_error, + connect_nodes, + hex_str_to_bytes, +) + class multidict(dict): """Dictionary that allows duplicate keys. @@ -53,7 +59,7 @@ class RawTransactionsTest(BitcoinTestFramework): def setup_network(self): super().setup_network() - connect_nodes_bi(self.nodes, 0, 2) + connect_nodes(self.nodes[0], 2) def run_test(self): self.log.info('prepare some coins for multiple *rawtransaction commands') diff --git a/test/functional/test_framework/test_framework.py b/test/functional/test_framework/test_framework.py index cf595a60dc..20c235ebeb 100755 --- a/test/functional/test_framework/test_framework.py +++ b/test/functional/test_framework/test_framework.py @@ -37,7 +37,6 @@ from .util import ( MAX_NODES, assert_equal, check_json_precision, - connect_nodes_bi, connect_nodes, copy_datadir, disconnect_nodes, @@ -326,8 +325,18 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass): # Connect the nodes as a "chain". This allows us # to split the network between nodes 1 and 2 to get # two halves that can work on competing chains. + # + # Topology looks like this: + # node0 <-- node1 <-- node2 <-- node3 + # + # If all nodes are in IBD (clean chain from genesis), node0 is assumed to be the source of blocks (miner). To + # ensure block propagation, all nodes will establish outgoing connections toward node0. + # See fPreferredDownload in net_processing. + # + # If further outbound connections are needed, they can be added at the beginning of the test with e.g. + # connect_nodes(self.nodes[1], 2) for i in range(self.num_nodes - 1): - connect_nodes_bi(self.nodes, i, i + 1) + connect_nodes(self.nodes[i + 1], i) self.sync_all() def setup_nodes(self): @@ -459,7 +468,7 @@ class BitcoinTestFramework(metaclass=BitcoinTestMetaClass): """ Join the (previously split) network halves together. """ - connect_nodes_bi(self.nodes, 1, 2) + connect_nodes(self.nodes[1], 2) self.sync_all() def sync_blocks(self, nodes=None, **kwargs): diff --git a/test/functional/test_framework/util.py b/test/functional/test_framework/util.py index afb406ed95..5dd62282ab 100644 --- a/test/functional/test_framework/util.py +++ b/test/functional/test_framework/util.py @@ -445,10 +445,6 @@ def connect_nodes(from_connection, node_num): wait_until(lambda: all(peer['version'] != 0 for peer in from_connection.getpeerinfo())) wait_until(lambda: all(peer['bytesrecv_per_msg'].pop('verack', 0) == 24 for peer in from_connection.getpeerinfo())) -def connect_nodes_bi(nodes, a, b): - connect_nodes(nodes[a], b) - connect_nodes(nodes[b], a) - def isolate_node(node, timeout=5): node.setnetworkactive(False) st = time.time() diff --git a/test/functional/wallet_basic.py b/test/functional/wallet_basic.py index 7faeba932d..fe766073a5 100755 --- a/test/functional/wallet_basic.py +++ b/test/functional/wallet_basic.py @@ -12,7 +12,7 @@ from test_framework.util import ( assert_equal, assert_fee_amount, assert_raises_rpc_error, - connect_nodes_bi, + connect_nodes, count_bytes, wait_until, ) @@ -32,9 +32,9 @@ class WalletTest(BitcoinTestFramework): self.start_node(0) self.start_node(1) self.start_node(2) - connect_nodes_bi(self.nodes, 0, 1) - connect_nodes_bi(self.nodes, 1, 2) - connect_nodes_bi(self.nodes, 0, 2) + connect_nodes(self.nodes[0], 1) + connect_nodes(self.nodes[1], 2) + connect_nodes(self.nodes[0], 2) self.sync_all(self.nodes[0:3]) def check_fee_amount(self, curr_balance, balance_with_fee, fee_per_byte, tx_size): @@ -214,7 +214,7 @@ class WalletTest(BitcoinTestFramework): node_0_bal = self.check_fee_amount(self.nodes[0].getbalance(), node_0_bal + Decimal('100'), fee_per_byte, count_bytes(self.nodes[2].gettransaction(txid)['hex'])) self.start_node(3) - connect_nodes_bi(self.nodes, 0, 3) + connect_nodes(self.nodes[0], 3) self.sync_all() # check if we can list zero value tx as available coins @@ -249,9 +249,9 @@ class WalletTest(BitcoinTestFramework): self.start_node(0, ["-walletbroadcast=0"]) self.start_node(1, ["-walletbroadcast=0"]) self.start_node(2, ["-walletbroadcast=0"]) - connect_nodes_bi(self.nodes, 0, 1) - connect_nodes_bi(self.nodes, 1, 2) - connect_nodes_bi(self.nodes, 0, 2) + connect_nodes(self.nodes[0], 1) + connect_nodes(self.nodes[1], 2) + connect_nodes(self.nodes[0], 2) self.sync_all(self.nodes[0:3]) txid_not_broadcast = self.nodes[0].sendtoaddress(self.nodes[2].getnewaddress(), 2) @@ -276,9 +276,9 @@ class WalletTest(BitcoinTestFramework): self.start_node(0) self.start_node(1) self.start_node(2) - connect_nodes_bi(self.nodes, 0, 1) - connect_nodes_bi(self.nodes, 1, 2) - connect_nodes_bi(self.nodes, 0, 2) + connect_nodes(self.nodes[0], 1) + connect_nodes(self.nodes[1], 2) + connect_nodes(self.nodes[0], 2) self.sync_blocks(self.nodes[0:3]) self.nodes[0].generate(1) diff --git a/test/functional/wallet_hd.py b/test/functional/wallet_hd.py index bd4c3d0e09..2c1915a747 100755 --- a/test/functional/wallet_hd.py +++ b/test/functional/wallet_hd.py @@ -10,7 +10,7 @@ import os from test_framework.test_framework import BitcoinTestFramework from test_framework.util import ( assert_equal, - connect_nodes_bi, + connect_nodes, ) class WalletHDTest(BitcoinTestFramework): @@ -31,7 +31,7 @@ class WalletHDTest(BitcoinTestFramework): self.stop_node(1) self.nodes[1].assert_start_raises_init_error(['-usehd=0'], "Error: Error loading : You can't disable HD on an already existing HD wallet") self.start_node(1) - connect_nodes_bi(self.nodes, 0, 1) + connect_nodes(self.nodes[0], 1) # Make sure we use hd, keep chainid chainid = self.nodes[1].getwalletinfo()['hdchainid'] @@ -92,7 +92,7 @@ class WalletHDTest(BitcoinTestFramework): assert_equal(hd_info_2["hdkeypath"], "m/44'/1'/0'/0/"+str(i)) assert_equal(hd_info_2["hdchainid"], chainid) assert_equal(hd_add, hd_add_2) - connect_nodes_bi(self.nodes, 0, 1) + connect_nodes(self.nodes[0], 1) self.sync_all() # Needs rescan @@ -108,7 +108,7 @@ class WalletHDTest(BitcoinTestFramework): shutil.rmtree(os.path.join(self.nodes[1].datadir, self.chain, "llmq")) shutil.copyfile(os.path.join(self.nodes[1].datadir, "hd.bak"), os.path.join(self.nodes[1].datadir, self.chain, "wallets", "wallet.dat")) self.start_node(1, extra_args=self.extra_args[1]) - connect_nodes_bi(self.nodes, 0, 1) + connect_nodes(self.nodes[0], 1) self.sync_all() # Wallet automatically scans blocks older than key on startup assert_equal(self.nodes[1].getbalance(), NUM_HD_ADDS + 1) diff --git a/test/functional/wallet_keypool_topup.py b/test/functional/wallet_keypool_topup.py index 02d020f395..67c8de9837 100755 --- a/test/functional/wallet_keypool_topup.py +++ b/test/functional/wallet_keypool_topup.py @@ -16,7 +16,7 @@ import shutil from test_framework.test_framework import BitcoinTestFramework from test_framework.util import ( assert_equal, - connect_nodes_bi, + connect_nodes, ) @@ -38,7 +38,7 @@ class KeypoolRestoreTest(BitcoinTestFramework): self.stop_node(1) shutil.copyfile(wallet_path, wallet_backup_path) self.start_node(1, self.extra_args[1]) - connect_nodes_bi(self.nodes, 0, 1) + connect_nodes(self.nodes[0], 1) self.log.info("Generate keys for wallet") for _ in range(90): @@ -57,7 +57,7 @@ class KeypoolRestoreTest(BitcoinTestFramework): self.stop_node(1) shutil.copyfile(wallet_backup_path, wallet_path) self.start_node(1, self.extra_args[1]) - connect_nodes_bi(self.nodes, 0, 1) + connect_nodes(self.nodes[0], 1) self.sync_all() self.log.info("Verify keypool is restored and balance is correct") diff --git a/test/functional/wallet_listsinceblock.py b/test/functional/wallet_listsinceblock.py index b735b51ec4..18ab146098 100755 --- a/test/functional/wallet_listsinceblock.py +++ b/test/functional/wallet_listsinceblock.py @@ -5,9 +5,15 @@ """Test the listsincelast RPC.""" from test_framework.test_framework import BitcoinTestFramework -from test_framework.util import assert_equal, assert_array_result, assert_raises_rpc_error +from test_framework.util import ( + assert_array_result, + assert_equal, + assert_raises_rpc_error, + connect_nodes, +) -class ListSinceBlockTest (BitcoinTestFramework): + +class ListSinceBlockTest(BitcoinTestFramework): def set_test_params(self): self.num_nodes = 4 self.setup_clean_chain = True @@ -16,6 +22,9 @@ class ListSinceBlockTest (BitcoinTestFramework): self.skip_if_no_wallet() def run_test(self): + # All nodes are in IBD from genesis, so they'll need the miner (node2) to be an outbound connection, or have + # only one connection. (See fPreferredDownload in net_processing) + connect_nodes(self.nodes[1], 2) self.nodes[2].generate(101) self.sync_all()