#include <addrdb.h>
#include <addrman.h>
#include <addrman_impl.h>
#include <chainparams.h>
#include <clientversion.h>
#include <hash.h>
#include <netbase.h>
#include <random.h>
#include <test/data/asmap.raw.h>
#include <test/util/setup_common.h>
#include <util/asmap.h>
#include <util/string.h>
#include <boost/test/unit_test.hpp>
#include <optional>
#include <string>
using namespace std::literals;
using node::NodeContext;
using util::ToString;
static NetGroupManager EMPTY_NETGROUPMAN{std::vector<bool>()};
static const bool DETERMINISTIC{true};
static int32_t GetCheckRatio(const NodeContext& node_ctx)
{
return std::clamp<int32_t>(node_ctx.args->GetIntArg("-checkaddrman", 100), 0, 1000000);
}
static CNetAddr ResolveIP(const std::string& ip)
{
const std::optional<CNetAddr> addr{LookupHost(ip, false)};
BOOST_CHECK_MESSAGE(addr.has_value(), strprintf("failed to resolve: %s", ip));
return addr.value_or(CNetAddr{});
}
static CService ResolveService(const std::string& ip, uint16_t port = 0)
{
const std::optional<CService> serv{Lookup(ip, port, false)};
BOOST_CHECK_MESSAGE(serv.has_value(), strprintf("failed to resolve: %s:%i", ip, port));
return serv.value_or(CService{});
}
static std::vector<bool> FromBytes(std::span<const std::byte> source)
{
int vector_size(source.size() * 8);
std::vector<bool> result(vector_size);
for (int byte_i = 0; byte_i < vector_size / 8; ++byte_i) {
uint8_t cur_byte{std::to_integer<uint8_t>(source[byte_i])};
for (int bit_i = 0; bit_i < 8; ++bit_i) {
result[byte_i * 8 + bit_i] = (cur_byte >> bit_i) & 1;
}
}
return result;
}
BOOST_FIXTURE_TEST_SUITE(addrman_tests, BasicTestingSetup)
BOOST_AUTO_TEST_CASE(addrman_simple)
{
auto addrman = std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, DETERMINISTIC, GetCheckRatio(m_node));
CNetAddr source = ResolveIP("252.2.2.2");
BOOST_CHECK_EQUAL(addrman->Size(), 0U);
auto addr_null = addrman->Select().first;
BOOST_CHECK_EQUAL(addr_null.ToStringAddrPort(), "[::]:0");
CService addr1 = ResolveService("250.1.1.1", 8333);
BOOST_CHECK(addrman->Add({CAddress(addr1, NODE_NONE)}, source));
BOOST_CHECK_EQUAL(addrman->Size(), 1U);
auto addr_ret1 = addrman->Select().first;
BOOST_CHECK_EQUAL(addr_ret1.ToStringAddrPort(), "250.1.1.1:8333");
CService addr1_dup = ResolveService("250.1.1.1", 8333);
BOOST_CHECK(!addrman->Add({CAddress(addr1_dup, NODE_NONE)}, source));
BOOST_CHECK_EQUAL(addrman->Size(), 1U);
CService addr2 = ResolveService("250.1.1.2", 8333);
BOOST_CHECK(addrman->Add({CAddress(addr2, NODE_NONE)}, source));
BOOST_CHECK(addrman->Size() >= 1);
addrman = std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, DETERMINISTIC, GetCheckRatio(m_node));
std::vector<CAddress> vAddr;
vAddr.emplace_back(ResolveService("250.1.1.3", 8333), NODE_NONE);
vAddr.emplace_back(ResolveService("250.1.1.4", 8333), NODE_NONE);
BOOST_CHECK(addrman->Add(vAddr, source));
BOOST_CHECK(addrman->Size() >= 1);
}
BOOST_AUTO_TEST_CASE(addrman_ports)
{
auto addrman = std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, DETERMINISTIC, GetCheckRatio(m_node));
CNetAddr source = ResolveIP("252.2.2.2");
BOOST_CHECK_EQUAL(addrman->Size(), 0U);
CService addr1 = ResolveService("250.1.1.1", 8333);
BOOST_CHECK(addrman->Add({CAddress(addr1, NODE_NONE)}, source));
BOOST_CHECK_EQUAL(addrman->Size(), 1U);
CService addr1_port = ResolveService("250.1.1.1", 8334);
BOOST_CHECK(addrman->Add({CAddress(addr1_port, NODE_NONE)}, source));
BOOST_CHECK_EQUAL(addrman->Size(), 2U);
auto addr_ret2 = addrman->Select().first;
BOOST_CHECK(addr_ret2.ToStringAddrPort() == "250.1.1.1:8333" || addr_ret2.ToStringAddrPort() == "250.1.1.1:8334");
addrman->Good(CAddress(addr1_port, NODE_NONE));
BOOST_CHECK_EQUAL(addrman->Size(), 2U);
bool new_only = true;
auto addr_ret3 = addrman->Select(new_only).first;
BOOST_CHECK_EQUAL(addr_ret3.ToStringAddrPort(), "250.1.1.1:8333");
}
BOOST_AUTO_TEST_CASE(addrman_select)
{
auto addrman = std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, DETERMINISTIC, GetCheckRatio(m_node));
BOOST_CHECK(!addrman->Select(false).first.IsValid());
BOOST_CHECK(!addrman->Select(true).first.IsValid());
CNetAddr source = ResolveIP("252.2.2.2");
CService addr1 = ResolveService("250.1.1.1", 8333);
BOOST_CHECK(addrman->Add({CAddress(addr1, NODE_NONE)}, source));
BOOST_CHECK_EQUAL(addrman->Size(), 1U);
BOOST_CHECK(addrman->Select(true).first == addr1);
BOOST_CHECK(addrman->Select(false).first == addr1);
BOOST_CHECK(addrman->Good(CAddress(addr1, NODE_NONE)));
BOOST_CHECK_EQUAL(addrman->Size(), 1U);
BOOST_CHECK(!addrman->Select(true).first.IsValid());
BOOST_CHECK(addrman->Select().first == addr1);
BOOST_CHECK_EQUAL(addrman->Size(), 1U);
CService addr2 = ResolveService("250.3.1.1", 8333);
BOOST_CHECK(addrman->Add({CAddress(addr2, NODE_NONE)}, addr2));
BOOST_CHECK(addrman->Select(true).first == addr2);
CService addr3 = ResolveService("250.3.2.2", 9999);
CService addr4 = ResolveService("250.3.3.3", 9999);
BOOST_CHECK(addrman->Add({CAddress(addr3, NODE_NONE)}, addr2));
BOOST_CHECK(addrman->Add({CAddress(addr4, NODE_NONE)}, ResolveService("250.4.1.1", 8333)));
CService addr5 = ResolveService("250.4.4.4", 8333);
CService addr6 = ResolveService("250.4.5.5", 7777);
CService addr7 = ResolveService("250.4.6.6", 8333);
BOOST_CHECK(addrman->Add({CAddress(addr5, NODE_NONE)}, addr3));
BOOST_CHECK(addrman->Good(CAddress(addr5, NODE_NONE)));
BOOST_CHECK(addrman->Add({CAddress(addr6, NODE_NONE)}, addr3));
BOOST_CHECK(addrman->Good(CAddress(addr6, NODE_NONE)));
BOOST_CHECK(addrman->Add({CAddress(addr7, NODE_NONE)}, ResolveService("250.1.1.3", 8333)));
BOOST_CHECK(addrman->Good(CAddress(addr7, NODE_NONE)));
BOOST_CHECK_EQUAL(addrman->Size(), 7U);
std::set<uint16_t> ports;
for (int i = 0; i < 20; ++i) {
ports.insert(addrman->Select().first.GetPort());
}
BOOST_CHECK_EQUAL(ports.size(), 3U);
}
BOOST_AUTO_TEST_CASE(addrman_select_by_network)
{
auto addrman = std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, DETERMINISTIC, GetCheckRatio(m_node));
BOOST_CHECK(!addrman->Select(true, {NET_IPV4}).first.IsValid());
BOOST_CHECK(!addrman->Select(false, {NET_IPV4}).first.IsValid());
CNetAddr source = ResolveIP("252.2.2.2");
CService addr1 = ResolveService("250.1.1.1", 8333);
BOOST_CHECK(addrman->Add({CAddress(addr1, NODE_NONE)}, source));
BOOST_CHECK(addrman->Select(true, {NET_IPV4}).first == addr1);
BOOST_CHECK(addrman->Select(false, {NET_IPV4}).first == addr1);
BOOST_CHECK(!addrman->Select(false, {NET_IPV6}).first.IsValid());
BOOST_CHECK(!addrman->Select(false, {NET_ONION}).first.IsValid());
BOOST_CHECK(!addrman->Select(false, {NET_I2P}).first.IsValid());
BOOST_CHECK(!addrman->Select(false, {NET_CJDNS}).first.IsValid());
BOOST_CHECK(!addrman->Select(true, {NET_CJDNS}).first.IsValid());
BOOST_CHECK(addrman->Select(false).first == addr1);
CAddress i2p_addr;
i2p_addr.SetSpecial("udhdrtrcetjm5sxzskjyr5ztpeszydbh4dpl3pl4utgqqw2v4jna.b32.i2p");
BOOST_CHECK(addrman->Add({i2p_addr}, source));
BOOST_CHECK(addrman->Select(true, {NET_I2P}).first == i2p_addr);
BOOST_CHECK(addrman->Select(false, {NET_I2P}).first == i2p_addr);
BOOST_CHECK(addrman->Select(false, {NET_IPV4}).first == addr1);
std::unordered_set<Network> nets_with_entries = {NET_IPV4, NET_I2P};
BOOST_CHECK(addrman->Select(false, nets_with_entries).first.IsValid());
BOOST_CHECK(!addrman->Select(false, {NET_IPV6}).first.IsValid());
BOOST_CHECK(!addrman->Select(false, {NET_ONION}).first.IsValid());
BOOST_CHECK(!addrman->Select(false, {NET_CJDNS}).first.IsValid());
std::unordered_set<Network> nets_without_entries = {NET_IPV6, NET_ONION, NET_CJDNS};
BOOST_CHECK(!addrman->Select(false, nets_without_entries).first.IsValid());
BOOST_CHECK(addrman->Good(i2p_addr));
BOOST_CHECK(!addrman->Select(true, {NET_I2P}).first.IsValid());
BOOST_CHECK(addrman->Select(false, {NET_I2P}).first == i2p_addr);
CAddress i2p_addr2;
i2p_addr2.SetSpecial("c4gfnttsuwqomiygupdqqqyy5y5emnk5c73hrfvatri67prd7vyq.b32.i2p");
BOOST_CHECK(addrman->Add({i2p_addr2}, source));
BOOST_CHECK(addrman->Select(true, {NET_I2P}).first == i2p_addr2);
bool new_selected{false};
bool tried_selected{false};
int counter = 256;
while (--counter > 0 && (!new_selected || !tried_selected)) {
const CAddress selected{addrman->Select(false, {NET_I2P}).first};
BOOST_REQUIRE(selected == i2p_addr || selected == i2p_addr2);
if (selected == i2p_addr) {
tried_selected = true;
} else {
new_selected = true;
}
}
BOOST_CHECK(new_selected);
BOOST_CHECK(tried_selected);
}
BOOST_AUTO_TEST_CASE(addrman_select_special)
{
auto addrman = std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, false, GetCheckRatio(m_node));
CNetAddr source = ResolveIP("252.2.2.2");
CAddress i2p_addr;
i2p_addr.SetSpecial("udhdrtrcetjm5sxzskjyr5ztpeszydbh4dpl3pl4utgqqw2v4jna.b32.i2p");
BOOST_CHECK(addrman->Add({i2p_addr}, source));
BOOST_CHECK(addrman->Good(i2p_addr));
CService addr1 = ResolveService("250.1.1.3", 8333);
BOOST_CHECK(addrman->Add({CAddress(addr1, NODE_NONE)}, source));
BOOST_CHECK(addrman->Select(false, {NET_IPV4}).first == addr1);
}
BOOST_AUTO_TEST_CASE(addrman_new_collisions)
{
auto addrman = std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, DETERMINISTIC, GetCheckRatio(m_node));
CNetAddr source = ResolveIP("252.2.2.2");
uint32_t num_addrs{0};
BOOST_CHECK_EQUAL(addrman->Size(), num_addrs);
while (num_addrs < 22) { CService addr = ResolveService("250.1.1." + ToString(++num_addrs));
BOOST_CHECK(addrman->Add({CAddress(addr, NODE_NONE)}, source));
BOOST_CHECK_EQUAL(addrman->Size(), num_addrs);
}
CService addr1 = ResolveService("250.1.1." + ToString(++num_addrs));
uint32_t collisions{1};
BOOST_CHECK(addrman->Add({CAddress(addr1, NODE_NONE)}, source));
BOOST_CHECK_EQUAL(addrman->Size(), num_addrs - collisions);
CService addr2 = ResolveService("250.1.1." + ToString(++num_addrs));
BOOST_CHECK(addrman->Add({CAddress(addr2, NODE_NONE)}, source));
BOOST_CHECK_EQUAL(addrman->Size(), num_addrs - collisions);
}
BOOST_AUTO_TEST_CASE(addrman_new_multiplicity)
{
auto addrman = std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, DETERMINISTIC, GetCheckRatio(m_node));
CAddress addr{CAddress(ResolveService("253.3.3.3", 8333), NODE_NONE)};
const auto start_time{Now<NodeSeconds>()};
addr.nTime = start_time;
for (unsigned int i = 1; i < 20; ++i) {
std::string addr_ip{ToString(i % 256) + "." + ToString(i >> 8 % 256) + ".1.1"};
CNetAddr source{ResolveIP(addr_ip)};
addrman->Add({addr}, source);
}
AddressPosition addr_pos = addrman->FindAddressEntry(addr).value();
BOOST_CHECK_EQUAL(addr_pos.multiplicity, 1U);
BOOST_CHECK_EQUAL(addrman->Size(), 1U);
for (unsigned int i = 1; i < 400; ++i) {
std::string addr_ip{ToString(i % 256) + "." + ToString(i >> 8 % 256) + ".1.1"};
CNetAddr source{ResolveIP(addr_ip)};
addr.nTime = start_time + std::chrono::seconds{i};
addrman->Add({addr}, source);
}
AddressPosition addr_pos_multi = addrman->FindAddressEntry(addr).value();
BOOST_CHECK_EQUAL(addr_pos_multi.multiplicity, 8U);
BOOST_CHECK_EQUAL(addrman->Size(), 1U);
}
BOOST_AUTO_TEST_CASE(addrman_tried_collisions)
{
auto addrman = std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, DETERMINISTIC, GetCheckRatio(m_node));
CNetAddr source = ResolveIP("252.2.2.2");
uint32_t num_addrs{0};
BOOST_CHECK_EQUAL(addrman->Size(), num_addrs);
while (num_addrs < 35) { CService addr = ResolveService("250.1.1." + ToString(++num_addrs));
BOOST_CHECK(addrman->Add({CAddress(addr, NODE_NONE)}, source));
BOOST_CHECK(addrman->Good(CAddress(addr, NODE_NONE)));
}
CService addr1 = ResolveService("250.1.1." + ToString(++num_addrs));
BOOST_CHECK(addrman->Add({CAddress(addr1, NODE_NONE)}, source));
BOOST_CHECK(!addrman->Good(CAddress(addr1, NODE_NONE)));
CService addr2 = ResolveService("250.1.1." + ToString(++num_addrs));
BOOST_CHECK(addrman->Add({CAddress(addr2, NODE_NONE)}, source));
BOOST_CHECK(addrman->Good(CAddress(addr2, NODE_NONE)));
}
BOOST_AUTO_TEST_CASE(addrman_getaddr)
{
auto addrman = std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, DETERMINISTIC, GetCheckRatio(m_node));
BOOST_CHECK_EQUAL(addrman->Size(), 0U);
std::vector<CAddress> vAddr1 = addrman->GetAddr(0, 0, std::nullopt);
BOOST_CHECK_EQUAL(vAddr1.size(), 0U);
CAddress addr1 = CAddress(ResolveService("250.250.2.1", 8333), NODE_NONE);
addr1.nTime = Now<NodeSeconds>(); CAddress addr2 = CAddress(ResolveService("250.251.2.2", 9999), NODE_NONE);
addr2.nTime = Now<NodeSeconds>();
CAddress addr3 = CAddress(ResolveService("251.252.2.3", 8333), NODE_NONE);
addr3.nTime = Now<NodeSeconds>();
CAddress addr4 = CAddress(ResolveService("252.253.3.4", 8333), NODE_NONE);
addr4.nTime = Now<NodeSeconds>();
CAddress addr5 = CAddress(ResolveService("252.254.4.5", 8333), NODE_NONE);
addr5.nTime = Now<NodeSeconds>();
CNetAddr source1 = ResolveIP("250.1.2.1");
CNetAddr source2 = ResolveIP("250.2.3.3");
BOOST_CHECK(addrman->Add({addr1, addr3, addr5}, source1));
BOOST_CHECK(addrman->Add({addr2, addr4}, source2));
BOOST_CHECK_EQUAL(addrman->GetAddr(0, 0, std::nullopt).size(), 5U);
BOOST_CHECK_EQUAL(addrman->GetAddr(2500, 23, std::nullopt).size(), 1U);
BOOST_CHECK(addrman->Good(CAddress(addr1, NODE_NONE)));
BOOST_CHECK(addrman->Good(CAddress(addr2, NODE_NONE)));
BOOST_CHECK_EQUAL(addrman->GetAddr(0, 0, std::nullopt).size(), 5U);
BOOST_CHECK_EQUAL(addrman->GetAddr(2500, 23, std::nullopt).size(), 1U);
for (unsigned int i = 1; i < (8 * 256); i++) {
int octet1 = i % 256;
int octet2 = i >> 8 % 256;
std::string strAddr = ToString(octet1) + "." + ToString(octet2) + ".1.23";
CAddress addr = CAddress(ResolveService(strAddr), NODE_NONE);
addr.nTime = Now<NodeSeconds>();
addrman->Add({addr}, ResolveIP(strAddr));
if (i % 8 == 0)
addrman->Good(addr);
}
std::vector<CAddress> vAddr = addrman->GetAddr(2500, 23, std::nullopt);
size_t percent23 = (addrman->Size() * 23) / 100;
BOOST_CHECK_EQUAL(vAddr.size(), percent23);
BOOST_CHECK_EQUAL(vAddr.size(), 461U);
BOOST_CHECK_EQUAL(addrman->Size(), 2006U);
}
BOOST_AUTO_TEST_CASE(getaddr_unfiltered)
{
auto addrman = std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, DETERMINISTIC, GetCheckRatio(m_node));
CAddress addr1 = CAddress(ResolveService("250.250.2.1", 8333), NODE_NONE);
addr1.nTime = Now<NodeSeconds>();
CAddress addr2 = CAddress(ResolveService("250.251.2.2", 9999), NODE_NONE);
CNetAddr source = ResolveIP("250.1.2.1");
BOOST_CHECK(addrman->Add({addr1, addr2}, source));
CAddress addr3 = CAddress(ResolveService("250.251.2.3", 9998), NODE_NONE);
addr3.nTime = Now<NodeSeconds>();
addrman->Good(addr3, Now<NodeSeconds>());
BOOST_CHECK(addrman->Add({addr3}, source));
for (size_t i = 0; i < 3; ++i) {
addrman->Attempt(addr3, true, Now<NodeSeconds>() - 61s);
}
BOOST_CHECK_EQUAL(addrman->GetAddr(0, 0, std::nullopt).size(), 1U);
BOOST_CHECK_EQUAL(addrman->GetAddr(0, 0, std::nullopt, false).size(), 3U);
}
BOOST_AUTO_TEST_CASE(caddrinfo_get_tried_bucket_legacy)
{
CAddress addr1 = CAddress(ResolveService("250.1.1.1", 8333), NODE_NONE);
CAddress addr2 = CAddress(ResolveService("250.1.1.1", 9999), NODE_NONE);
CNetAddr source1 = ResolveIP("250.1.1.1");
AddrInfo info1 = AddrInfo(addr1, source1);
uint256 nKey1 = (HashWriter{} << 1).GetHash();
uint256 nKey2 = (HashWriter{} << 2).GetHash();
BOOST_CHECK_EQUAL(info1.GetTriedBucket(nKey1, EMPTY_NETGROUPMAN), 40);
BOOST_CHECK(info1.GetTriedBucket(nKey1, EMPTY_NETGROUPMAN) != info1.GetTriedBucket(nKey2, EMPTY_NETGROUPMAN));
AddrInfo info2 = AddrInfo(addr2, source1);
BOOST_CHECK(info1.GetKey() != info2.GetKey());
BOOST_CHECK(info1.GetTriedBucket(nKey1, EMPTY_NETGROUPMAN) != info2.GetTriedBucket(nKey1, EMPTY_NETGROUPMAN));
std::set<int> buckets;
for (int i = 0; i < 255; i++) {
AddrInfo infoi = AddrInfo(
CAddress(ResolveService("250.1.1." + ToString(i)), NODE_NONE),
ResolveIP("250.1.1." + ToString(i)));
int bucket = infoi.GetTriedBucket(nKey1, EMPTY_NETGROUPMAN);
buckets.insert(bucket);
}
BOOST_CHECK_EQUAL(buckets.size(), 8U);
buckets.clear();
for (int j = 0; j < 255; j++) {
AddrInfo infoj = AddrInfo(
CAddress(ResolveService("250." + ToString(j) + ".1.1"), NODE_NONE),
ResolveIP("250." + ToString(j) + ".1.1"));
int bucket = infoj.GetTriedBucket(nKey1, EMPTY_NETGROUPMAN);
buckets.insert(bucket);
}
BOOST_CHECK_EQUAL(buckets.size(), 160U);
}
BOOST_AUTO_TEST_CASE(caddrinfo_get_new_bucket_legacy)
{
CAddress addr1 = CAddress(ResolveService("250.1.2.1", 8333), NODE_NONE);
CAddress addr2 = CAddress(ResolveService("250.1.2.1", 9999), NODE_NONE);
CNetAddr source1 = ResolveIP("250.1.2.1");
AddrInfo info1 = AddrInfo(addr1, source1);
uint256 nKey1 = (HashWriter{} << 1).GetHash();
uint256 nKey2 = (HashWriter{} << 2).GetHash();
BOOST_CHECK_EQUAL(info1.GetNewBucket(nKey1, EMPTY_NETGROUPMAN), 786);
BOOST_CHECK_EQUAL(info1.GetNewBucket(nKey1, source1, EMPTY_NETGROUPMAN), 786);
BOOST_CHECK(info1.GetNewBucket(nKey1, EMPTY_NETGROUPMAN) != info1.GetNewBucket(nKey2, EMPTY_NETGROUPMAN));
AddrInfo info2 = AddrInfo(addr2, source1);
BOOST_CHECK(info1.GetKey() != info2.GetKey());
BOOST_CHECK_EQUAL(info1.GetNewBucket(nKey1, EMPTY_NETGROUPMAN), info2.GetNewBucket(nKey1, EMPTY_NETGROUPMAN));
std::set<int> buckets;
for (int i = 0; i < 255; i++) {
AddrInfo infoi = AddrInfo(
CAddress(ResolveService("250.1.1." + ToString(i)), NODE_NONE),
ResolveIP("250.1.1." + ToString(i)));
int bucket = infoi.GetNewBucket(nKey1, EMPTY_NETGROUPMAN);
buckets.insert(bucket);
}
BOOST_CHECK_EQUAL(buckets.size(), 1U);
buckets.clear();
for (int j = 0; j < 4 * 255; j++) {
AddrInfo infoj = AddrInfo(CAddress(
ResolveService(
ToString(250 + (j / 255)) + "." + ToString(j % 256) + ".1.1"), NODE_NONE),
ResolveIP("251.4.1.1"));
int bucket = infoj.GetNewBucket(nKey1, EMPTY_NETGROUPMAN);
buckets.insert(bucket);
}
BOOST_CHECK(buckets.size() <= 64);
buckets.clear();
for (int p = 0; p < 255; p++) {
AddrInfo infoj = AddrInfo(
CAddress(ResolveService("250.1.1.1"), NODE_NONE),
ResolveIP("250." + ToString(p) + ".1.1"));
int bucket = infoj.GetNewBucket(nKey1, EMPTY_NETGROUPMAN);
buckets.insert(bucket);
}
BOOST_CHECK(buckets.size() > 64);
}
BOOST_AUTO_TEST_CASE(caddrinfo_get_tried_bucket)
{
std::vector<bool> asmap = FromBytes(test::data::asmap);
NetGroupManager ngm_asmap{asmap};
CAddress addr1 = CAddress(ResolveService("250.1.1.1", 8333), NODE_NONE);
CAddress addr2 = CAddress(ResolveService("250.1.1.1", 9999), NODE_NONE);
CNetAddr source1 = ResolveIP("250.1.1.1");
AddrInfo info1 = AddrInfo(addr1, source1);
uint256 nKey1 = (HashWriter{} << 1).GetHash();
uint256 nKey2 = (HashWriter{} << 2).GetHash();
BOOST_CHECK_EQUAL(info1.GetTriedBucket(nKey1, ngm_asmap), 236);
BOOST_CHECK(info1.GetTriedBucket(nKey1, ngm_asmap) != info1.GetTriedBucket(nKey2, ngm_asmap));
AddrInfo info2 = AddrInfo(addr2, source1);
BOOST_CHECK(info1.GetKey() != info2.GetKey());
BOOST_CHECK(info1.GetTriedBucket(nKey1, ngm_asmap) != info2.GetTriedBucket(nKey1, ngm_asmap));
std::set<int> buckets;
for (int j = 0; j < 255; j++) {
AddrInfo infoj = AddrInfo(
CAddress(ResolveService("101." + ToString(j) + ".1.1"), NODE_NONE),
ResolveIP("101." + ToString(j) + ".1.1"));
int bucket = infoj.GetTriedBucket(nKey1, ngm_asmap);
buckets.insert(bucket);
}
BOOST_CHECK(buckets.size() > 8);
buckets.clear();
for (int j = 0; j < 255; j++) {
AddrInfo infoj = AddrInfo(
CAddress(ResolveService("250." + ToString(j) + ".1.1"), NODE_NONE),
ResolveIP("250." + ToString(j) + ".1.1"));
int bucket = infoj.GetTriedBucket(nKey1, ngm_asmap);
buckets.insert(bucket);
}
BOOST_CHECK(buckets.size() == 8);
}
BOOST_AUTO_TEST_CASE(caddrinfo_get_new_bucket)
{
std::vector<bool> asmap = FromBytes(test::data::asmap);
NetGroupManager ngm_asmap{asmap};
CAddress addr1 = CAddress(ResolveService("250.1.2.1", 8333), NODE_NONE);
CAddress addr2 = CAddress(ResolveService("250.1.2.1", 9999), NODE_NONE);
CNetAddr source1 = ResolveIP("250.1.2.1");
AddrInfo info1 = AddrInfo(addr1, source1);
uint256 nKey1 = (HashWriter{} << 1).GetHash();
uint256 nKey2 = (HashWriter{} << 2).GetHash();
BOOST_CHECK_EQUAL(info1.GetNewBucket(nKey1, ngm_asmap), 795);
BOOST_CHECK_EQUAL(info1.GetNewBucket(nKey1, source1, ngm_asmap), 795);
BOOST_CHECK(info1.GetNewBucket(nKey1, ngm_asmap) != info1.GetNewBucket(nKey2, ngm_asmap));
AddrInfo info2 = AddrInfo(addr2, source1);
BOOST_CHECK(info1.GetKey() != info2.GetKey());
BOOST_CHECK_EQUAL(info1.GetNewBucket(nKey1, ngm_asmap), info2.GetNewBucket(nKey1, ngm_asmap));
std::set<int> buckets;
for (int i = 0; i < 255; i++) {
AddrInfo infoi = AddrInfo(
CAddress(ResolveService("250.1.1." + ToString(i)), NODE_NONE),
ResolveIP("250.1.1." + ToString(i)));
int bucket = infoi.GetNewBucket(nKey1, ngm_asmap);
buckets.insert(bucket);
}
BOOST_CHECK_EQUAL(buckets.size(), 1U);
buckets.clear();
for (int j = 0; j < 4 * 255; j++) {
AddrInfo infoj = AddrInfo(CAddress(
ResolveService(
ToString(250 + (j / 255)) + "." + ToString(j % 256) + ".1.1"), NODE_NONE),
ResolveIP("251.4.1.1"));
int bucket = infoj.GetNewBucket(nKey1, ngm_asmap);
buckets.insert(bucket);
}
BOOST_CHECK(buckets.size() <= 64);
buckets.clear();
for (int p = 0; p < 255; p++) {
AddrInfo infoj = AddrInfo(
CAddress(ResolveService("250.1.1.1"), NODE_NONE),
ResolveIP("101." + ToString(p) + ".1.1"));
int bucket = infoj.GetNewBucket(nKey1, ngm_asmap);
buckets.insert(bucket);
}
BOOST_CHECK(buckets.size() > 1);
buckets.clear();
for (int p = 0; p < 255; p++) {
AddrInfo infoj = AddrInfo(
CAddress(ResolveService("250.1.1.1"), NODE_NONE),
ResolveIP("250." + ToString(p) + ".1.1"));
int bucket = infoj.GetNewBucket(nKey1, ngm_asmap);
buckets.insert(bucket);
}
BOOST_CHECK(buckets.size() == 1);
}
BOOST_AUTO_TEST_CASE(addrman_serialization)
{
std::vector<bool> asmap1 = FromBytes(test::data::asmap);
NetGroupManager netgroupman{asmap1};
const auto ratio = GetCheckRatio(m_node);
auto addrman_asmap1 = std::make_unique<AddrMan>(netgroupman, DETERMINISTIC, ratio);
auto addrman_asmap1_dup = std::make_unique<AddrMan>(netgroupman, DETERMINISTIC, ratio);
auto addrman_noasmap = std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, DETERMINISTIC, ratio);
DataStream stream{};
CAddress addr = CAddress(ResolveService("250.1.1.1"), NODE_NONE);
CNetAddr default_source;
addrman_asmap1->Add({addr}, default_source);
stream << *addrman_asmap1;
stream >> *addrman_asmap1_dup;
AddressPosition addr_pos1 = addrman_asmap1->FindAddressEntry(addr).value();
AddressPosition addr_pos2 = addrman_asmap1_dup->FindAddressEntry(addr).value();
BOOST_CHECK(addr_pos1.multiplicity != 0);
BOOST_CHECK(addr_pos2.multiplicity != 0);
BOOST_CHECK(addr_pos1 == addr_pos2);
stream << *addrman_asmap1;
stream >> *addrman_noasmap;
AddressPosition addr_pos3 = addrman_noasmap->FindAddressEntry(addr).value();
BOOST_CHECK(addr_pos3.multiplicity != 0);
BOOST_CHECK(addr_pos1.bucket != addr_pos3.bucket);
BOOST_CHECK(addr_pos1.position != addr_pos3.position);
addrman_asmap1 = std::make_unique<AddrMan>(netgroupman, DETERMINISTIC, ratio);
addrman_noasmap = std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, DETERMINISTIC, ratio);
addrman_noasmap->Add({addr}, default_source);
stream << *addrman_noasmap;
stream >> *addrman_asmap1;
AddressPosition addr_pos4 = addrman_asmap1->FindAddressEntry(addr).value();
BOOST_CHECK(addr_pos4.multiplicity != 0);
BOOST_CHECK(addr_pos4.bucket != addr_pos3.bucket);
BOOST_CHECK(addr_pos4 == addr_pos2);
addrman_asmap1 = std::make_unique<AddrMan>(netgroupman, DETERMINISTIC, ratio);
addrman_noasmap = std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, DETERMINISTIC, ratio);
CAddress addr1 = CAddress(ResolveService("250.1.1.1"), NODE_NONE);
CAddress addr2 = CAddress(ResolveService("250.2.1.1"), NODE_NONE);
addrman_noasmap->Add({addr, addr2}, default_source);
AddressPosition addr_pos5 = addrman_noasmap->FindAddressEntry(addr1).value();
AddressPosition addr_pos6 = addrman_noasmap->FindAddressEntry(addr2).value();
BOOST_CHECK(addr_pos5.bucket != addr_pos6.bucket);
stream << *addrman_noasmap;
stream >> *addrman_asmap1;
AddressPosition addr_pos7 = addrman_asmap1->FindAddressEntry(addr1).value();
AddressPosition addr_pos8 = addrman_asmap1->FindAddressEntry(addr2).value();
BOOST_CHECK(addr_pos7.bucket == addr_pos8.bucket);
BOOST_CHECK(addr_pos7.position != addr_pos8.position);
}
BOOST_AUTO_TEST_CASE(remove_invalid)
{
auto addrman = std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, DETERMINISTIC, GetCheckRatio(m_node));
DataStream stream{};
const CAddress new1{ResolveService("5.5.5.5"), NODE_NONE};
const CAddress new2{ResolveService("6.6.6.6"), NODE_NONE};
const CAddress tried1{ResolveService("7.7.7.7"), NODE_NONE};
const CAddress tried2{ResolveService("8.8.8.8"), NODE_NONE};
addrman->Add({new1, tried1, new2, tried2}, CNetAddr{});
addrman->Good(tried1);
addrman->Good(tried2);
BOOST_REQUIRE_EQUAL(addrman->Size(), 4);
stream << *addrman;
const std::string str{stream.str()};
size_t pos;
const char new2_raw[]{6, 6, 6, 6};
const uint8_t new2_raw_replacement[]{0, 0, 0, 0}; pos = str.find(new2_raw, 0, sizeof(new2_raw));
BOOST_REQUIRE(pos != std::string::npos);
BOOST_REQUIRE(pos + sizeof(new2_raw_replacement) <= stream.size());
memcpy(stream.data() + pos, new2_raw_replacement, sizeof(new2_raw_replacement));
const char tried2_raw[]{8, 8, 8, 8};
const uint8_t tried2_raw_replacement[]{255, 255, 255, 255}; pos = str.find(tried2_raw, 0, sizeof(tried2_raw));
BOOST_REQUIRE(pos != std::string::npos);
BOOST_REQUIRE(pos + sizeof(tried2_raw_replacement) <= stream.size());
memcpy(stream.data() + pos, tried2_raw_replacement, sizeof(tried2_raw_replacement));
addrman = std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, DETERMINISTIC, GetCheckRatio(m_node));
stream >> *addrman;
BOOST_CHECK_EQUAL(addrman->Size(), 2);
}
BOOST_AUTO_TEST_CASE(addrman_selecttriedcollision)
{
auto addrman = std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, DETERMINISTIC, GetCheckRatio(m_node));
BOOST_CHECK(addrman->Size() == 0);
BOOST_CHECK(addrman->SelectTriedCollision().first.ToStringAddrPort() == "[::]:0");
CNetAddr source = ResolveIP("252.2.2.2");
for (unsigned int i = 1; i < 23; i++) {
CService addr = ResolveService("250.1.1." + ToString(i));
BOOST_CHECK(addrman->Add({CAddress(addr, NODE_NONE)}, source));
BOOST_CHECK(addrman->Good(addr));
BOOST_CHECK(addrman->SelectTriedCollision().first.ToStringAddrPort() == "[::]:0");
}
for (unsigned int i = 1; i < 23; i++) {
CService addr = ResolveService("250.1.1." + ToString(i));
BOOST_CHECK(!addrman->Good(addr));
BOOST_CHECK(addrman->SelectTriedCollision().first.ToStringAddrPort() == "[::]:0");
}
}
BOOST_AUTO_TEST_CASE(addrman_noevict)
{
auto addrman = std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, DETERMINISTIC, GetCheckRatio(m_node));
CNetAddr source = ResolveIP("252.2.2.2");
for (unsigned int i = 1; i < 36; i++) {
CService addr = ResolveService("250.1.1." + ToString(i));
BOOST_CHECK(addrman->Add({CAddress(addr, NODE_NONE)}, source));
BOOST_CHECK(addrman->Good(addr));
}
CService addr36 = ResolveService("250.1.1.36");
BOOST_CHECK(addrman->Add({CAddress(addr36, NODE_NONE)}, source));
BOOST_CHECK(!addrman->Good(addr36));
BOOST_CHECK_EQUAL(addrman->SelectTriedCollision().first.ToStringAddrPort(), "250.1.1.19:0");
addrman->ResolveCollisions();
BOOST_CHECK(addrman->SelectTriedCollision().first.ToStringAddrPort() == "[::]:0");
for (unsigned int i = 37; i < 59; i++) {
CService addr = ResolveService("250.1.1." + ToString(i));
BOOST_CHECK(addrman->Add({CAddress(addr, NODE_NONE)}, source));
BOOST_CHECK(addrman->Good(addr));
}
CService addr59 = ResolveService("250.1.1.59");
BOOST_CHECK(addrman->Add({CAddress(addr59, NODE_NONE)}, source));
BOOST_CHECK(!addrman->Good(addr59));
BOOST_CHECK_EQUAL(addrman->SelectTriedCollision().first.ToStringAddrPort(), "250.1.1.10:0");
BOOST_CHECK(!addrman->Add({CAddress(addr36, NODE_NONE)}, source));
BOOST_CHECK(!addrman->Good(addr36));
BOOST_CHECK(addrman->SelectTriedCollision().first.ToStringAddrPort() != "[::]:0");
addrman->ResolveCollisions();
BOOST_CHECK(addrman->SelectTriedCollision().first.ToStringAddrPort() == "[::]:0");
}
BOOST_AUTO_TEST_CASE(addrman_evictionworks)
{
auto addrman = std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, DETERMINISTIC, GetCheckRatio(m_node));
BOOST_CHECK(addrman->Size() == 0);
BOOST_CHECK(addrman->SelectTriedCollision().first.ToStringAddrPort() == "[::]:0");
CNetAddr source = ResolveIP("252.2.2.2");
for (unsigned int i = 1; i < 36; i++) {
CService addr = ResolveService("250.1.1." + ToString(i));
BOOST_CHECK(addrman->Add({CAddress(addr, NODE_NONE)}, source));
BOOST_CHECK(addrman->Good(addr));
}
CService addr = ResolveService("250.1.1.36");
BOOST_CHECK(addrman->Add({CAddress(addr, NODE_NONE)}, source));
BOOST_CHECK(!addrman->Good(addr));
auto info = addrman->SelectTriedCollision().first;
BOOST_CHECK_EQUAL(info.ToStringAddrPort(), "250.1.1.19:0");
BOOST_CHECK(!addrman->Good(info, NodeSeconds{1s}));
addrman->Attempt(info, false, Now<NodeSeconds>() - 61s);
addrman->ResolveCollisions();
BOOST_CHECK(addrman->SelectTriedCollision().first.ToStringAddrPort() == "[::]:0");
AddressPosition addr_pos{addrman->FindAddressEntry(CAddress(addr, NODE_NONE)).value()};
BOOST_CHECK(addr_pos.tried);
BOOST_CHECK(!addrman->Good(addr));
BOOST_CHECK(addrman->SelectTriedCollision().first.ToStringAddrPort() == "[::]:0");
CService addr19 = ResolveService("250.1.1.19");
BOOST_CHECK(!addrman->Good(addr19));
BOOST_CHECK_EQUAL(addrman->SelectTriedCollision().first.ToStringAddrPort(), "250.1.1.36:0");
SetMockTime(GetTime() + 4 * 60 *60);
addrman->ResolveCollisions();
BOOST_CHECK(addrman->SelectTriedCollision().first.ToStringAddrPort() == "[::]:0");
AddressPosition addr_pos19{addrman->FindAddressEntry(CAddress(addr19, NODE_NONE)).value()};
BOOST_CHECK(addr_pos19.tried);
AddressPosition addr_pos36{addrman->FindAddressEntry(CAddress(addr, NODE_NONE)).value()};
BOOST_CHECK(!addr_pos36.tried);
}
static auto AddrmanToStream(const AddrMan& addrman)
{
DataStream ssPeersIn{};
ssPeersIn << Params().MessageStart();
ssPeersIn << addrman;
return ssPeersIn;
}
BOOST_AUTO_TEST_CASE(load_addrman)
{
AddrMan addrman{EMPTY_NETGROUPMAN, DETERMINISTIC, GetCheckRatio(m_node)};
std::optional<CService> addr1, addr2, addr3, addr4;
addr1 = Lookup("250.7.1.1", 8333, false);
BOOST_CHECK(addr1.has_value());
addr2 = Lookup("250.7.2.2", 9999, false);
BOOST_CHECK(addr2.has_value());
addr3 = Lookup("250.7.3.3", 9999, false);
BOOST_CHECK(addr3.has_value());
addr3 = Lookup("250.7.3.3"s, 9999, false);
BOOST_CHECK(addr3.has_value());
addr4 = Lookup("250.7.3.3\0example.com"s, 9999, false);
BOOST_CHECK(!addr4.has_value());
const std::optional<CService> source{Lookup("252.5.1.1", 8333, false)};
BOOST_CHECK(source.has_value());
std::vector<CAddress> addresses{CAddress(addr1.value(), NODE_NONE), CAddress(addr2.value(), NODE_NONE), CAddress(addr3.value(), NODE_NONE)};
BOOST_CHECK(addrman.Add(addresses, source.value()));
BOOST_CHECK(addrman.Size() == 3);
auto ssPeers1{AddrmanToStream(addrman)};
bool exceptionThrown = false;
AddrMan addrman1{EMPTY_NETGROUPMAN, !DETERMINISTIC, GetCheckRatio(m_node)};
BOOST_CHECK(addrman1.Size() == 0);
try {
unsigned char pchMsgTmp[4];
ssPeers1 >> pchMsgTmp;
ssPeers1 >> addrman1;
} catch (const std::exception&) {
exceptionThrown = true;
}
BOOST_CHECK(addrman1.Size() == 3);
BOOST_CHECK(exceptionThrown == false);
DataStream ssPeers2 = AddrmanToStream(addrman);
AddrMan addrman2{EMPTY_NETGROUPMAN, !DETERMINISTIC, GetCheckRatio(m_node)};
BOOST_CHECK(addrman2.Size() == 0);
ReadFromStream(addrman2, ssPeers2);
BOOST_CHECK(addrman2.Size() == 3);
}
static auto MakeCorruptPeersDat()
{
DataStream s{};
s << ::Params().MessageStart();
unsigned char nVersion = 1;
s << nVersion;
s << ((unsigned char)32);
s << uint256::ONE;
s << 10; s << 10;
int nUBuckets = ADDRMAN_NEW_BUCKET_COUNT ^ (1 << 30);
s << nUBuckets;
const std::optional<CService> serv{Lookup("252.1.1.1", 7777, false)};
BOOST_REQUIRE(serv.has_value());
CAddress addr = CAddress(serv.value(), NODE_NONE);
std::optional<CNetAddr> resolved{LookupHost("252.2.2.2", false)};
BOOST_REQUIRE(resolved.has_value());
AddrInfo info = AddrInfo(addr, resolved.value());
s << CAddress::V1_DISK(info);
return s;
}
BOOST_AUTO_TEST_CASE(load_addrman_corrupted)
{
auto ssPeers1{MakeCorruptPeersDat()};
bool exceptionThrown = false;
AddrMan addrman1{EMPTY_NETGROUPMAN, !DETERMINISTIC, GetCheckRatio(m_node)};
BOOST_CHECK(addrman1.Size() == 0);
try {
unsigned char pchMsgTmp[4];
ssPeers1 >> pchMsgTmp;
ssPeers1 >> addrman1;
} catch (const std::exception&) {
exceptionThrown = true;
}
BOOST_CHECK(exceptionThrown);
auto ssPeers2{MakeCorruptPeersDat()};
AddrMan addrman2{EMPTY_NETGROUPMAN, !DETERMINISTIC, GetCheckRatio(m_node)};
BOOST_CHECK(addrman2.Size() == 0);
BOOST_CHECK_THROW(ReadFromStream(addrman2, ssPeers2), std::ios_base::failure);
}
BOOST_AUTO_TEST_CASE(addrman_update_address)
{
auto addrman = std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, DETERMINISTIC, GetCheckRatio(m_node));
CNetAddr source{ResolveIP("252.2.2.2")};
CAddress addr{CAddress(ResolveService("250.1.1.1", 8333), NODE_NONE)};
const auto start_time{Now<NodeSeconds>() - 10000s};
addr.nTime = start_time;
BOOST_CHECK(addrman->Add({addr}, source));
BOOST_CHECK_EQUAL(addrman->Size(), 1U);
CAddress addr_diff_port{CAddress(ResolveService("250.1.1.1", 8334), NODE_NONE)};
addr_diff_port.nTime = start_time;
addrman->Connected(addr_diff_port);
addrman->SetServices(addr_diff_port, NODE_NETWORK_LIMITED);
std::vector<CAddress> vAddr1{addrman->GetAddr(0, 0, std::nullopt)};
BOOST_CHECK_EQUAL(vAddr1.size(), 1U);
BOOST_CHECK(vAddr1.at(0).nTime == start_time);
BOOST_CHECK_EQUAL(vAddr1.at(0).nServices, NODE_NONE);
addrman->Connected(addr);
addrman->SetServices(addr, NODE_NETWORK_LIMITED);
std::vector<CAddress> vAddr2 = addrman->GetAddr(0, 0, std::nullopt);
BOOST_CHECK_EQUAL(vAddr2.size(), 1U);
BOOST_CHECK(vAddr2.at(0).nTime >= start_time + 10000s);
BOOST_CHECK_EQUAL(vAddr2.at(0).nServices, NODE_NETWORK_LIMITED);
CAddress addr_v2{CAddress(ResolveService("250.1.1.1", 8333), NODE_P2P_V2)};
addr_v2.nTime = start_time;
BOOST_CHECK(!addrman->Add({addr_v2}, source));
std::vector<CAddress> vAddr3{addrman->GetAddr(0, 0, std::nullopt)};
BOOST_CHECK_EQUAL(vAddr3.size(), 1U);
BOOST_CHECK_EQUAL(vAddr3.at(0).nServices, NODE_P2P_V2 | NODE_NETWORK_LIMITED);
addrman->SetServices(addr, NODE_NETWORK);
std::vector<CAddress> vAddr4{addrman->GetAddr(0, 0, std::nullopt)};
BOOST_CHECK_EQUAL(vAddr4.size(), 1U);
BOOST_CHECK_EQUAL(vAddr4.at(0).nServices, NODE_NETWORK);
BOOST_CHECK(addrman->Good(addr)); std::vector<CAddress> vAddr5{addrman->GetAddr(0, 0, std::nullopt)};
BOOST_CHECK_EQUAL(vAddr5.size(), 1U);
BOOST_CHECK_EQUAL(vAddr5.at(0).nServices, NODE_NETWORK);
BOOST_CHECK(!addrman->Add({addr_v2}, source));
std::vector<CAddress> vAddr6{addrman->GetAddr(0, 0, std::nullopt)};
BOOST_CHECK_EQUAL(vAddr6.size(), 1U);
BOOST_CHECK_EQUAL(vAddr6.at(0).nServices, NODE_NETWORK | NODE_P2P_V2);
}
BOOST_AUTO_TEST_CASE(addrman_size)
{
auto addrman = std::make_unique<AddrMan>(EMPTY_NETGROUPMAN, DETERMINISTIC, GetCheckRatio(m_node));
const CNetAddr source = ResolveIP("252.2.2.2");
BOOST_CHECK_EQUAL(addrman->Size(std::nullopt, std::nullopt), 0U);
BOOST_CHECK_EQUAL(addrman->Size(NET_IPV4, std::nullopt), 0U);
BOOST_CHECK_EQUAL(addrman->Size(std::nullopt, true), 0U);
BOOST_CHECK_EQUAL(addrman->Size(NET_IPV4, false), 0U);
const CAddress addr1{ResolveService("250.1.1.1", 8333), NODE_NONE};
BOOST_CHECK(addrman->Add({addr1}, source));
BOOST_CHECK(addrman->Good(addr1));
const CAddress addr2{ResolveService("250.1.1.2", 8333), NODE_NONE};
BOOST_CHECK(addrman->Add({addr2}, source));
BOOST_CHECK_EQUAL(addrman->Size(std::nullopt, std::nullopt), 2U);
BOOST_CHECK_EQUAL(addrman->Size(NET_IPV4, std::nullopt), 2U);
BOOST_CHECK_EQUAL(addrman->Size(std::nullopt, true), 1U);
BOOST_CHECK_EQUAL(addrman->Size(std::nullopt, false), 1U);
BOOST_CHECK_EQUAL(addrman->Size(NET_IPV4, true), 1U);
BOOST_CHECK_EQUAL(addrman->Size(NET_IPV4, false), 1U);
CService i2p_addr;
i2p_addr.SetSpecial("UDHDrtrcetjm5sxzskjyr5ztpeszydbh4dpl3pl4utgqqw2v4jna.b32.I2P");
const CAddress addr3{i2p_addr, NODE_NONE};
BOOST_CHECK(addrman->Add({addr3}, source));
BOOST_CHECK_EQUAL(addrman->Size(std::nullopt, std::nullopt), 3U);
BOOST_CHECK_EQUAL(addrman->Size(NET_IPV4, std::nullopt), 2U);
BOOST_CHECK_EQUAL(addrman->Size(NET_I2P, std::nullopt), 1U);
BOOST_CHECK_EQUAL(addrman->Size(NET_I2P, true), 1U);
BOOST_CHECK_EQUAL(addrman->Size(std::nullopt, true), 2U);
BOOST_CHECK_EQUAL(addrman->Size(std::nullopt, false), 1U);
}
BOOST_AUTO_TEST_SUITE_END()