Skip to content

Commit 2cc8ca1

Browse files
committed
[test] Use deterministic addrman in addrman info tests
The nodes are restarted with an empty addrman and populated with addresses from different networks using a helper function. We can safely add multiple addresses to addrman tables without worrying about unpredictable collisions since bucket:position is fixed in a deterministic addrman.
1 parent a897866 commit 2cc8ca1

File tree

1 file changed

+99
-70
lines changed

1 file changed

+99
-70
lines changed

test/functional/rpc_net.py

Lines changed: 99 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
import time
1414

1515
import test_framework.messages
16-
from test_framework.netutil import ADDRMAN_NEW_BUCKET_COUNT, ADDRMAN_TRIED_BUCKET_COUNT, ADDRMAN_BUCKET_SIZE
1716
from test_framework.p2p import (
1817
P2PInterface,
1918
P2P_SERVICES,
@@ -42,6 +41,20 @@ def assert_net_servicesnames(servicesflag, servicenames):
4241
assert servicesflag_generated == servicesflag
4342

4443

44+
def seed_addrman(node):
45+
""" Populate the addrman with addresses from different networks.
46+
Here 2 ipv4, 2 ipv6, 1 cjdns, 2 onion and 1 i2p addresses are added.
47+
"""
48+
node.addpeeraddress(address="1.2.3.4", tried=True, port=8333)
49+
node.addpeeraddress(address="2.0.0.0", port=8333)
50+
node.addpeeraddress(address="1233:3432:2434:2343:3234:2345:6546:4534", tried=True, port=8333)
51+
node.addpeeraddress(address="2803:0:1234:abcd::1", port=45324)
52+
node.addpeeraddress(address="fc00:1:2:3:4:5:6:7", port=8333)
53+
node.addpeeraddress(address="pg6mmjiyjmcrsslvykfwnntlaru7p5svn6y2ymmju6nubxndf4pscryd.onion", tried=True, port=8333)
54+
node.addpeeraddress(address="nrfj6inpyf73gpkyool35hcmne5zwfmse3jl3aw23vk7chdemalyaqad.onion", port=45324, tried=True)
55+
node.addpeeraddress(address="c4gfnttsuwqomiygupdqqqyy5y5emnk5c73hrfvatri67prd7vyq.b32.i2p", port=8333)
56+
57+
4558
class NetTest(BitcoinTestFramework):
4659
def set_test_params(self):
4760
self.num_nodes = 2
@@ -376,25 +389,33 @@ def test_sendmsgtopeer(self):
376389

377390
def test_getaddrmaninfo(self):
378391
self.log.info("Test getaddrmaninfo")
392+
self.restart_node(1, extra_args=["-cjdnsreachable", "-test=addrman"], clear_addrman=True)
379393
node = self.nodes[1]
394+
seed_addrman(node)
395+
396+
expected_network_count = {
397+
'all_networks': {'new': 4, 'tried': 4, 'total': 8},
398+
'ipv4': {'new': 1, 'tried': 1, 'total': 2},
399+
'ipv6': {'new': 1, 'tried': 1, 'total': 2},
400+
'onion': {'new': 0, 'tried': 2, 'total': 2},
401+
'i2p': {'new': 1, 'tried': 0, 'total': 1},
402+
'cjdns': {'new': 1, 'tried': 0, 'total': 1},
403+
}
380404

381-
# current count of ipv4 addresses in addrman is {'new':1, 'tried':1}
382-
self.log.info("Test that count of addresses in addrman match expected values")
405+
self.log.debug("Test that count of addresses in addrman match expected values")
383406
res = node.getaddrmaninfo()
384-
assert_equal(res["ipv4"]["new"], 1)
385-
assert_equal(res["ipv4"]["tried"], 1)
386-
assert_equal(res["ipv4"]["total"], 2)
387-
assert_equal(res["all_networks"]["new"], 1)
388-
assert_equal(res["all_networks"]["tried"], 1)
389-
assert_equal(res["all_networks"]["total"], 2)
390-
for net in ["ipv6", "onion", "i2p", "cjdns"]:
391-
assert_equal(res[net]["new"], 0)
392-
assert_equal(res[net]["tried"], 0)
393-
assert_equal(res[net]["total"], 0)
407+
for network, count in expected_network_count.items():
408+
assert_equal(res[network]['new'], count['new'])
409+
assert_equal(res[network]['tried'], count['tried'])
410+
assert_equal(res[network]['total'], count['total'])
394411

395412
def test_getrawaddrman(self):
396413
self.log.info("Test getrawaddrman")
414+
self.restart_node(1, extra_args=["-cjdnsreachable", "-test=addrman"], clear_addrman=True)
397415
node = self.nodes[1]
416+
self.addr_time = int(time.time())
417+
node.setmocktime(self.addr_time)
418+
seed_addrman(node)
398419

399420
self.log.debug("Test that getrawaddrman is a hidden RPC")
400421
# It is hidden from general help, but its detailed help may be called directly.
@@ -416,88 +437,96 @@ def check_getrawaddrman_entries(expected):
416437
getrawaddrman = node.getrawaddrman()
417438
getaddrmaninfo = node.getaddrmaninfo()
418439
for (table_name, table_info) in expected.items():
419-
assert_equal(len(getrawaddrman[table_name]), len(table_info["entries"]))
440+
assert_equal(len(getrawaddrman[table_name]), len(table_info))
420441
assert_equal(len(getrawaddrman[table_name]), getaddrmaninfo["all_networks"][table_name])
421442

422443
for bucket_position in getrawaddrman[table_name].keys():
423-
bucket = int(bucket_position.split("/")[0])
424-
position = int(bucket_position.split("/")[1])
425-
426-
# bucket and position only be sanity checked here as the
427-
# test-addrman isn't deterministic
428-
assert 0 <= int(bucket) < table_info["bucket_count"]
429-
assert 0 <= int(position) < ADDRMAN_BUCKET_SIZE
430-
431444
entry = getrawaddrman[table_name][bucket_position]
432-
expected_entry = list(filter(lambda e: e["address"] == entry["address"], table_info["entries"]))[0]
445+
expected_entry = list(filter(lambda e: e["address"] == entry["address"], table_info))[0]
446+
assert bucket_position == expected_entry["bucket_position"]
433447
check_addr_information(entry, expected_entry)
434448

435-
# we expect one addrman new and tried table entry, which were added in a previous test
449+
# we expect 4 new and 4 tried table entries in the addrman which were added using seed_addrman()
436450
expected = {
437-
"new": {
438-
"bucket_count": ADDRMAN_NEW_BUCKET_COUNT,
439-
"entries": [
451+
"new": [
440452
{
453+
"bucket_position": "82/8",
441454
"address": "2.0.0.0",
442455
"port": 8333,
443456
"services": 9,
444457
"network": "ipv4",
445458
"source": "2.0.0.0",
446459
"source_network": "ipv4",
460+
},
461+
{
462+
"bucket_position": "336/24",
463+
"address": "fc00:1:2:3:4:5:6:7",
464+
"port": 8333,
465+
"services": 9,
466+
"network": "cjdns",
467+
"source": "fc00:1:2:3:4:5:6:7",
468+
"source_network": "cjdns",
469+
},
470+
{
471+
"bucket_position": "963/46",
472+
"address": "c4gfnttsuwqomiygupdqqqyy5y5emnk5c73hrfvatri67prd7vyq.b32.i2p",
473+
"port": 8333,
474+
"services": 9,
475+
"network": "i2p",
476+
"source": "c4gfnttsuwqomiygupdqqqyy5y5emnk5c73hrfvatri67prd7vyq.b32.i2p",
477+
"source_network": "i2p",
478+
},
479+
{
480+
"bucket_position": "613/6",
481+
"address": "2803:0:1234:abcd::1",
482+
"services": 9,
483+
"network": "ipv6",
484+
"source": "2803:0:1234:abcd::1",
485+
"source_network": "ipv6",
486+
"port": 45324,
447487
}
448-
]
449-
},
450-
"tried": {
451-
"bucket_count": ADDRMAN_TRIED_BUCKET_COUNT,
452-
"entries": [
488+
],
489+
"tried": [
453490
{
491+
"bucket_position": "6/33",
454492
"address": "1.2.3.4",
455493
"port": 8333,
456494
"services": 9,
457495
"network": "ipv4",
458496
"source": "1.2.3.4",
459497
"source_network": "ipv4",
498+
},
499+
{
500+
"bucket_position": "197/34",
501+
"address": "1233:3432:2434:2343:3234:2345:6546:4534",
502+
"port": 8333,
503+
"services": 9,
504+
"network": "ipv6",
505+
"source": "1233:3432:2434:2343:3234:2345:6546:4534",
506+
"source_network": "ipv6",
507+
},
508+
{
509+
"bucket_position": "72/61",
510+
"address": "pg6mmjiyjmcrsslvykfwnntlaru7p5svn6y2ymmju6nubxndf4pscryd.onion",
511+
"port": 8333,
512+
"services": 9,
513+
"network": "onion",
514+
"source": "pg6mmjiyjmcrsslvykfwnntlaru7p5svn6y2ymmju6nubxndf4pscryd.onion",
515+
"source_network": "onion"
516+
},
517+
{
518+
"bucket_position": "139/46",
519+
"address": "nrfj6inpyf73gpkyool35hcmne5zwfmse3jl3aw23vk7chdemalyaqad.onion",
520+
"services": 9,
521+
"network": "onion",
522+
"source": "nrfj6inpyf73gpkyool35hcmne5zwfmse3jl3aw23vk7chdemalyaqad.onion",
523+
"source_network": "onion",
524+
"port": 45324,
460525
}
461-
]
462-
}
526+
]
463527
}
464528

465-
self.log.debug("Test that the getrawaddrman contains information about the addresses added in a previous test")
466-
check_getrawaddrman_entries(expected)
467-
468-
self.log.debug("Add one new address to each addrman table")
469-
expected["new"]["entries"].append({
470-
"address": "2803:0:1234:abcd::1",
471-
"services": 9,
472-
"network": "ipv6",
473-
"source": "2803:0:1234:abcd::1",
474-
"source_network": "ipv6",
475-
"port": -1, # set once addpeeraddress is successful
476-
})
477-
expected["tried"]["entries"].append({
478-
"address": "nrfj6inpyf73gpkyool35hcmne5zwfmse3jl3aw23vk7chdemalyaqad.onion",
479-
"services": 9,
480-
"network": "onion",
481-
"source": "nrfj6inpyf73gpkyool35hcmne5zwfmse3jl3aw23vk7chdemalyaqad.onion",
482-
"source_network": "onion",
483-
"port": -1, # set once addpeeraddress is successful
484-
})
485-
486-
port = 0
487-
for (table_name, table_info) in expected.items():
488-
# There's a slight chance that the to-be-added address collides with an already
489-
# present table entry. To avoid this, we increment the port until an address has been
490-
# added. Incrementing the port changes the position in the new table bucket (bucket
491-
# stays the same) and changes both the bucket and the position in the tried table.
492-
while True:
493-
if node.addpeeraddress(address=table_info["entries"][1]["address"], port=port, tried=table_name == "tried")["success"]:
494-
table_info["entries"][1]["port"] = port
495-
self.log.debug(f"Added {table_info['entries'][1]['address']} to {table_name} table")
496-
break
497-
else:
498-
port += 1
499-
500-
self.log.debug("Test that the newly added addresses appear in getrawaddrman")
529+
self.log.debug("Test that getrawaddrman contains information about newly added addresses in each addrman table")
501530
check_getrawaddrman_entries(expected)
502531

503532

0 commit comments

Comments
 (0)