|
21 | 21 | P2P_SERVICES,
|
22 | 22 | )
|
23 | 23 | from test_framework.test_framework import BitcoinTestFramework
|
24 |
| -from test_framework.util import assert_equal, assert_greater_than |
| 24 | +from test_framework.util import ( |
| 25 | + assert_equal, |
| 26 | + assert_greater_than, |
| 27 | + assert_greater_than_or_equal |
| 28 | +) |
| 29 | + |
| 30 | +ONE_MINUTE = 60 |
| 31 | +TEN_MINUTES = 10 * ONE_MINUTE |
| 32 | +ONE_HOUR = 60 * ONE_MINUTE |
| 33 | +TWO_HOURS = 2 * ONE_HOUR |
| 34 | +ONE_DAY = 24 * ONE_HOUR |
25 | 35 |
|
| 36 | +ADDR_DESTINATIONS_THRESHOLD = 4 |
26 | 37 |
|
27 | 38 | class AddrReceiver(P2PInterface):
|
28 | 39 | num_ipv4_received = 0
|
@@ -85,6 +96,9 @@ def run_test(self):
|
85 | 96 | self.relay_tests()
|
86 | 97 | self.inbound_blackhole_tests()
|
87 | 98 |
|
| 99 | + self.destination_rotates_once_in_24_hours_test() |
| 100 | + self.destination_rotates_more_than_once_over_several_days_test() |
| 101 | + |
88 | 102 | # This test populates the addrman, which can impact the node's behavior
|
89 | 103 | # in subsequent tests
|
90 | 104 | self.getaddr_tests()
|
@@ -362,6 +376,56 @@ def rate_limit_tests(self):
|
362 | 376 |
|
363 | 377 | self.nodes[0].disconnect_p2ps()
|
364 | 378 |
|
| 379 | + def get_nodes_that_received_addr(self, peer, receiver_peer, addr_receivers, |
| 380 | + time_interval_1, time_interval_2): |
| 381 | + |
| 382 | + # Clean addr response related to the initial getaddr. There is no way to avoid initial |
| 383 | + # getaddr because the peer won't self-announce then. |
| 384 | + for addr_receiver in addr_receivers: |
| 385 | + addr_receiver.num_ipv4_received = 0 |
| 386 | + |
| 387 | + for _ in range(10): |
| 388 | + self.mocktime += time_interval_1 |
| 389 | + self.msg.addrs[0].time = self.mocktime + TEN_MINUTES |
| 390 | + self.nodes[0].setmocktime(self.mocktime) |
| 391 | + with self.nodes[0].assert_debug_log(['received: addr (31 bytes) peer=0']): |
| 392 | + peer.send_and_ping(self.msg) |
| 393 | + self.mocktime += time_interval_2 |
| 394 | + self.nodes[0].setmocktime(self.mocktime) |
| 395 | + receiver_peer.sync_with_ping() |
| 396 | + return [node for node in addr_receivers if node.addr_received()] |
| 397 | + |
| 398 | + def destination_rotates_once_in_24_hours_test(self): |
| 399 | + self.restart_node(0, []) |
| 400 | + |
| 401 | + self.log.info('Test within 24 hours an addr relay destination is rotated at most once') |
| 402 | + self.mocktime = int(time.time()) |
| 403 | + self.msg = self.setup_addr_msg(1) |
| 404 | + self.addr_receivers = [] |
| 405 | + peer = self.nodes[0].add_p2p_connection(P2PInterface()) |
| 406 | + receiver_peer = self.nodes[0].add_p2p_connection(AddrReceiver()) |
| 407 | + addr_receivers = [self.nodes[0].add_p2p_connection(AddrReceiver()) for _ in range(20)] |
| 408 | + nodes_received_addr = self.get_nodes_that_received_addr(peer, receiver_peer, addr_receivers, 0, TWO_HOURS) # 10 intervals of 2 hours |
| 409 | + # Per RelayAddress, we would announce these addrs to 2 destinations per day. |
| 410 | + # Since it's at most one rotation, at most 4 nodes can receive ADDR. |
| 411 | + assert_greater_than_or_equal(ADDR_DESTINATIONS_THRESHOLD, len(nodes_received_addr)) |
| 412 | + self.nodes[0].disconnect_p2ps() |
| 413 | + |
| 414 | + def destination_rotates_more_than_once_over_several_days_test(self): |
| 415 | + self.restart_node(0, []) |
| 416 | + |
| 417 | + self.log.info('Test after several days an addr relay destination is rotated more than once') |
| 418 | + self.msg = self.setup_addr_msg(1) |
| 419 | + peer = self.nodes[0].add_p2p_connection(P2PInterface()) |
| 420 | + receiver_peer = self.nodes[0].add_p2p_connection(AddrReceiver()) |
| 421 | + addr_receivers = [self.nodes[0].add_p2p_connection(AddrReceiver()) for _ in range(20)] |
| 422 | + # 10 intervals of 1 day (+ 1 hour, which should be enough to cover 30-min Poisson in most cases) |
| 423 | + nodes_received_addr = self.get_nodes_that_received_addr(peer, receiver_peer, addr_receivers, ONE_DAY, ONE_HOUR) |
| 424 | + # Now that there should have been more than one rotation, more than |
| 425 | + # ADDR_DESTINATIONS_THRESHOLD nodes should have received ADDR. |
| 426 | + assert_greater_than(len(nodes_received_addr), ADDR_DESTINATIONS_THRESHOLD) |
| 427 | + self.nodes[0].disconnect_p2ps() |
| 428 | + |
365 | 429 |
|
366 | 430 | if __name__ == '__main__':
|
367 | 431 | AddrTest().main()
|
0 commit comments