Skip to content
This repository was archived by the owner on Oct 28, 2021. It is now read-only.

Commit 3cfb4fe

Browse files
committed
Tests for NodeTable::nearestNodeEntries
1 parent 17f2d77 commit 3cfb4fe

File tree

2 files changed

+93
-5
lines changed

2 files changed

+93
-5
lines changed

libp2p/NodeTable.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -270,7 +270,7 @@ vector<shared_ptr<NodeEntry>> NodeTable::nearestNodeEntries(NodeID const& _targe
270270
return _node1.first < _node2.first;
271271
};
272272

273-
std::set<pair<int, shared_ptr<NodeEntry>>, decltype(distanceToTargetLess)>
273+
std::multiset<pair<int, shared_ptr<NodeEntry>>, decltype(distanceToTargetLess)>
274274
nodesByDistanceToTarget(distanceToTargetLess);
275275
for (auto const& bucket : m_buckets)
276276
for (auto const& nodeWeakPtr : bucket.nodes)
@@ -279,7 +279,7 @@ vector<shared_ptr<NodeEntry>> NodeTable::nearestNodeEntries(NodeID const& _targe
279279
nodesByDistanceToTarget.emplace(distance(_target, node->id()), node);
280280

281281
if (nodesByDistanceToTarget.size() > s_bucketSize)
282-
nodesByDistanceToTarget.erase(nodesByDistanceToTarget.rbegin().base());
282+
nodesByDistanceToTarget.erase(--nodesByDistanceToTarget.end());
283283
}
284284

285285
vector<shared_ptr<NodeEntry>> ret;

test/unittests/libp2p/net.cpp

Lines changed: 91 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -210,13 +210,14 @@ struct TestNodeTable: public NodeTable
210210
concurrent_queue<bytes> packetsReceived;
211211

212212

213-
using NodeTable::m_hostNodeID;
213+
using NodeTable::m_allowLocalDiscovery;
214214
using NodeTable::m_hostNodeEndpoint;
215+
using NodeTable::m_hostNodeID;
215216
using NodeTable::m_socket;
217+
using NodeTable::nearestNodeEntries;
218+
using NodeTable::nodeEntry;
216219
using NodeTable::noteActiveNode;
217220
using NodeTable::setRequestTimeToLive;
218-
using NodeTable::nodeEntry;
219-
using NodeTable::m_allowLocalDiscovery;
220221
};
221222

222223
/**
@@ -550,6 +551,93 @@ BOOST_AUTO_TEST_CASE(noteActiveNodeEvictsTheNodeWhenBucketIsFull)
550551
BOOST_CHECK_EQUAL(evicted->replacementNodeEntry->id(), newNodeId);
551552
}
552553

554+
BOOST_AUTO_TEST_CASE(nearestNodeEntriesOneNode)
555+
{
556+
TestNodeTableHost nodeTableHost(1);
557+
nodeTableHost.populate(1);
558+
559+
auto& nodeTable = nodeTableHost.nodeTable;
560+
vector<shared_ptr<NodeEntry>> const nearest = nodeTable->nearestNodeEntries(NodeID::random());
561+
562+
BOOST_REQUIRE_EQUAL(nearest.size(), 1);
563+
BOOST_REQUIRE_EQUAL(nearest.front()->id(), nodeTableHost.testNodes.front().first);
564+
}
565+
566+
unsigned xorDistance(h256 const& _h1, h256 const& _h2)
567+
{
568+
u256 d = _h1 ^ _h2;
569+
unsigned ret = 0;
570+
while (d >>= 1)
571+
++ret;
572+
return ret;
573+
};
574+
575+
BOOST_AUTO_TEST_CASE(nearestNodeEntriesOneDistantNode)
576+
{
577+
// specific case that was failing - one node in bucket #252, target corresponding to bucket #253
578+
unique_ptr<TestNodeTableHost> nodeTableHost;
579+
do
580+
{
581+
nodeTableHost.reset(new TestNodeTableHost(1));
582+
nodeTableHost->populate(1);
583+
} while (nodeTableHost->nodeTable->bucketSize(252) != 1);
584+
585+
auto& nodeTable = nodeTableHost->nodeTable;
586+
587+
h256 const hostNodeIDHash = sha3(nodeTable->m_hostNodeID);
588+
589+
NodeID target = NodeID::random();
590+
while (xorDistance(hostNodeIDHash, sha3(target)) != 254)
591+
target = NodeID::random();
592+
593+
vector<shared_ptr<NodeEntry>> const nearest = nodeTable->nearestNodeEntries(target);
594+
595+
BOOST_REQUIRE_EQUAL(nearest.size(), 1);
596+
BOOST_REQUIRE_EQUAL(nearest.front()->id(), nodeTableHost->testNodes.front().first);
597+
}
598+
599+
BOOST_AUTO_TEST_CASE(nearestNodeEntriesManyNodes)
600+
{
601+
unsigned constexpr nodeCount = 128;
602+
TestNodeTableHost nodeTableHost(nodeCount);
603+
nodeTableHost.populate(nodeCount);
604+
605+
auto& nodeTable = nodeTableHost.nodeTable;
606+
607+
NodeID const target = NodeID::random();
608+
vector<shared_ptr<NodeEntry>> nearest = nodeTable->nearestNodeEntries(target);
609+
610+
BOOST_REQUIRE_EQUAL(nearest.size(), 16);
611+
612+
// get all nodes sorted by distance to target
613+
list<NodeEntry> const allNodeEntries = nodeTable->snapshot();
614+
h256 const targetNodeIDHash = sha3(target);
615+
vector<pair<unsigned, NodeID>> nodesByDistanceToTarget;
616+
for (auto const& nodeEntry : allNodeEntries)
617+
{
618+
NodeID const& nodeID = nodeEntry.id();
619+
nodesByDistanceToTarget.emplace_back(xorDistance(targetNodeIDHash, sha3(nodeID)), nodeID);
620+
}
621+
// stable sort to keep them in the order as they are in buckets
622+
// (the same order they are iterated in nearestNodeEntries implementation)
623+
std::stable_sort(nodesByDistanceToTarget.begin(), nodesByDistanceToTarget.end(),
624+
[](pair<unsigned, NodeID> const& _n1, pair<unsigned, NodeID> const& _n2) {
625+
return _n1.first < _n2.first;
626+
});
627+
// get 16 with lowest distance
628+
std::vector<NodeID> expectedNearestIDs;
629+
std::transform(nodesByDistanceToTarget.begin(), nodesByDistanceToTarget.begin() + 16,
630+
std::back_inserter(expectedNearestIDs),
631+
[](pair<unsigned, NodeID> const& _n) { return _n.second; });
632+
633+
634+
vector<NodeID> nearestIDs;
635+
for (auto const& nodeEntry : nearest)
636+
nearestIDs.push_back(nodeEntry->id());
637+
638+
BOOST_REQUIRE(nearestIDs == expectedNearestIDs);
639+
}
640+
553641
BOOST_AUTO_TEST_CASE(unexpectedPong)
554642
{
555643
// NodeTable receiving PONG

0 commit comments

Comments
 (0)