13
13
msg_addr ,
14
14
msg_getaddr
15
15
)
16
- from test_framework .p2p import P2PInterface
17
- from test_framework .test_framework import BGLTestFramework
18
- from test_framework .util import (
19
- assert_equal ,
16
+ from test_framework .p2p import (
17
+ P2PInterface ,
18
+ p2p_lock ,
20
19
)
20
+ from test_framework .test_framework import BGLTestFramework
21
+ from test_framework .util import assert_equal
22
+ import random
21
23
import time
22
24
23
25
24
26
class AddrReceiver (P2PInterface ):
25
27
num_ipv4_received = 0
28
+ test_addr_contents = False
29
+ _tokens = 1
30
+
31
+ def __init__ (self , test_addr_contents = False ):
32
+ super ().__init__ ()
33
+ self .test_addr_contents = test_addr_contents
26
34
27
35
def on_addr (self , message ):
28
36
for addr in message .addrs :
29
- assert_equal (addr .nServices , 9 )
30
- if not 8333 <= addr .port < 8343 :
31
- raise AssertionError ("Invalid addr.port of {} (8333-8342 expected)" .format (addr .port ))
32
- assert addr .ip .startswith ('123.123.123.' )
33
37
self .num_ipv4_received += 1
34
-
35
-
36
- class GetAddrStore (P2PInterface ):
37
- getaddr_received = False
38
- num_ipv4_received = 0
38
+ if (self .test_addr_contents ):
39
+ # relay_tests checks the content of the addr messages match
40
+ # expectations based on the message creation in setup_addr_msg
41
+ assert_equal (addr .nServices , 9 )
42
+ if not 8333 <= addr .port < 8343 :
43
+ raise AssertionError ("Invalid addr.port of {} (8333-8342 expected)" .format (addr .port ))
44
+ assert addr .ip .startswith ('123.123.123.' )
39
45
40
46
def on_getaddr (self , message ):
41
- self .getaddr_received = True
47
+ # When the node sends us a getaddr, it increments the addr relay tokens for the connection by 1000
48
+ self ._tokens += 1000
42
49
43
- def on_addr (self , message ):
44
- for addr in message .addrs :
45
- self .num_ipv4_received += 1
50
+ @property
51
+ def tokens (self ):
52
+ with p2p_lock :
53
+ return self ._tokens
54
+
55
+ def increment_tokens (self , n ):
56
+ # When we move mocktime forward, the node increments the addr relay tokens for its peers
57
+ with p2p_lock :
58
+ self ._tokens += n
46
59
47
60
def addr_received (self ):
48
61
return self .num_ipv4_received != 0
49
62
63
+ def getaddr_received (self ):
64
+ return self .message_count ['getaddr' ] > 0
65
+
50
66
51
67
class AddrTest (BGLTestFramework ):
52
68
counter = 0
53
69
mocktime = int (time .time ())
54
70
55
71
def set_test_params (self ):
56
72
self .num_nodes = 1
73
+ self .
extra_args = [[
"[email protected] " ]]
57
74
58
75
def run_test (self ):
59
76
self .oversized_addr_test ()
60
77
self .relay_tests ()
61
78
self .getaddr_tests ()
62
79
self .blocksonly_mode_tests ()
80
+ # Not sure if supported by BGL
81
+ #self.rate_limit_tests()
63
82
64
83
def setup_addr_msg (self , num ):
65
84
addrs = []
@@ -76,13 +95,26 @@ def setup_addr_msg(self, num):
76
95
msg .addrs = addrs
77
96
return msg
78
97
98
+ def setup_rand_addr_msg (self , num ):
99
+ addrs = []
100
+ for i in range (num ):
101
+ addr = CAddress ()
102
+ addr .time = self .mocktime + i
103
+ addr .nServices = NODE_NETWORK | NODE_WITNESS
104
+ addr .ip = f"{ random .randrange (128 ,169 )} .{ random .randrange (1 ,255 )} .{ random .randrange (1 ,255 )} .{ random .randrange (1 ,255 )} "
105
+ addr .port = 8333
106
+ addrs .append (addr )
107
+ msg = msg_addr ()
108
+ msg .addrs = addrs
109
+ return msg
110
+
79
111
def send_addr_msg (self , source , msg , receivers ):
80
112
source .send_and_ping (msg )
81
113
# pop m_next_addr_send timer
82
- self .mocktime += 5 * 60
114
+ self .mocktime += 10 * 60
83
115
self .nodes [0 ].setmocktime (self .mocktime )
84
116
for peer in receivers :
85
- peer .sync_with_ping ()
117
+ peer .sync_send_with_ping ()
86
118
87
119
def oversized_addr_test (self ):
88
120
self .log .info ('Send an addr message that is too large' )
@@ -101,7 +133,7 @@ def relay_tests(self):
101
133
num_receivers = 7
102
134
receivers = []
103
135
for _ in range (num_receivers ):
104
- receivers .append (self .nodes [0 ].add_p2p_connection (AddrReceiver ()))
136
+ receivers .append (self .nodes [0 ].add_p2p_connection (AddrReceiver (test_addr_contents = True )))
105
137
106
138
# Keep this with length <= 10. Addresses from larger messages are not
107
139
# relayed.
@@ -125,8 +157,8 @@ def relay_tests(self):
125
157
self .nodes [0 ].disconnect_p2ps ()
126
158
127
159
self .log .info ('Check relay of addresses received from outbound peers' )
128
- inbound_peer = self .nodes [0 ].add_p2p_connection (AddrReceiver ())
129
- full_outbound_peer = self .nodes [0 ].add_outbound_p2p_connection (GetAddrStore (), p2p_idx = 0 , connection_type = "outbound-full-relay" )
160
+ inbound_peer = self .nodes [0 ].add_p2p_connection (AddrReceiver (test_addr_contents = True ))
161
+ full_outbound_peer = self .nodes [0 ].add_outbound_p2p_connection (AddrReceiver (), p2p_idx = 0 , connection_type = "outbound-full-relay" )
130
162
msg = self .setup_addr_msg (2 )
131
163
self .send_addr_msg (full_outbound_peer , msg , [inbound_peer ])
132
164
self .log .info ('Check that the first addr message received from an outbound peer is not relayed' )
@@ -142,7 +174,7 @@ def relay_tests(self):
142
174
assert_equal (inbound_peer .num_ipv4_received , 2 )
143
175
144
176
self .log .info ('Check address relay to outbound peers' )
145
- block_relay_peer = self .nodes [0 ].add_outbound_p2p_connection (GetAddrStore (), p2p_idx = 1 , connection_type = "block-relay-only" )
177
+ block_relay_peer = self .nodes [0 ].add_outbound_p2p_connection (AddrReceiver (), p2p_idx = 1 , connection_type = "block-relay-only" )
146
178
msg3 = self .setup_addr_msg (2 )
147
179
self .send_addr_msg (inbound_peer , msg3 , [full_outbound_peer , block_relay_peer ])
148
180
@@ -156,17 +188,17 @@ def relay_tests(self):
156
188
def getaddr_tests (self ):
157
189
self .log .info ('Test getaddr behavior' )
158
190
self .log .info ('Check that we send a getaddr message upon connecting to an outbound-full-relay peer' )
159
- full_outbound_peer = self .nodes [0 ].add_outbound_p2p_connection (GetAddrStore (), p2p_idx = 0 , connection_type = "outbound-full-relay" )
191
+ full_outbound_peer = self .nodes [0 ].add_outbound_p2p_connection (AddrReceiver (), p2p_idx = 0 , connection_type = "outbound-full-relay" )
160
192
full_outbound_peer .sync_with_ping ()
161
- assert full_outbound_peer .getaddr_received
193
+ assert full_outbound_peer .getaddr_received ()
162
194
163
195
self .log .info ('Check that we do not send a getaddr message upon connecting to a block-relay-only peer' )
164
- block_relay_peer = self .nodes [0 ].add_outbound_p2p_connection (GetAddrStore (), p2p_idx = 1 , connection_type = "block-relay-only" )
196
+ block_relay_peer = self .nodes [0 ].add_outbound_p2p_connection (AddrReceiver (), p2p_idx = 1 , connection_type = "block-relay-only" )
165
197
block_relay_peer .sync_with_ping ()
166
- assert_equal (block_relay_peer .getaddr_received , False )
198
+ assert_equal (block_relay_peer .getaddr_received () , False )
167
199
168
200
self .log .info ('Check that we answer getaddr messages only from inbound peers' )
169
- inbound_peer = self .nodes [0 ].add_p2p_connection (GetAddrStore ())
201
+ inbound_peer = self .nodes [0 ].add_p2p_connection (AddrReceiver ())
170
202
inbound_peer .sync_with_ping ()
171
203
172
204
# Add some addresses to addrman
@@ -182,7 +214,7 @@ def getaddr_tests(self):
182
214
183
215
self .mocktime += 5 * 60
184
216
self .nodes [0 ].setmocktime (self .mocktime )
185
- inbound_peer .wait_until (inbound_peer .addr_received )
217
+ inbound_peer .wait_until (lambda : inbound_peer .addr_received () is True )
186
218
187
219
assert_equal (full_outbound_peer .num_ipv4_received , 0 )
188
220
assert_equal (block_relay_peer .num_ipv4_received , 0 )
@@ -192,25 +224,79 @@ def getaddr_tests(self):
192
224
193
225
def blocksonly_mode_tests (self ):
194
226
self .log .info ('Test addr relay in -blocksonly mode' )
195
- self .restart_node (0 , ["-blocksonly" ])
227
+ self .
restart_node (
0 , [
"-blocksonly" , "[email protected] " ])
196
228
self .mocktime = int (time .time ())
197
229
198
230
self .log .info ('Check that we send getaddr messages' )
199
- full_outbound_peer = self .nodes [0 ].add_outbound_p2p_connection (GetAddrStore (), p2p_idx = 0 , connection_type = "outbound-full-relay" )
231
+ full_outbound_peer = self .nodes [0 ].add_outbound_p2p_connection (AddrReceiver (), p2p_idx = 0 , connection_type = "outbound-full-relay" )
200
232
full_outbound_peer .sync_with_ping ()
201
- assert full_outbound_peer .getaddr_received
233
+ assert full_outbound_peer .getaddr_received ()
202
234
203
235
self .log .info ('Check that we relay address messages' )
204
236
addr_source = self .nodes [0 ].add_p2p_connection (P2PInterface ())
205
237
msg = self .setup_addr_msg (2 )
206
- addr_source .send_and_ping (msg )
207
- self .mocktime += 5 * 60
208
- self .nodes [0 ].setmocktime (self .mocktime )
209
- full_outbound_peer .sync_with_ping ()
238
+ self .send_addr_msg (addr_source , msg , [full_outbound_peer ])
210
239
assert_equal (full_outbound_peer .num_ipv4_received , 2 )
211
240
212
241
self .nodes [0 ].disconnect_p2ps ()
213
242
243
+ def send_addrs_and_test_rate_limiting (self , peer , no_relay , new_addrs , total_addrs ):
244
+ """Send an addr message and check that the number of addresses processed and rate-limited is as expected"""
245
+
246
+ peer .send_and_ping (self .setup_rand_addr_msg (new_addrs ))
247
+
248
+ peerinfo = self .nodes [0 ].getpeerinfo ()[0 ]
249
+ addrs_processed = peerinfo ['addr_processed' ]
250
+ addrs_rate_limited = peerinfo ['addr_rate_limited' ]
251
+ self .log .debug (f"addrs_processed = { addrs_processed } , addrs_rate_limited = { addrs_rate_limited } " )
252
+
253
+ if no_relay :
254
+ assert_equal (addrs_processed , 0 )
255
+ assert_equal (addrs_rate_limited , 0 )
256
+ else :
257
+ assert_equal (addrs_processed , min (total_addrs , peer .tokens ))
258
+ assert_equal (addrs_rate_limited , max (0 , total_addrs - peer .tokens ))
259
+
260
+ def rate_limit_tests (self ):
261
+
262
+ self .mocktime = int (time .time ())
263
+ self .restart_node (0 , [])
264
+ self .nodes [0 ].setmocktime (self .mocktime )
265
+
266
+ for contype , no_relay in [("outbound-full-relay" , False ), ("block-relay-only" , True ), ("inbound" , False )]:
267
+ self .log .info (f'Test rate limiting of addr processing for { contype } peers' )
268
+ if contype == "inbound" :
269
+ peer = self .nodes [0 ].add_p2p_connection (AddrReceiver ())
270
+ else :
271
+ peer = self .nodes [0 ].add_outbound_p2p_connection (AddrReceiver (), p2p_idx = 0 , connection_type = contype )
272
+
273
+ # Send 600 addresses. For all but the block-relay-only peer this should result in addresses being processed.
274
+ self .send_addrs_and_test_rate_limiting (peer , no_relay , 600 , 600 )
275
+
276
+ # Send 600 more addresses. For the outbound-full-relay peer (which we send a GETADDR, and thus will
277
+ # process up to 1001 incoming addresses), this means more addresses will be processed.
278
+ self .send_addrs_and_test_rate_limiting (peer , no_relay , 600 , 1200 )
279
+
280
+ # Send 10 more. As we reached the processing limit for all nodes, no more addresses should be procesesd.
281
+ self .send_addrs_and_test_rate_limiting (peer , no_relay , 10 , 1210 )
282
+
283
+ # Advance the time by 100 seconds, permitting the processing of 10 more addresses.
284
+ # Send 200 and verify that 10 are processed.
285
+ self .mocktime += 100
286
+ self .nodes [0 ].setmocktime (self .mocktime )
287
+ peer .increment_tokens (10 )
288
+
289
+ self .send_addrs_and_test_rate_limiting (peer , no_relay , 200 , 1410 )
290
+
291
+ # Advance the time by 1000 seconds, permitting the processing of 100 more addresses.
292
+ # Send 200 and verify that 100 are processed.
293
+ self .mocktime += 1000
294
+ self .nodes [0 ].setmocktime (self .mocktime )
295
+ peer .increment_tokens (100 )
296
+
297
+ self .send_addrs_and_test_rate_limiting (peer , no_relay , 200 , 1610 )
298
+
299
+ self .nodes [0 ].disconnect_p2ps ()
214
300
215
301
if __name__ == '__main__' :
216
302
AddrTest ().main ()
0 commit comments