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