@@ -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+
553641BOOST_AUTO_TEST_CASE (unexpectedPong)
554642{
555643 // NodeTable receiving PONG
0 commit comments