Changeset View
Changeset View
Standalone View
Standalone View
src/test/addrman_tests.cpp
// Copyright (c) 2012-2019 The Bitcoin Core developers | // Copyright (c) 2012-2019 The Bitcoin Core developers | ||||
// Distributed under the MIT software license, see the accompanying | // Distributed under the MIT software license, see the accompanying | ||||
// file COPYING or http://www.opensource.org/licenses/mit-license.php. | // file COPYING or http://www.opensource.org/licenses/mit-license.php. | ||||
#include <addrman.h> | #include <addrman.h> | ||||
#include <hash.h> | #include <hash.h> | ||||
#include <netbase.h> | #include <netbase.h> | ||||
#include <random.h> | #include <random.h> | ||||
#include <util/asmap.h> | |||||
#include <test/data/asmap.raw.h> | |||||
#include <test/util/setup_common.h> | #include <test/util/setup_common.h> | ||||
#include <boost/test/unit_test.hpp> | #include <boost/test/unit_test.hpp> | ||||
#include <string> | #include <string> | ||||
class CAddrManTest : public CAddrMan { | class CAddrManTest : public CAddrMan { | ||||
private: | |||||
bool deterministic; | |||||
public: | public: | ||||
explicit CAddrManTest(bool makeDeterministic = true) { | explicit CAddrManTest(bool makeDeterministic = true, | ||||
std::vector<bool> asmap = std::vector<bool>()) { | |||||
if (makeDeterministic) { | if (makeDeterministic) { | ||||
// Set addrman addr placement to be deterministic. | // Set addrman addr placement to be deterministic. | ||||
MakeDeterministic(); | MakeDeterministic(); | ||||
} | } | ||||
deterministic = makeDeterministic; | |||||
m_asmap = asmap; | |||||
} | } | ||||
//! Ensure that bucket placement is always the same for testing purposes. | //! Ensure that bucket placement is always the same for testing purposes. | ||||
void MakeDeterministic() { | void MakeDeterministic() { | ||||
nKey.SetNull(); | nKey.SetNull(); | ||||
insecure_rand = FastRandomContext(true); | insecure_rand = FastRandomContext(true); | ||||
} | } | ||||
CAddrInfo *Find(const CNetAddr &addr, int *pnId = nullptr) { | CAddrInfo *Find(const CNetAddr &addr, int *pnId = nullptr) { | ||||
LOCK(cs); | LOCK(cs); | ||||
return CAddrMan::Find(addr, pnId); | return CAddrMan::Find(addr, pnId); | ||||
} | } | ||||
CAddrInfo *Create(const CAddress &addr, const CNetAddr &addrSource, | CAddrInfo *Create(const CAddress &addr, const CNetAddr &addrSource, | ||||
int *pnId = nullptr) { | int *pnId = nullptr) { | ||||
LOCK(cs); | LOCK(cs); | ||||
return CAddrMan::Create(addr, addrSource, pnId); | return CAddrMan::Create(addr, addrSource, pnId); | ||||
} | } | ||||
void Delete(int nId) { | void Delete(int nId) { | ||||
LOCK(cs); | LOCK(cs); | ||||
CAddrMan::Delete(nId); | CAddrMan::Delete(nId); | ||||
} | } | ||||
// Used to test deserialization | |||||
std::pair<int, int> GetBucketAndEntry(const CAddress &addr) { | |||||
LOCK(cs); | |||||
int nId = mapAddr[addr]; | |||||
for (int bucket = 0; bucket < ADDRMAN_NEW_BUCKET_COUNT; ++bucket) { | |||||
for (int entry = 0; entry < ADDRMAN_BUCKET_SIZE; ++entry) { | |||||
if (nId == vvNew[bucket][entry]) { | |||||
return std::pair<int, int>(bucket, entry); | |||||
} | |||||
} | |||||
} | |||||
return std::pair<int, int>(-1, -1); | |||||
} | |||||
// Simulates connection failure so that we can test eviction of offline | // Simulates connection failure so that we can test eviction of offline | ||||
// nodes | // nodes | ||||
void SimConnFail(CService &addr) { | void SimConnFail(CService &addr) { | ||||
LOCK(cs); | LOCK(cs); | ||||
int64_t nLastSuccess = 1; | int64_t nLastSuccess = 1; | ||||
// Set last good connection in the deep past. | // Set last good connection in the deep past. | ||||
Good_(addr, true, nLastSuccess); | Good_(addr, true, nLastSuccess); | ||||
bool count_failure = false; | bool count_failure = false; | ||||
int64_t nLastTry = GetAdjustedTime() - 61; | int64_t nLastTry = GetAdjustedTime() - 61; | ||||
Attempt(addr, count_failure, nLastTry); | Attempt(addr, count_failure, nLastTry); | ||||
} | } | ||||
void Clear() { | |||||
CAddrMan::Clear(); | |||||
if (deterministic) { | |||||
nKey.SetNull(); | |||||
insecure_rand = FastRandomContext(true); | |||||
} | |||||
} | |||||
}; | }; | ||||
static CNetAddr ResolveIP(const char *ip) { | static CNetAddr ResolveIP(const char *ip) { | ||||
CNetAddr addr; | CNetAddr addr; | ||||
BOOST_CHECK_MESSAGE(LookupHost(ip, addr, false), | BOOST_CHECK_MESSAGE(LookupHost(ip, addr, false), | ||||
strprintf("failed to resolve: %s", ip)); | strprintf("failed to resolve: %s", ip)); | ||||
return addr; | return addr; | ||||
} | } | ||||
static CNetAddr ResolveIP(std::string ip) { | static CNetAddr ResolveIP(std::string ip) { | ||||
return ResolveIP(ip.c_str()); | return ResolveIP(ip.c_str()); | ||||
} | } | ||||
static CService ResolveService(const char *ip, int port = 0) { | static CService ResolveService(const char *ip, int port = 0) { | ||||
CService serv; | CService serv; | ||||
BOOST_CHECK_MESSAGE(Lookup(ip, serv, port, false), | BOOST_CHECK_MESSAGE(Lookup(ip, serv, port, false), | ||||
strprintf("failed to resolve: %s:%i", ip, port)); | strprintf("failed to resolve: %s:%i", ip, port)); | ||||
return serv; | return serv; | ||||
} | } | ||||
static CService ResolveService(std::string ip, int port = 0) { | static CService ResolveService(std::string ip, int port = 0) { | ||||
return ResolveService(ip.c_str(), port); | return ResolveService(ip.c_str(), port); | ||||
} | } | ||||
static std::vector<bool> FromBytes(const uint8_t *source, int vector_size) { | |||||
std::vector<bool> result(vector_size); | |||||
for (int byte_i = 0; byte_i < vector_size / 8; ++byte_i) { | |||||
uint8_t cur_byte = 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_FIXTURE_TEST_SUITE(addrman_tests, BasicTestingSetup) | ||||
BOOST_AUTO_TEST_CASE(addrman_simple) { | BOOST_AUTO_TEST_CASE(addrman_simple) { | ||||
CAddrManTest addrman; | CAddrManTest addrman; | ||||
CNetAddr source = ResolveIP("252.2.2.2"); | CNetAddr source = ResolveIP("252.2.2.2"); | ||||
// Test: Does Addrman respond correctly when empty. | // Test: Does Addrman respond correctly when empty. | ||||
▲ Show 20 Lines • Show All 303 Lines • ▼ Show 20 Lines | BOOST_AUTO_TEST_CASE(addrman_getaddr) { | ||||
size_t percent23 = (addrman.size() * 23) / 100; | size_t percent23 = (addrman.size() * 23) / 100; | ||||
BOOST_CHECK_EQUAL(vAddr.size(), percent23); | BOOST_CHECK_EQUAL(vAddr.size(), percent23); | ||||
BOOST_CHECK_EQUAL(vAddr.size(), 461U); | BOOST_CHECK_EQUAL(vAddr.size(), 461U); | ||||
// (Addrman.size() < number of addresses added) due to address collisions. | // (Addrman.size() < number of addresses added) due to address collisions. | ||||
BOOST_CHECK_EQUAL(addrman.size(), 2006U); | BOOST_CHECK_EQUAL(addrman.size(), 2006U); | ||||
} | } | ||||
BOOST_AUTO_TEST_CASE(caddrinfo_get_tried_bucket) { | BOOST_AUTO_TEST_CASE(caddrinfo_get_tried_bucket_legacy) { | ||||
CAddrManTest addrman; | CAddrManTest addrman; | ||||
CAddress addr1 = CAddress(ResolveService("250.1.1.1", 8333), NODE_NONE); | CAddress addr1 = CAddress(ResolveService("250.1.1.1", 8333), NODE_NONE); | ||||
CAddress addr2 = CAddress(ResolveService("250.1.1.1", 9999), NODE_NONE); | CAddress addr2 = CAddress(ResolveService("250.1.1.1", 9999), NODE_NONE); | ||||
CNetAddr source1 = ResolveIP("250.1.1.1"); | CNetAddr source1 = ResolveIP("250.1.1.1"); | ||||
CAddrInfo info1 = CAddrInfo(addr1, source1); | CAddrInfo info1 = CAddrInfo(addr1, source1); | ||||
uint256 nKey1 = (uint256)(CHashWriter(SER_GETHASH, 0) << 1).GetHash(); | uint256 nKey1 = (uint256)(CHashWriter(SER_GETHASH, 0) << 1).GetHash(); | ||||
uint256 nKey2 = (uint256)(CHashWriter(SER_GETHASH, 0) << 2).GetHash(); | uint256 nKey2 = (uint256)(CHashWriter(SER_GETHASH, 0) << 2).GetHash(); | ||||
BOOST_CHECK_EQUAL(info1.GetTriedBucket(nKey1), 40); | // use /16 | ||||
std::vector<bool> asmap; | |||||
BOOST_CHECK_EQUAL(info1.GetTriedBucket(nKey1, asmap), 40); | |||||
// Test: Make sure key actually randomizes bucket placement. A fail on | // Test: Make sure key actually randomizes bucket placement. A fail on | ||||
// this test could be a security issue. | // this test could be a security issue. | ||||
BOOST_CHECK(info1.GetTriedBucket(nKey1) != info1.GetTriedBucket(nKey2)); | BOOST_CHECK(info1.GetTriedBucket(nKey1, asmap) != | ||||
info1.GetTriedBucket(nKey2, asmap)); | |||||
// Test: Two addresses with same IP but different ports can map to | // Test: Two addresses with same IP but different ports can map to | ||||
// different buckets because they have different keys. | // different buckets because they have different keys. | ||||
CAddrInfo info2 = CAddrInfo(addr2, source1); | CAddrInfo info2 = CAddrInfo(addr2, source1); | ||||
BOOST_CHECK(info1.GetKey() != info2.GetKey()); | BOOST_CHECK(info1.GetKey() != info2.GetKey()); | ||||
BOOST_CHECK(info1.GetTriedBucket(nKey1) != info2.GetTriedBucket(nKey1)); | BOOST_CHECK(info1.GetTriedBucket(nKey1, asmap) != | ||||
info2.GetTriedBucket(nKey1, asmap)); | |||||
std::set<int> buckets; | std::set<int> buckets; | ||||
for (int i = 0; i < 255; i++) { | for (int i = 0; i < 255; i++) { | ||||
CAddrInfo infoi = CAddrInfo( | CAddrInfo infoi = CAddrInfo( | ||||
CAddress(ResolveService("250.1.1." + std::to_string(i)), NODE_NONE), | CAddress(ResolveService("250.1.1." + std::to_string(i)), NODE_NONE), | ||||
ResolveIP("250.1.1." + std::to_string(i))); | ResolveIP("250.1.1." + std::to_string(i))); | ||||
int bucket = infoi.GetTriedBucket(nKey1); | int bucket = infoi.GetTriedBucket(nKey1, asmap); | ||||
buckets.insert(bucket); | buckets.insert(bucket); | ||||
} | } | ||||
// Test: IP addresses in the same group (\16 prefix for IPv4) should | // Test: IP addresses in the same /16 prefix should never get more than 8 | ||||
// never get more than 8 buckets | // buckets with legacy grouping | ||||
BOOST_CHECK_EQUAL(buckets.size(), 8U); | BOOST_CHECK_EQUAL(buckets.size(), 8U); | ||||
buckets.clear(); | buckets.clear(); | ||||
for (int j = 0; j < 255; j++) { | for (int j = 0; j < 255; j++) { | ||||
CAddrInfo infoj = CAddrInfo( | CAddrInfo infoj = CAddrInfo( | ||||
CAddress(ResolveService("250." + std::to_string(j) + ".1.1"), | CAddress(ResolveService("250." + std::to_string(j) + ".1.1"), | ||||
NODE_NONE), | NODE_NONE), | ||||
ResolveIP("250." + std::to_string(j) + ".1.1")); | ResolveIP("250." + std::to_string(j) + ".1.1")); | ||||
int bucket = infoj.GetTriedBucket(nKey1); | int bucket = infoj.GetTriedBucket(nKey1, asmap); | ||||
buckets.insert(bucket); | buckets.insert(bucket); | ||||
} | } | ||||
// Test: IP addresses in the different groups should map to more than | // Test: IP addresses in the different /16 prefix should map to more than 8 | ||||
// 8 buckets. | // buckets with legacy grouping | ||||
BOOST_CHECK_EQUAL(buckets.size(), 160U); | BOOST_CHECK_EQUAL(buckets.size(), 160U); | ||||
} | } | ||||
BOOST_AUTO_TEST_CASE(caddrinfo_get_new_bucket) { | BOOST_AUTO_TEST_CASE(caddrinfo_get_new_bucket_legacy) { | ||||
CAddrManTest addrman; | CAddrManTest addrman; | ||||
CAddress addr1 = CAddress(ResolveService("250.1.2.1", 8333), NODE_NONE); | CAddress addr1 = CAddress(ResolveService("250.1.2.1", 8333), NODE_NONE); | ||||
CAddress addr2 = CAddress(ResolveService("250.1.2.1", 9999), NODE_NONE); | CAddress addr2 = CAddress(ResolveService("250.1.2.1", 9999), NODE_NONE); | ||||
CNetAddr source1 = ResolveIP("250.1.2.1"); | CNetAddr source1 = ResolveIP("250.1.2.1"); | ||||
CAddrInfo info1 = CAddrInfo(addr1, source1); | CAddrInfo info1 = CAddrInfo(addr1, source1); | ||||
uint256 nKey1 = (uint256)(CHashWriter(SER_GETHASH, 0) << 1).GetHash(); | uint256 nKey1 = (uint256)(CHashWriter(SER_GETHASH, 0) << 1).GetHash(); | ||||
uint256 nKey2 = (uint256)(CHashWriter(SER_GETHASH, 0) << 2).GetHash(); | uint256 nKey2 = (uint256)(CHashWriter(SER_GETHASH, 0) << 2).GetHash(); | ||||
// use /16 | |||||
std::vector<bool> asmap; | |||||
// Test: Make sure the buckets are what we expect | // Test: Make sure the buckets are what we expect | ||||
BOOST_CHECK_EQUAL(info1.GetNewBucket(nKey1), 786); | BOOST_CHECK_EQUAL(info1.GetNewBucket(nKey1, asmap), 786); | ||||
BOOST_CHECK_EQUAL(info1.GetNewBucket(nKey1, source1), 786); | BOOST_CHECK_EQUAL(info1.GetNewBucket(nKey1, source1, asmap), 786); | ||||
// Test: Make sure key actually randomizes bucket placement. A fail on | // Test: Make sure key actually randomizes bucket placement. A fail on | ||||
// this test could be a security issue. | // this test could be a security issue. | ||||
BOOST_CHECK(info1.GetNewBucket(nKey1) != info1.GetNewBucket(nKey2)); | BOOST_CHECK(info1.GetNewBucket(nKey1, asmap) != | ||||
info1.GetNewBucket(nKey2, asmap)); | |||||
// Test: Ports should not affect bucket placement in the addr | // Test: Ports should not affect bucket placement in the addr | ||||
CAddrInfo info2 = CAddrInfo(addr2, source1); | CAddrInfo info2 = CAddrInfo(addr2, source1); | ||||
BOOST_CHECK(info1.GetKey() != info2.GetKey()); | BOOST_CHECK(info1.GetKey() != info2.GetKey()); | ||||
BOOST_CHECK_EQUAL(info1.GetNewBucket(nKey1), info2.GetNewBucket(nKey1)); | BOOST_CHECK_EQUAL(info1.GetNewBucket(nKey1, asmap), | ||||
info2.GetNewBucket(nKey1, asmap)); | |||||
std::set<int> buckets; | std::set<int> buckets; | ||||
for (int i = 0; i < 255; i++) { | for (int i = 0; i < 255; i++) { | ||||
CAddrInfo infoi = CAddrInfo( | CAddrInfo infoi = CAddrInfo( | ||||
CAddress(ResolveService("250.1.1." + std::to_string(i)), NODE_NONE), | CAddress(ResolveService("250.1.1." + std::to_string(i)), NODE_NONE), | ||||
ResolveIP("250.1.1." + std::to_string(i))); | ResolveIP("250.1.1." + std::to_string(i))); | ||||
int bucket = infoi.GetNewBucket(nKey1); | int bucket = infoi.GetNewBucket(nKey1, asmap); | ||||
buckets.insert(bucket); | buckets.insert(bucket); | ||||
} | } | ||||
// Test: IP addresses in the same group (\16 prefix for IPv4) should | // Test: IP addresses in the same group (\16 prefix for IPv4) should | ||||
// always map to the same bucket. | // always map to the same bucket. | ||||
BOOST_CHECK_EQUAL(buckets.size(), 1U); | BOOST_CHECK_EQUAL(buckets.size(), 1U); | ||||
buckets.clear(); | buckets.clear(); | ||||
for (int j = 0; j < 4 * 255; j++) { | for (int j = 0; j < 4 * 255; j++) { | ||||
CAddrInfo infoj = CAddrInfo( | CAddrInfo infoj = CAddrInfo( | ||||
CAddress(ResolveService(std::to_string(250 + (j / 255)) + "." + | CAddress(ResolveService(std::to_string(250 + (j / 255)) + "." + | ||||
std::to_string(j % 256) + ".1.1"), | std::to_string(j % 256) + ".1.1"), | ||||
NODE_NONE), | NODE_NONE), | ||||
ResolveIP("251.4.1.1")); | ResolveIP("251.4.1.1")); | ||||
int bucket = infoj.GetNewBucket(nKey1); | int bucket = infoj.GetNewBucket(nKey1, asmap); | ||||
buckets.insert(bucket); | buckets.insert(bucket); | ||||
} | } | ||||
// Test: IP addresses in the same source groups should map to no more | // Test: IP addresses in the same source groups should map to NO MORE | ||||
// than 64 buckets. | // than 64 buckets. | ||||
BOOST_CHECK(buckets.size() <= 64); | BOOST_CHECK(buckets.size() <= 64); | ||||
buckets.clear(); | buckets.clear(); | ||||
for (int p = 0; p < 255; p++) { | for (int p = 0; p < 255; p++) { | ||||
CAddrInfo infoj = | CAddrInfo infoj = | ||||
CAddrInfo(CAddress(ResolveService("250.1.1.1"), NODE_NONE), | CAddrInfo(CAddress(ResolveService("250.1.1.1"), NODE_NONE), | ||||
ResolveIP("250." + std::to_string(p) + ".1.1")); | ResolveIP("250." + std::to_string(p) + ".1.1")); | ||||
int bucket = infoj.GetNewBucket(nKey1); | int bucket = infoj.GetNewBucket(nKey1, asmap); | ||||
buckets.insert(bucket); | buckets.insert(bucket); | ||||
} | } | ||||
// Test: IP addresses in the different source groups should map to more | // Test: IP addresses in the different source groups should map to more | ||||
// than 64 buckets. | // than 64 buckets. | ||||
BOOST_CHECK(buckets.size() > 64); | BOOST_CHECK(buckets.size() > 64); | ||||
} | } | ||||
// The following three test cases use asmap.raw | |||||
// We use an artificial minimal mock mapping | |||||
// 250.0.0.0/8 AS1000 | |||||
// 101.1.0.0/16 AS1 | |||||
// 101.2.0.0/16 AS2 | |||||
// 101.3.0.0/16 AS3 | |||||
// 101.4.0.0/16 AS4 | |||||
// 101.5.0.0/16 AS5 | |||||
// 101.6.0.0/16 AS6 | |||||
// 101.7.0.0/16 AS7 | |||||
// 101.8.0.0/16 AS8 | |||||
BOOST_AUTO_TEST_CASE(caddrinfo_get_tried_bucket) { | |||||
CAddrManTest addrman; | |||||
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"); | |||||
CAddrInfo info1 = CAddrInfo(addr1, source1); | |||||
uint256 nKey1 = (uint256)(CHashWriter(SER_GETHASH, 0) << 1).GetHash(); | |||||
uint256 nKey2 = (uint256)(CHashWriter(SER_GETHASH, 0) << 2).GetHash(); | |||||
std::vector<bool> asmap = FromBytes(asmap_raw, sizeof(asmap_raw) * 8); | |||||
BOOST_CHECK_EQUAL(info1.GetTriedBucket(nKey1, asmap), 236); | |||||
// Test: Make sure key actually randomizes bucket placement. A fail on | |||||
// this test could be a security issue. | |||||
BOOST_CHECK(info1.GetTriedBucket(nKey1, asmap) != | |||||
info1.GetTriedBucket(nKey2, asmap)); | |||||
// Test: Two addresses with same IP but different ports can map to | |||||
// different buckets because they have different keys. | |||||
CAddrInfo info2 = CAddrInfo(addr2, source1); | |||||
BOOST_CHECK(info1.GetKey() != info2.GetKey()); | |||||
BOOST_CHECK(info1.GetTriedBucket(nKey1, asmap) != | |||||
info2.GetTriedBucket(nKey1, asmap)); | |||||
std::set<int> buckets; | |||||
for (int j = 0; j < 255; j++) { | |||||
CAddrInfo infoj = CAddrInfo( | |||||
CAddress(ResolveService("101." + std::to_string(j) + ".1.1"), | |||||
NODE_NONE), | |||||
ResolveIP("101." + std::to_string(j) + ".1.1")); | |||||
int bucket = infoj.GetTriedBucket(nKey1, asmap); | |||||
buckets.insert(bucket); | |||||
} | |||||
// Test: IP addresses in the different /16 prefix MAY map to more than | |||||
// 8 buckets. | |||||
BOOST_CHECK(buckets.size() > 8); | |||||
buckets.clear(); | |||||
for (int j = 0; j < 255; j++) { | |||||
CAddrInfo infoj = CAddrInfo( | |||||
CAddress(ResolveService("250." + std::to_string(j) + ".1.1"), | |||||
NODE_NONE), | |||||
ResolveIP("250." + std::to_string(j) + ".1.1")); | |||||
int bucket = infoj.GetTriedBucket(nKey1, asmap); | |||||
buckets.insert(bucket); | |||||
} | |||||
// Test: IP addresses in the different /16 prefix MAY NOT map to more than | |||||
// 8 buckets. | |||||
BOOST_CHECK(buckets.size() == 8); | |||||
} | |||||
BOOST_AUTO_TEST_CASE(caddrinfo_get_new_bucket) { | |||||
CAddrManTest addrman; | |||||
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"); | |||||
CAddrInfo info1 = CAddrInfo(addr1, source1); | |||||
uint256 nKey1 = (uint256)(CHashWriter(SER_GETHASH, 0) << 1).GetHash(); | |||||
uint256 nKey2 = (uint256)(CHashWriter(SER_GETHASH, 0) << 2).GetHash(); | |||||
std::vector<bool> asmap = FromBytes(asmap_raw, sizeof(asmap_raw) * 8); | |||||
// Test: Make sure the buckets are what we expect | |||||
BOOST_CHECK_EQUAL(info1.GetNewBucket(nKey1, asmap), 795); | |||||
BOOST_CHECK_EQUAL(info1.GetNewBucket(nKey1, source1, asmap), 795); | |||||
// Test: Make sure key actually randomizes bucket placement. A fail on | |||||
// this test could be a security issue. | |||||
BOOST_CHECK(info1.GetNewBucket(nKey1, asmap) != | |||||
info1.GetNewBucket(nKey2, asmap)); | |||||
// Test: Ports should not affect bucket placement in the addr | |||||
CAddrInfo info2 = CAddrInfo(addr2, source1); | |||||
BOOST_CHECK(info1.GetKey() != info2.GetKey()); | |||||
BOOST_CHECK_EQUAL(info1.GetNewBucket(nKey1, asmap), | |||||
info2.GetNewBucket(nKey1, asmap)); | |||||
std::set<int> buckets; | |||||
for (int i = 0; i < 255; i++) { | |||||
CAddrInfo infoi = CAddrInfo( | |||||
CAddress(ResolveService("250.1.1." + std::to_string(i)), NODE_NONE), | |||||
ResolveIP("250.1.1." + std::to_string(i))); | |||||
int bucket = infoi.GetNewBucket(nKey1, asmap); | |||||
buckets.insert(bucket); | |||||
} | |||||
// Test: IP addresses in the same /16 prefix | |||||
// usually map to the same bucket. | |||||
BOOST_CHECK_EQUAL(buckets.size(), 1U); | |||||
buckets.clear(); | |||||
for (int j = 0; j < 4 * 255; j++) { | |||||
CAddrInfo infoj = CAddrInfo( | |||||
CAddress(ResolveService(std::to_string(250 + (j / 255)) + "." + | |||||
std::to_string(j % 256) + ".1.1"), | |||||
NODE_NONE), | |||||
ResolveIP("251.4.1.1")); | |||||
int bucket = infoj.GetNewBucket(nKey1, asmap); | |||||
buckets.insert(bucket); | |||||
} | |||||
// Test: IP addresses in the same source /16 prefix should not map to more | |||||
// than 64 buckets. | |||||
BOOST_CHECK(buckets.size() <= 64); | |||||
buckets.clear(); | |||||
for (int p = 0; p < 255; p++) { | |||||
CAddrInfo infoj = | |||||
CAddrInfo(CAddress(ResolveService("250.1.1.1"), NODE_NONE), | |||||
ResolveIP("101." + std::to_string(p) + ".1.1")); | |||||
int bucket = infoj.GetNewBucket(nKey1, asmap); | |||||
buckets.insert(bucket); | |||||
} | |||||
// Test: IP addresses in the different source /16 prefixes usually map to | |||||
// MORE than 1 bucket. | |||||
BOOST_CHECK(buckets.size() > 1); | |||||
buckets.clear(); | |||||
for (int p = 0; p < 255; p++) { | |||||
CAddrInfo infoj = | |||||
CAddrInfo(CAddress(ResolveService("250.1.1.1"), NODE_NONE), | |||||
ResolveIP("250." + std::to_string(p) + ".1.1")); | |||||
int bucket = infoj.GetNewBucket(nKey1, asmap); | |||||
buckets.insert(bucket); | |||||
} | |||||
// Test: IP addresses in the different source /16 prefixes sometimes map to | |||||
// NO MORE than 1 bucket. | |||||
BOOST_CHECK(buckets.size() == 1); | |||||
} | |||||
BOOST_AUTO_TEST_CASE(addrman_serialization) { | |||||
std::vector<bool> asmap1 = FromBytes(asmap_raw, sizeof(asmap_raw) * 8); | |||||
CAddrManTest addrman_asmap1(true, asmap1); | |||||
CAddrManTest addrman_asmap1_dup(true, asmap1); | |||||
CAddrManTest addrman_noasmap; | |||||
CDataStream stream(SER_NETWORK, PROTOCOL_VERSION); | |||||
CAddress addr = CAddress(ResolveService("250.1.1.1"), NODE_NONE); | |||||
CNetAddr default_source; | |||||
addrman_asmap1.Add(addr, default_source); | |||||
stream << addrman_asmap1; | |||||
// serizalizing/deserializing addrman with the same asmap | |||||
stream >> addrman_asmap1_dup; | |||||
std::pair<int, int> bucketAndEntry_asmap1 = | |||||
addrman_asmap1.GetBucketAndEntry(addr); | |||||
std::pair<int, int> bucketAndEntry_asmap1_dup = | |||||
addrman_asmap1_dup.GetBucketAndEntry(addr); | |||||
BOOST_CHECK(bucketAndEntry_asmap1.second != -1); | |||||
BOOST_CHECK(bucketAndEntry_asmap1_dup.second != -1); | |||||
BOOST_CHECK(bucketAndEntry_asmap1.first == bucketAndEntry_asmap1_dup.first); | |||||
BOOST_CHECK(bucketAndEntry_asmap1.second == | |||||
bucketAndEntry_asmap1_dup.second); | |||||
// deserializing asmaped peers.dat to non-asmaped addrman | |||||
stream << addrman_asmap1; | |||||
stream >> addrman_noasmap; | |||||
std::pair<int, int> bucketAndEntry_noasmap = | |||||
addrman_noasmap.GetBucketAndEntry(addr); | |||||
BOOST_CHECK(bucketAndEntry_noasmap.second != -1); | |||||
BOOST_CHECK(bucketAndEntry_asmap1.first != bucketAndEntry_noasmap.first); | |||||
BOOST_CHECK(bucketAndEntry_asmap1.second != bucketAndEntry_noasmap.second); | |||||
// deserializing non-asmaped peers.dat to asmaped addrman | |||||
addrman_asmap1.Clear(); | |||||
addrman_noasmap.Clear(); | |||||
addrman_noasmap.Add(addr, default_source); | |||||
stream << addrman_noasmap; | |||||
stream >> addrman_asmap1; | |||||
std::pair<int, int> bucketAndEntry_asmap1_deser = | |||||
addrman_asmap1.GetBucketAndEntry(addr); | |||||
BOOST_CHECK(bucketAndEntry_asmap1_deser.second != -1); | |||||
BOOST_CHECK(bucketAndEntry_asmap1_deser.first != | |||||
bucketAndEntry_noasmap.first); | |||||
BOOST_CHECK(bucketAndEntry_asmap1_deser.first == | |||||
bucketAndEntry_asmap1_dup.first); | |||||
BOOST_CHECK(bucketAndEntry_asmap1_deser.second == | |||||
bucketAndEntry_asmap1_dup.second); | |||||
// used to map to different buckets, now maps to the same bucket. | |||||
addrman_asmap1.Clear(); | |||||
addrman_noasmap.Clear(); | |||||
CAddress addr1 = CAddress(ResolveService("250.1.1.1"), NODE_NONE); | |||||
CAddress addr2 = CAddress(ResolveService("250.2.1.1"), NODE_NONE); | |||||
addrman_noasmap.Add(addr, default_source); | |||||
addrman_noasmap.Add(addr2, default_source); | |||||
std::pair<int, int> bucketAndEntry_noasmap_addr1 = | |||||
addrman_noasmap.GetBucketAndEntry(addr1); | |||||
std::pair<int, int> bucketAndEntry_noasmap_addr2 = | |||||
addrman_noasmap.GetBucketAndEntry(addr2); | |||||
BOOST_CHECK(bucketAndEntry_noasmap_addr1.first != | |||||
bucketAndEntry_noasmap_addr2.first); | |||||
BOOST_CHECK(bucketAndEntry_noasmap_addr1.second != | |||||
bucketAndEntry_noasmap_addr2.second); | |||||
stream << addrman_noasmap; | |||||
stream >> addrman_asmap1; | |||||
std::pair<int, int> bucketAndEntry_asmap1_deser_addr1 = | |||||
addrman_asmap1.GetBucketAndEntry(addr1); | |||||
std::pair<int, int> bucketAndEntry_asmap1_deser_addr2 = | |||||
addrman_asmap1.GetBucketAndEntry(addr2); | |||||
BOOST_CHECK(bucketAndEntry_asmap1_deser_addr1.first == | |||||
bucketAndEntry_asmap1_deser_addr2.first); | |||||
BOOST_CHECK(bucketAndEntry_asmap1_deser_addr1.second != | |||||
bucketAndEntry_asmap1_deser_addr2.second); | |||||
} | |||||
BOOST_AUTO_TEST_CASE(addrman_selecttriedcollision) { | BOOST_AUTO_TEST_CASE(addrman_selecttriedcollision) { | ||||
CAddrManTest addrman; | CAddrManTest addrman; | ||||
BOOST_CHECK(addrman.size() == 0); | BOOST_CHECK(addrman.size() == 0); | ||||
// Empty addrman should return blank addrman info. | // Empty addrman should return blank addrman info. | ||||
BOOST_CHECK(addrman.SelectTriedCollision().ToString() == "[::]:0"); | BOOST_CHECK(addrman.SelectTriedCollision().ToString() == "[::]:0"); | ||||
▲ Show 20 Lines • Show All 131 Lines • Show Last 20 Lines |