Skip to content

Commit

Permalink
Merge bitcoin#16898: test: Remove connect_nodes_bi
Browse files Browse the repository at this point in the history
fadfd84 test: Remove unused connect_nodes_bi (MarcoFalke)
fa3b9ee scripted-diff: test: Replace connect_nodes_bi with connect_nodes (MarcoFalke)
faaee1e test: Use connect_nodes when connecting nodes in the test_framework (MarcoFalke)
1111bb9 test: Reformat python imports to aid scripted diff (MarcoFalke)

Pull request description:

  By default all test nodes are connected in a chain. However, instead of just a single connection between each pair of nodes, we end up with up to four connections for a "middle" node (two outbound, two inbound, from each side).

  This is generally redundant (tx and block relay should succeed with just a single connection) and confusing. For example, test timeouts after a call to `sync_` may be racy and hard to reproduce. On top of that, the test `debug.log`s are hard to read because txs and block invs may be relayed on the same connection multiple times.

  Fix this by inlining `connect_nodes_bi` in the two tests that need it, and then replace it with a single `connect_nodes` in all other tests.

  Historic background:

  `connect_nodes_bi` has been introduced as a (temporary?) workaround for bug bitcoin#5113 and bitcoin#5138, which has long been fixed in bitcoin#5157 and bitcoin#5662.

ACKs for top commit:
  laanwj:
    ACK fadfd84
  jonasschnelli:
    utACK fadfd84 - more of less a cleanup PR.
  promag:
    Tested ACK fadfd84, ran extended tests.

Tree-SHA512: 2d027a8fd150749c071b64438a0a78ec922178628a7dbb89fd1212b0fa34febd451798c940101155d3617c0426c2c4865174147709894f1f1bb6cfa336aa7e24
  • Loading branch information
MarcoFalke committed Sep 18, 2019
2 parents cfcaa97 + fadfd84 commit 59c138d
Show file tree
Hide file tree
Showing 20 changed files with 108 additions and 69 deletions.
8 changes: 6 additions & 2 deletions test/functional/feature_notifications.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,11 @@

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):
Expand Down Expand Up @@ -58,7 +62,7 @@ def run_test(self):
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)

Expand Down
4 changes: 2 additions & 2 deletions test/functional/mining_basic.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
from test_framework.util import (
assert_equal,
assert_raises_rpc_error,
connect_nodes_bi,
connect_nodes,
)
from test_framework.script import CScriptNum

Expand All @@ -54,7 +54,7 @@ def mine_chain(self):
assert_equal(mining_info['currentblocktx'], 0)
assert_equal(mining_info['currentblockweight'], 4000)
self.restart_node(0)
connect_nodes_bi(self.nodes, 0, 1)
connect_nodes(self.nodes[0], 1)

def run_test(self):
self.mine_chain()
Expand Down
12 changes: 9 additions & 3 deletions test/functional/p2p_disconnect_ban.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from test_framework.util import (
assert_equal,
assert_raises_rpc_error,
connect_nodes_bi,
connect_nodes,
wait_until,
)

Expand All @@ -18,6 +18,10 @@ def set_test_params(self):
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")
Expand Down Expand Up @@ -74,7 +78,9 @@ def run_test(self):

# 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")

Expand All @@ -93,7 +99,7 @@ def run_test(self):
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]

Expand Down
10 changes: 5 additions & 5 deletions test/functional/p2p_node_network_limited.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
from test_framework.util import (
assert_equal,
disconnect_nodes,
connect_nodes_bi,
connect_nodes,
wait_until,
)

Expand Down Expand Up @@ -64,7 +64,7 @@ def run_test(self):
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)
self.sync_blocks([self.nodes[0], self.nodes[1]])

Expand All @@ -90,7 +90,7 @@ def run_test(self):

# 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:
self.sync_blocks([self.nodes[0], self.nodes[2]], timeout=5)
except:
Expand All @@ -99,7 +99,7 @@ def run_test(self):
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
self.sync_blocks()
Expand All @@ -111,7 +111,7 @@ def run_test(self):
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)
self.sync_blocks([self.nodes[0], self.nodes[1]])
Expand Down
1 change: 1 addition & 0 deletions test/functional/p2p_tx_download.py
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ def test_inv_block(self):
# peer, plus
# * the first time it is re-requested from the outbound peer, plus
# * 2 seconds to avoid races
assert self.nodes[1].getpeerinfo()[0]['inbound'] == False
timeout = 2 + (MAX_GETDATA_RANDOM_DELAY + INBOUND_PEER_TX_DELAY) + (
GETDATA_TX_INTERVAL + MAX_GETDATA_RANDOM_DELAY)
self.log.info("Tx should be received at node 1 after {} seconds".format(timeout))
Expand Down
18 changes: 9 additions & 9 deletions test/functional/rpc_fundrawtransaction.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
assert_greater_than,
assert_greater_than_or_equal,
assert_raises_rpc_error,
connect_nodes_bi,
connect_nodes,
count_bytes,
find_vout_for_address,
)
Expand All @@ -35,10 +35,10 @@ def skip_test_if_missing_module(self):
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):
self.min_relay_tx_fee = self.nodes[0].getnetworkinfo()['relayfee']
Expand Down Expand Up @@ -508,10 +508,10 @@ def test_locked_wallet(self):
for node in self.nodes:
node.settxfee(self.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": self.watchonly_txid, "vout": self.watchonly_vout}])
Expand Down
13 changes: 10 additions & 3 deletions test/functional/rpc_net.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
assert_greater_than_or_equal,
assert_greater_than,
assert_raises_rpc_error,
connect_nodes_bi,
connect_nodes,
p2p_port,
wait_until,
)
Expand Down Expand Up @@ -54,6 +54,10 @@ def set_test_params(self):
self.extra_args = [["-minrelaytxfee=0.00001000"],["-minrelaytxfee=0.00000500"]]

def run_test(self):
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()
self._test_getnetworkinfo()
Expand All @@ -62,7 +66,7 @@ def run_test(self):
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):
Expand Down Expand Up @@ -105,7 +109,10 @@ def _test_getnetworkinfo(self):
wait_until(lambda: self.nodes[0].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)

Expand Down
8 changes: 4 additions & 4 deletions test/functional/rpc_preciousblock.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
from test_framework.test_framework import BitcoinTestFramework
from test_framework.util import (
assert_equal,
connect_nodes_bi,
connect_nodes,
)

def unidirectional_node_sync_via_rpc(node_src, node_dest):
Expand Down Expand Up @@ -60,7 +60,7 @@ def run_test(self):
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")
Expand Down Expand Up @@ -97,8 +97,8 @@ def run_test(self):
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)
Expand Down
6 changes: 3 additions & 3 deletions test/functional/rpc_psbt.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
assert_equal,
assert_greater_than,
assert_raises_rpc_error,
connect_nodes_bi,
connect_nodes,
disconnect_nodes,
find_output,
)
Expand Down Expand Up @@ -72,8 +72,8 @@ def test_utxo_conversion(self):
assert_equal(online_node.gettxout(txid,0)["confirmations"], 1)

# Reconnect
connect_nodes_bi(self.nodes, 0, 1)
connect_nodes_bi(self.nodes, 0, 2)
connect_nodes(self.nodes[0], 1)
connect_nodes(self.nodes[0], 2)

def run_test(self):
# Create and fund a raw tx for sending 10 BTC
Expand Down
10 changes: 8 additions & 2 deletions test/functional/rpc_rawtransaction.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,13 @@
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.
Expand Down Expand Up @@ -53,7 +59,7 @@ def skip_test_if_missing_module(self):

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')
Expand Down
16 changes: 13 additions & 3 deletions test/functional/test_framework/test_framework.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
PortSeed,
assert_equal,
check_json_precision,
connect_nodes_bi,
connect_nodes,
disconnect_nodes,
get_datadir_path,
initialize_datadir,
Expand Down Expand Up @@ -281,8 +281,18 @@ def setup_network(self):
# 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):
Expand Down Expand Up @@ -423,7 +433,7 @@ def join_network(self):
"""
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):
Expand Down
4 changes: 0 additions & 4 deletions test/functional/test_framework/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -377,10 +377,6 @@ def connect_nodes(from_connection, node_num):
# with transaction relaying
wait_until(lambda: all(peer['version'] != 0 for peer in from_connection.getpeerinfo()))

def connect_nodes_bi(nodes, a, b):
connect_nodes(nodes[a], b)
connect_nodes(nodes[b], a)

def sync_blocks(rpc_connections, *, wait=1, timeout=60):
"""
Wait until everybody has the same tip.
Expand Down
4 changes: 2 additions & 2 deletions test/functional/wallet_address_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@
assert_equal,
assert_greater_than,
assert_raises_rpc_error,
connect_nodes_bi,
connect_nodes,
)
from test_framework.segwit_addr import (
encode,
Expand Down Expand Up @@ -90,7 +90,7 @@ def setup_network(self):
# Fully mesh-connect nodes for faster mempool sync
for i, j in itertools.product(range(self.num_nodes), repeat=2):
if i > j:
connect_nodes_bi(self.nodes, i, j)
connect_nodes(self.nodes[i], j)
self.sync_all()

def get_balances(self, confirmed=True):
Expand Down
4 changes: 2 additions & 2 deletions test/functional/wallet_avoidreuse.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from test_framework.util import (
assert_equal,
assert_raises_rpc_error,
connect_nodes_bi,
connect_nodes,
)

# TODO: Copied from wallet_groups.py -- should perhaps move into util.py
Expand Down Expand Up @@ -103,7 +103,7 @@ def test_persistence(self):
# Stop and restart node 1
self.stop_node(1)
self.start_node(1)
connect_nodes_bi(self.nodes, 0, 1)
connect_nodes(self.nodes[0], 1)

# Flags should still be node1.avoid_reuse=false, node2.avoid_reuse=true
assert_equal(self.nodes[0].getwalletinfo()["avoid_reuse"], False)
Expand Down
4 changes: 2 additions & 2 deletions test/functional/wallet_balance.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
from test_framework.util import (
assert_equal,
assert_raises_rpc_error,
connect_nodes_bi,
connect_nodes,
sync_blocks,
)

Expand Down Expand Up @@ -211,7 +211,7 @@ def test_balances(*, fee_node_1=0):

# Now confirm tx_orig
self.restart_node(1, ['-persistmempool=0'])
connect_nodes_bi(self.nodes, 0, 1)
connect_nodes(self.nodes[0], 1)
sync_blocks(self.nodes)
self.nodes[1].sendrawtransaction(tx_orig)
self.nodes[1].generatetoaddress(1, ADDRESS_WATCHONLY)
Expand Down
Loading

0 comments on commit 59c138d

Please sign in to comment.