@@ -69,6 +69,167 @@ def test_connect_basic(node_factory):
6969 assert l1 .rpc .listpeers (l2id )['peers' ][0 ]['num_channels' ] == 2
7070
7171
72+ # Helper function to setup nodes with the specified test case
73+ def alt_addr_setup_nodes (node_factory , test_case ):
74+ alt_addr = "127.0.0.1"
75+ alt_port = node_factory .get_unused_port ()
76+
77+ opts = {
78+ 'may_reconnect' : True ,
79+ 'dev-no-reconnect' : None ,
80+ }
81+ alt_port2 = None
82+
83+ if test_case == "standard" :
84+ opts ['alt-addr' ] = f'{ alt_addr } :{ alt_port } '
85+ elif test_case == "rpc" :
86+ alt_port2 = node_factory .get_unused_port ()
87+ opts ['alt-bind-addr' ] = [f'{ alt_addr } :{ alt_port } ' , f'{ alt_addr } :{ alt_port2 } ' ]
88+ elif test_case == "announce" :
89+ opts ['alt-bind-addr' ] = f'{ alt_addr } :{ alt_port } '
90+ opts ['alt-announce-addr' ] = f'{ alt_addr } :{ alt_port } '
91+ elif test_case == "whitelist" :
92+ opts ['alt-bind-addr' ] = f'{ alt_addr } :{ alt_port } '
93+ elif test_case == "clear_alt_addr" :
94+ opts ['alt-addr' ] = f'{ alt_addr } :{ alt_port } '
95+ else :
96+ raise ValueError ("Unknown test case" )
97+
98+ l1 , l2 = node_factory .line_graph (2 , fundchannel = True , opts = [{'may_reconnect' : True }, opts ])
99+
100+ return l1 , l2 , alt_addr , alt_port , alt_port2
101+
102+
103+ @pytest .mark .parametrize ("test_case" , [
104+ "standard" ,
105+ "rpc" ,
106+ "announce"
107+ ])
108+ def test_alt_addr_connection_scenarios (node_factory , bitcoind , test_case ):
109+ """Test various alternate connection address scenarios for nodes."""
110+
111+ # Function to verify that the node is correctly bound to the alternate address
112+ def verify_binding (l2 , alt_addr , alt_port ):
113+ binding = l2 .rpc .getinfo ()['binding' ]
114+ assert len (binding ) > 0 , "No binding found for l2"
115+ assert any (bind ['address' ] == alt_addr for bind in binding ), f"Expected alt-addr { alt_addr } , found { binding } "
116+ assert any (bind ['port' ] == alt_port for bind in binding ), f"Expected alt-port { alt_port } , found { binding } "
117+
118+ # Function to reconnect the node using the alternate address and verify the connection
119+ def reconnect_and_verify (l1 , l2 , alt_addr , alt_port ):
120+ l1 .rpc .disconnect (l2 .info ['id' ], force = True )
121+ assert not any (peer ['connected' ] for peer in l1 .rpc .listpeers ()['peers' ]), "l1 should not have any connected peers"
122+
123+ l1 .rpc .connect (l2 .info ['id' ], alt_addr , alt_port )
124+ wait_for (lambda : l1 .rpc .listpeers (l2 .info ['id' ])['peers' ][0 ]['connected' ], timeout = 180 )
125+
126+ connected_peer = l1 .rpc .getpeer (l2 .info ['id' ])
127+ assert connected_peer ['connected' ], "Peers not connected"
128+ assert connected_peer ['netaddr' ][0 ] == f'{ alt_addr } :{ alt_port } ' , f"Connection not using alt-addr: { connected_peer ['netaddr' ][0 ]} "
129+
130+ def auto_reconnect_and_verify (l1 , l2 , alt_addr , alt_port ):
131+ l2 .rpc .disconnect (l1 .info ['id' ], force = True )
132+ assert not any (peer ['connected' ] for peer in l2 .rpc .listpeers ()['peers' ]), "l2 should not have any connected peers"
133+
134+ # Wait for l1 to auto-reconnect
135+ wait_for (lambda : any (peer ['connected' ] for peer in l1 .rpc .listpeers ()['peers' ]), timeout = 180 )
136+
137+ # Verify that l1 reconnected using alt-addr
138+ connected_peer = l1 .rpc .getpeer (l2 .info ['id' ])
139+ assert connected_peer ['connected' ], "Peers not reconnected"
140+ assert connected_peer ['netaddr' ][0 ] == f'{ alt_addr } :{ alt_port } ' , "Connection not using alt-addr"
141+
142+ # Function to restart the node and verify it reconnects using the alternate address
143+ def restart_and_verify (l1 , l2 , alt_addr , alt_port ):
144+ l2 .restart ()
145+ wait_for (lambda : any (peer ['connected' ] for peer in l1 .rpc .listpeers ()['peers' ]), timeout = 180 )
146+
147+ connected_peer = l1 .rpc .getpeer (l2 .info ['id' ])
148+ assert connected_peer ['connected' ], "Peers not connected"
149+ assert connected_peer ['netaddr' ][0 ] == f'{ alt_addr } :{ alt_port } ' , "Connection address does not match"
150+
151+ # l2 provides alt_addrs to l1, l1 connects to l2.
152+ l1 , l2 , alt_addr , alt_port , alt_port2 = alt_addr_setup_nodes (node_factory , test_case )
153+
154+ if test_case == "rpc" :
155+ # Test with two alternate addresses in one RPC call
156+ l2 .rpc .alt_addr (l1 .info ['id' ], [f'{ alt_addr } :{ alt_port } ' , f'{ alt_addr } :{ alt_port2 } ' ])
157+ verify_binding (l2 , alt_addr , alt_port )
158+ verify_binding (l2 , alt_addr , alt_port2 )
159+
160+ reconnect_and_verify (l1 , l2 , alt_addr , alt_port )
161+ auto_reconnect_and_verify (l1 , l2 , alt_addr , alt_port )
162+ restart_and_verify (l1 , l2 , alt_addr , alt_port )
163+
164+ # Test with the second alternate address
165+ reconnect_and_verify (l1 , l2 , alt_addr , alt_port2 )
166+ auto_reconnect_and_verify (l1 , l2 , alt_addr , alt_port2 )
167+ restart_and_verify (l1 , l2 , alt_addr , alt_port2 )
168+
169+ # Test to clear the alt-addrs and connect to default
170+ l2 .rpc .alt_addr (l1 .info ['id' ], [f'' ])
171+ default_addr = l2 .rpc .getinfo ()['binding' ][0 ]['address' ]
172+ default_port = l2 .rpc .getinfo ()['binding' ][0 ]['port' ]
173+ reconnect_and_verify (l1 , l2 , default_addr , default_port )
174+
175+ else :
176+ verify_binding (l2 , alt_addr , alt_port )
177+ reconnect_and_verify (l1 , l2 , alt_addr , alt_port )
178+ auto_reconnect_and_verify (l1 , l2 , alt_addr , alt_port )
179+ restart_and_verify (l1 , l2 , alt_addr , alt_port )
180+
181+
182+ @pytest .mark .parametrize ("test_case" , [
183+ ("wrong_port_standard" ),
184+ ("wrong_port_rpc" ),
185+ ])
186+ def test_alt_addr_wrong_port_handling (node_factory , test_case ):
187+ """Test handling of incorrect ports with alternative addresses."""
188+
189+ l1 , l2 , alt_addr , alt_port , alt_port2 = alt_addr_setup_nodes (node_factory , test_case .replace ("wrong_port_" , "" ))
190+
191+ wrong_port = node_factory .get_unused_port ()
192+
193+ if "rpc" in test_case :
194+ l2 .rpc .alt_addr (l1 .info ['id' ], [f'{ alt_addr } :{ wrong_port } ' ])
195+
196+ l1 .rpc .disconnect (l2 .info ['id' ], force = True )
197+ assert not any (peer ['connected' ] for peer in l1 .rpc .listpeers ()['peers' ]), "l1 should not have any connected peers"
198+ assert not any (peer ['connected' ] for peer in l2 .rpc .listpeers ()['peers' ]), "l2 should not have any connected peers"
199+
200+ with pytest .raises (Exception ):
201+ l1 .rpc .connect (l2 .info ['id' ], alt_addr , wrong_port )
202+ connected_peer = l1 .rpc .listpeers (l2 .info ['id' ])['peers' ]
203+ assert len (connected_peer ) == 0 or not connected_peer [0 ]['connected' ], "Peer should not be connected using wrong_port"
204+
205+ l1 .restart ()
206+ connected_peer = l1 .rpc .listpeers (l2 .info ['id' ])['peers' ]
207+ assert len (connected_peer ) == 0 or not connected_peer [0 ]['connected' ], "Peer should not be connected using wrong_port"
208+ else :
209+ l1 .rpc .connect (l2 .info ['id' ], alt_addr , wrong_port )
210+ connected_peer = l1 .rpc .getpeer (l2 .info ['id' ])
211+ assert not connected_peer ['netaddr' ][0 ] == f'{ alt_addr } :{ wrong_port } ' , "Connection address does not match"
212+
213+
214+ def test_alt_addr_whitelist_handling (node_factory ):
215+ """Test handling of whitelist with alternate addresses."""
216+
217+ l1 , l2 , alt_addr , alt_port , alt_port2 = alt_addr_setup_nodes (node_factory , "whitelist" )
218+ l3 = node_factory .get_node ()
219+
220+ try :
221+ l3 .rpc .connect (l2 .info ['id' ], alt_addr , alt_port )
222+ except RpcError as e :
223+ print (f"RPC Error: { e .error } " )
224+ assert e .error ['code' ] == 401 , f"Unexpected error code: { e .error ['code' ]} "
225+ assert "peer closed connection" in e .error ['message' ], f"Unexpected error message: { e .error ['message' ]} "
226+
227+ l2 .daemon .wait_for_log (f"Connection attempt from address { alt_addr } :{ alt_port } which is not in the whitelist. Closing connection." )
228+
229+ connected_peers = l2 .rpc .listpeers ()['peers' ]
230+ assert not any (peer ['id' ] == l3 .info ['id' ] and peer ['connected' ] for peer in connected_peers ), "l3 should not be connected to l2"
231+
232+
72233def test_remote_addr (node_factory , bitcoind ):
73234 """Check address discovery (BOLT1 #917) init remote_addr works as designed:
74235
0 commit comments