[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.
This commit is contained in:
stratospher 2023-12-01 12:54:43 +05:30
parent a897866109
commit 2cc8ca19f4
1 changed files with 100 additions and 71 deletions

View File

@ -13,7 +13,6 @@ import platform
import time
import test_framework.messages
from test_framework.netutil import ADDRMAN_NEW_BUCKET_COUNT, ADDRMAN_TRIED_BUCKET_COUNT, ADDRMAN_BUCKET_SIZE
from test_framework.p2p import (
P2PInterface,
P2P_SERVICES,
@ -42,6 +41,20 @@ def assert_net_servicesnames(servicesflag, servicenames):
assert servicesflag_generated == servicesflag
def seed_addrman(node):
""" Populate the addrman with addresses from different networks.
Here 2 ipv4, 2 ipv6, 1 cjdns, 2 onion and 1 i2p addresses are added.
"""
node.addpeeraddress(address="1.2.3.4", tried=True, port=8333)
node.addpeeraddress(address="2.0.0.0", port=8333)
node.addpeeraddress(address="1233:3432:2434:2343:3234:2345:6546:4534", tried=True, port=8333)
node.addpeeraddress(address="2803:0:1234:abcd::1", port=45324)
node.addpeeraddress(address="fc00:1:2:3:4:5:6:7", port=8333)
node.addpeeraddress(address="pg6mmjiyjmcrsslvykfwnntlaru7p5svn6y2ymmju6nubxndf4pscryd.onion", tried=True, port=8333)
node.addpeeraddress(address="nrfj6inpyf73gpkyool35hcmne5zwfmse3jl3aw23vk7chdemalyaqad.onion", port=45324, tried=True)
node.addpeeraddress(address="c4gfnttsuwqomiygupdqqqyy5y5emnk5c73hrfvatri67prd7vyq.b32.i2p", port=8333)
class NetTest(BitcoinTestFramework):
def set_test_params(self):
self.num_nodes = 2
@ -376,25 +389,33 @@ class NetTest(BitcoinTestFramework):
def test_getaddrmaninfo(self):
self.log.info("Test getaddrmaninfo")
self.restart_node(1, extra_args=["-cjdnsreachable", "-test=addrman"], clear_addrman=True)
node = self.nodes[1]
seed_addrman(node)
# current count of ipv4 addresses in addrman is {'new':1, 'tried':1}
self.log.info("Test that count of addresses in addrman match expected values")
expected_network_count = {
'all_networks': {'new': 4, 'tried': 4, 'total': 8},
'ipv4': {'new': 1, 'tried': 1, 'total': 2},
'ipv6': {'new': 1, 'tried': 1, 'total': 2},
'onion': {'new': 0, 'tried': 2, 'total': 2},
'i2p': {'new': 1, 'tried': 0, 'total': 1},
'cjdns': {'new': 1, 'tried': 0, 'total': 1},
}
self.log.debug("Test that count of addresses in addrman match expected values")
res = node.getaddrmaninfo()
assert_equal(res["ipv4"]["new"], 1)
assert_equal(res["ipv4"]["tried"], 1)
assert_equal(res["ipv4"]["total"], 2)
assert_equal(res["all_networks"]["new"], 1)
assert_equal(res["all_networks"]["tried"], 1)
assert_equal(res["all_networks"]["total"], 2)
for net in ["ipv6", "onion", "i2p", "cjdns"]:
assert_equal(res[net]["new"], 0)
assert_equal(res[net]["tried"], 0)
assert_equal(res[net]["total"], 0)
for network, count in expected_network_count.items():
assert_equal(res[network]['new'], count['new'])
assert_equal(res[network]['tried'], count['tried'])
assert_equal(res[network]['total'], count['total'])
def test_getrawaddrman(self):
self.log.info("Test getrawaddrman")
self.restart_node(1, extra_args=["-cjdnsreachable", "-test=addrman"], clear_addrman=True)
node = self.nodes[1]
self.addr_time = int(time.time())
node.setmocktime(self.addr_time)
seed_addrman(node)
self.log.debug("Test that getrawaddrman is a hidden RPC")
# It is hidden from general help, but its detailed help may be called directly.
@ -416,88 +437,96 @@ class NetTest(BitcoinTestFramework):
getrawaddrman = node.getrawaddrman()
getaddrmaninfo = node.getaddrmaninfo()
for (table_name, table_info) in expected.items():
assert_equal(len(getrawaddrman[table_name]), len(table_info["entries"]))
assert_equal(len(getrawaddrman[table_name]), len(table_info))
assert_equal(len(getrawaddrman[table_name]), getaddrmaninfo["all_networks"][table_name])
for bucket_position in getrawaddrman[table_name].keys():
bucket = int(bucket_position.split("/")[0])
position = int(bucket_position.split("/")[1])
# bucket and position only be sanity checked here as the
# test-addrman isn't deterministic
assert 0 <= int(bucket) < table_info["bucket_count"]
assert 0 <= int(position) < ADDRMAN_BUCKET_SIZE
entry = getrawaddrman[table_name][bucket_position]
expected_entry = list(filter(lambda e: e["address"] == entry["address"], table_info["entries"]))[0]
expected_entry = list(filter(lambda e: e["address"] == entry["address"], table_info))[0]
assert bucket_position == expected_entry["bucket_position"]
check_addr_information(entry, expected_entry)
# we expect one addrman new and tried table entry, which were added in a previous test
# we expect 4 new and 4 tried table entries in the addrman which were added using seed_addrman()
expected = {
"new": {
"bucket_count": ADDRMAN_NEW_BUCKET_COUNT,
"entries": [
"new": [
{
"bucket_position": "82/8",
"address": "2.0.0.0",
"port": 8333,
"services": 9,
"network": "ipv4",
"source": "2.0.0.0",
"source_network": "ipv4",
}
]
},
"tried": {
"bucket_count": ADDRMAN_TRIED_BUCKET_COUNT,
"entries": [
},
{
"bucket_position": "336/24",
"address": "fc00:1:2:3:4:5:6:7",
"port": 8333,
"services": 9,
"network": "cjdns",
"source": "fc00:1:2:3:4:5:6:7",
"source_network": "cjdns",
},
{
"bucket_position": "963/46",
"address": "c4gfnttsuwqomiygupdqqqyy5y5emnk5c73hrfvatri67prd7vyq.b32.i2p",
"port": 8333,
"services": 9,
"network": "i2p",
"source": "c4gfnttsuwqomiygupdqqqyy5y5emnk5c73hrfvatri67prd7vyq.b32.i2p",
"source_network": "i2p",
},
{
"bucket_position": "613/6",
"address": "2803:0:1234:abcd::1",
"services": 9,
"network": "ipv6",
"source": "2803:0:1234:abcd::1",
"source_network": "ipv6",
"port": 45324,
}
],
"tried": [
{
"bucket_position": "6/33",
"address": "1.2.3.4",
"port": 8333,
"services": 9,
"network": "ipv4",
"source": "1.2.3.4",
"source_network": "ipv4",
},
{
"bucket_position": "197/34",
"address": "1233:3432:2434:2343:3234:2345:6546:4534",
"port": 8333,
"services": 9,
"network": "ipv6",
"source": "1233:3432:2434:2343:3234:2345:6546:4534",
"source_network": "ipv6",
},
{
"bucket_position": "72/61",
"address": "pg6mmjiyjmcrsslvykfwnntlaru7p5svn6y2ymmju6nubxndf4pscryd.onion",
"port": 8333,
"services": 9,
"network": "onion",
"source": "pg6mmjiyjmcrsslvykfwnntlaru7p5svn6y2ymmju6nubxndf4pscryd.onion",
"source_network": "onion"
},
{
"bucket_position": "139/46",
"address": "nrfj6inpyf73gpkyool35hcmne5zwfmse3jl3aw23vk7chdemalyaqad.onion",
"services": 9,
"network": "onion",
"source": "nrfj6inpyf73gpkyool35hcmne5zwfmse3jl3aw23vk7chdemalyaqad.onion",
"source_network": "onion",
"port": 45324,
}
]
}
]
}
self.log.debug("Test that the getrawaddrman contains information about the addresses added in a previous test")
check_getrawaddrman_entries(expected)
self.log.debug("Add one new address to each addrman table")
expected["new"]["entries"].append({
"address": "2803:0:1234:abcd::1",
"services": 9,
"network": "ipv6",
"source": "2803:0:1234:abcd::1",
"source_network": "ipv6",
"port": -1, # set once addpeeraddress is successful
})
expected["tried"]["entries"].append({
"address": "nrfj6inpyf73gpkyool35hcmne5zwfmse3jl3aw23vk7chdemalyaqad.onion",
"services": 9,
"network": "onion",
"source": "nrfj6inpyf73gpkyool35hcmne5zwfmse3jl3aw23vk7chdemalyaqad.onion",
"source_network": "onion",
"port": -1, # set once addpeeraddress is successful
})
port = 0
for (table_name, table_info) in expected.items():
# There's a slight chance that the to-be-added address collides with an already
# present table entry. To avoid this, we increment the port until an address has been
# added. Incrementing the port changes the position in the new table bucket (bucket
# stays the same) and changes both the bucket and the position in the tried table.
while True:
if node.addpeeraddress(address=table_info["entries"][1]["address"], port=port, tried=table_name == "tried")["success"]:
table_info["entries"][1]["port"] = port
self.log.debug(f"Added {table_info['entries'][1]['address']} to {table_name} table")
break
else:
port += 1
self.log.debug("Test that the newly added addresses appear in getrawaddrman")
self.log.debug("Test that getrawaddrman contains information about newly added addresses in each addrman table")
check_getrawaddrman_entries(expected)