diff --git a/include/libp2p/injector/network_injector.hpp b/include/libp2p/injector/network_injector.hpp index 81fabf60..d2e0a2a7 100644 --- a/include/libp2p/injector/network_injector.hpp +++ b/include/libp2p/injector/network_injector.hpp @@ -147,9 +147,9 @@ namespace libp2p::injector { * ); * @endcode */ - inline auto useKeyPair(const crypto::KeyPair &key_pair) { + inline auto useKeyPair(crypto::KeyPair key_pair) { return boost::di::bind().template to( - key_pair)[boost::di::override]; + std::move(key_pair))[boost::di::override]; } /** diff --git a/include/libp2p/protocol/kademlia/config.hpp b/include/libp2p/protocol/kademlia/config.hpp index e66b6a12..aa7d1756 100644 --- a/include/libp2p/protocol/kademlia/config.hpp +++ b/include/libp2p/protocol/kademlia/config.hpp @@ -13,6 +13,9 @@ namespace libp2p::protocol::kademlia { using namespace std::chrono_literals; + // https://github.com/libp2p/rust-libp2p/blob/e63975d7742710d4498b941e151c5177e06392ce/protocols/kad/src/lib.rs#L93 + constexpr size_t K_VALUE = 20; + namespace { struct RandomWalk { /** @@ -122,7 +125,7 @@ namespace libp2p::protocol::kademlia { * This is implementation specified property. * @note Default: 20 */ - size_t maxBucketSize = 20; + size_t maxBucketSize = K_VALUE; /** * Maximum time to waiting response @@ -142,6 +145,9 @@ namespace libp2p::protocol::kademlia { * Random walk config */ RandomWalk randomWalk{}; + + // https://github.com/libp2p/rust-libp2p/blob/c6cf7fec6913aa590622aeea16709fce6e9c99a5/protocols/kad/src/query/peers/closest.rs#L110-L120 + size_t query_initial_peers = K_VALUE; }; } // namespace libp2p::protocol::kademlia diff --git a/include/libp2p/protocol/kademlia/impl/find_peer_executor.hpp b/include/libp2p/protocol/kademlia/impl/find_peer_executor.hpp index a423103e..2589b133 100644 --- a/include/libp2p/protocol/kademlia/impl/find_peer_executor.hpp +++ b/include/libp2p/protocol/kademlia/impl/find_peer_executor.hpp @@ -22,7 +22,6 @@ #include #include #include -#include namespace libp2p::protocol::kademlia { @@ -35,7 +34,6 @@ namespace libp2p::protocol::kademlia { std::shared_ptr host, std::shared_ptr scheduler, std::shared_ptr session_host, - std::shared_ptr peer_routing, const std::shared_ptr &peer_routing_table, PeerId peer_id, FoundPeerInfoHandler handler); @@ -70,7 +68,6 @@ namespace libp2p::protocol::kademlia { std::shared_ptr host_; std::shared_ptr scheduler_; std::shared_ptr session_host_; - std::shared_ptr peer_routing_; // Secondary const PeerId sought_peer_id_; diff --git a/include/libp2p/protocol/kademlia/impl/get_value_executor.hpp b/include/libp2p/protocol/kademlia/impl/get_value_executor.hpp index d7ae4160..437beb45 100644 --- a/include/libp2p/protocol/kademlia/impl/get_value_executor.hpp +++ b/include/libp2p/protocol/kademlia/impl/get_value_executor.hpp @@ -26,7 +26,6 @@ #include #include #include -#include #include namespace libp2p::protocol::kademlia { @@ -40,7 +39,6 @@ namespace libp2p::protocol::kademlia { std::shared_ptr host, std::shared_ptr scheduler, std::shared_ptr session_host, - std::shared_ptr peer_routing, std::shared_ptr content_routing_table, const std::shared_ptr &peer_routing_table, std::shared_ptr executor_factory, @@ -76,7 +74,6 @@ namespace libp2p::protocol::kademlia { std::shared_ptr host_; std::shared_ptr scheduler_; std::shared_ptr session_host_; - std::shared_ptr peer_routing_; std::shared_ptr content_routing_table_; std::shared_ptr executor_factory_; std::shared_ptr validator_; diff --git a/include/libp2p/protocol/kademlia/impl/kademlia_impl.hpp b/include/libp2p/protocol/kademlia/impl/kademlia_impl.hpp index 05fde400..91d04ded 100644 --- a/include/libp2p/protocol/kademlia/impl/kademlia_impl.hpp +++ b/include/libp2p/protocol/kademlia/impl/kademlia_impl.hpp @@ -140,6 +140,7 @@ namespace libp2p::protocol::kademlia { // Subscribtion to new connections event::Handle new_connection_subscription_; + event::Handle on_disconnected_; struct StreamPtrComparator { bool operator()(const std::shared_ptr &lhs, diff --git a/include/libp2p/protocol/kademlia/impl/peer_id_with_distance.hpp b/include/libp2p/protocol/kademlia/impl/peer_id_with_distance.hpp index 475fdd05..0c8168c6 100644 --- a/include/libp2p/protocol/kademlia/impl/peer_id_with_distance.hpp +++ b/include/libp2p/protocol/kademlia/impl/peer_id_with_distance.hpp @@ -10,7 +10,10 @@ #include namespace libp2p::protocol::kademlia { - + /** + * Used with `priority_queue`. + * `top()` must be minimal distance, so `operator<` is reversed. + */ struct PeerIdWithDistance { template PeerIdWithDistance(const PeerId &peer_id, T &&target) @@ -21,7 +24,7 @@ namespace libp2p::protocol::kademlia { bool operator<(const PeerIdWithDistance &other) const { return std::memcmp( distance_.data(), other.distance_.data(), distance_.size()) - < 0; + > 0; } const PeerId &operator*() const { diff --git a/include/libp2p/protocol/kademlia/impl/peer_routing_table_impl.hpp b/include/libp2p/protocol/kademlia/impl/peer_routing_table_impl.hpp index d49e8ead..06105bc3 100644 --- a/include/libp2p/protocol/kademlia/impl/peer_routing_table_impl.hpp +++ b/include/libp2p/protocol/kademlia/impl/peer_routing_table_impl.hpp @@ -19,27 +19,24 @@ #include namespace libp2p::protocol::kademlia { + constexpr size_t kBucketCount = 256; struct BucketPeerInfo { peer::PeerId peer_id; bool is_replaceable; + bool is_connected; NodeId node_id; - BucketPeerInfo(const peer::PeerId &peer_id, bool is_replaceable) - : peer_id(peer_id), is_replaceable(is_replaceable), node_id(peer_id) {} + BucketPeerInfo(const PeerId &peer_id, + bool is_replaceable, + bool is_connected) + : peer_id{peer_id}, + is_replaceable{is_replaceable}, + is_connected{is_connected}, + node_id{peer_id} {} }; struct XorDistanceComparator { - explicit XorDistanceComparator(const peer::PeerId &from) { - hfrom = crypto::sha256(from.toVector()).value(); - } - - explicit XorDistanceComparator(const NodeId &from) - : hfrom(from.getData()) {} - - explicit XorDistanceComparator(const Hash256 &hash) : hfrom(hash) {} - bool operator()(const BucketPeerInfo &a, const BucketPeerInfo &b) { - NodeId from(hfrom); auto d1 = a.node_id.distance(from); auto d2 = b.node_id.distance(from); constexpr auto size = Hash256().size(); @@ -48,7 +45,7 @@ namespace libp2p::protocol::kademlia { return std::memcmp(d1.data(), d2.data(), size) < 0; } - Hash256 hfrom{}; + NodeId from; }; /** @@ -67,7 +64,9 @@ namespace libp2p::protocol::kademlia { bool moveToFront(const PeerId &pid); - void emplaceToFront(const PeerId &pid, bool is_replaceable); + void emplaceToFront(const PeerId &pid, + bool is_replaceable, + bool is_connected); boost::optional removeReplaceableItem(); @@ -79,8 +78,6 @@ namespace libp2p::protocol::kademlia { bool remove(const peer::PeerId &p); - Bucket split(size_t commonLenPrefix, const NodeId &target); - private: std::list peers_; }; @@ -116,7 +113,7 @@ namespace libp2p::protocol::kademlia { size_t size() const override; private: - void nextBucket(); + std::optional getBucketIndex(const NodeId &key) const; const Config &config_; std::shared_ptr identity_manager_; @@ -124,9 +121,7 @@ namespace libp2p::protocol::kademlia { const NodeId local_; - std::vector buckets_; - - log::SubLogger log_; + std::array buckets_; }; } // namespace libp2p::protocol::kademlia diff --git a/include/libp2p/protocol/kademlia/node_id.hpp b/include/libp2p/protocol/kademlia/node_id.hpp index dc2cefc2..176c73e5 100644 --- a/include/libp2p/protocol/kademlia/node_id.hpp +++ b/include/libp2p/protocol/kademlia/node_id.hpp @@ -53,22 +53,17 @@ namespace libp2p::protocol::kademlia { */ class NodeId { public: - explicit NodeId(const Hash256 &h) : data_(h) {} - - explicit NodeId(const void *bytes) { - memcpy(data_.data(), bytes, data_.size()); - } - explicit NodeId(const peer::PeerId &pid) { auto digest_res = crypto::sha256(pid.toVector()); BOOST_ASSERT(digest_res.has_value()); data_ = std::move(digest_res.value()); } - explicit NodeId(const ContentId &content_id) { - auto digest_res = crypto::sha256(content_id); - BOOST_ASSERT(digest_res.has_value()); - data_ = std::move(digest_res.value()); + static NodeId prehashed(Hash256 hash) { + return NodeId{hash}; + } + static NodeId hash(BytesIn key) { + return prehashed(crypto::sha256(key).value()); } inline bool operator==(const NodeId &other) const { @@ -106,6 +101,8 @@ namespace libp2p::protocol::kademlia { } private: + explicit NodeId(Hash256 hash) : data_{hash} {} + Hash256 data_; }; diff --git a/src/protocol/kademlia/impl/add_provider_executor.cpp b/src/protocol/kademlia/impl/add_provider_executor.cpp index c56aa398..4c8bc487 100644 --- a/src/protocol/kademlia/impl/add_provider_executor.cpp +++ b/src/protocol/kademlia/impl/add_provider_executor.cpp @@ -28,10 +28,10 @@ namespace libp2p::protocol::kademlia { scheduler_(std::move(scheduler)), session_host_(std::move(session_host)), key_(std::move(key)), - target_(key_), + target_{NodeId::hash(key_)}, log_("KademliaExecutor", "kademlia", "AddProvider", ++instance_number) { - auto nearest_peer_ids = - peer_routing_table->getNearestPeers(target_, config_.maxBucketSize); + auto nearest_peer_ids = peer_routing_table->getNearestPeers( + target_, config_.query_initial_peers); nearest_peer_ids_.insert(std::move_iterator(nearest_peer_ids.begin()), std::move_iterator(nearest_peer_ids.end())); diff --git a/src/protocol/kademlia/impl/find_peer_executor.cpp b/src/protocol/kademlia/impl/find_peer_executor.cpp index c3198b30..05e2a6b5 100644 --- a/src/protocol/kademlia/impl/find_peer_executor.cpp +++ b/src/protocol/kademlia/impl/find_peer_executor.cpp @@ -24,7 +24,6 @@ namespace libp2p::protocol::kademlia { std::shared_ptr host, std::shared_ptr scheduler, std::shared_ptr session_host, - std::shared_ptr peer_routing, const std::shared_ptr &peer_routing_table, PeerId sought_peer_id, FoundPeerInfoHandler handler) @@ -32,13 +31,12 @@ namespace libp2p::protocol::kademlia { host_(std::move(host)), scheduler_(std::move(scheduler)), session_host_(std::move(session_host)), - peer_routing_(std::move(peer_routing)), sought_peer_id_(std::move(sought_peer_id)), target_(sought_peer_id_), handler_(std::move(handler)), log_("KademliaExecutor", "kademlia", "FindPeer", ++instance_number) { auto nearest_peer_ids = peer_routing_table->getNearestPeers( - target_, config_.closerPeerCount * 2); + target_, config_.query_initial_peers); nearest_peer_ids_.insert(std::move_iterator(nearest_peer_ids.begin()), std::move_iterator(nearest_peer_ids.end())); diff --git a/src/protocol/kademlia/impl/find_providers_executor.cpp b/src/protocol/kademlia/impl/find_providers_executor.cpp index 228589d1..ba7c4a14 100644 --- a/src/protocol/kademlia/impl/find_providers_executor.cpp +++ b/src/protocol/kademlia/impl/find_providers_executor.cpp @@ -33,7 +33,7 @@ namespace libp2p::protocol::kademlia { session_host_(std::move(session_host)), content_id_(std::move(content_id)), handler_(std::move(handler)), - target_(content_id_), + target_{NodeId::hash(content_id_)}, log_("KademliaExecutor", "kademlia", "FindProviders", @@ -43,7 +43,7 @@ namespace libp2p::protocol::kademlia { BOOST_ASSERT(session_host_ != nullptr); auto nearest_peer_ids = peer_routing_table->getNearestPeers( - target_, config_.closerPeerCount * 2); + target_, config_.query_initial_peers); nearest_peer_ids_.insert(std::move_iterator(nearest_peer_ids.begin()), std::move_iterator(nearest_peer_ids.end())); diff --git a/src/protocol/kademlia/impl/get_value_executor.cpp b/src/protocol/kademlia/impl/get_value_executor.cpp index 6d5c576e..55dfa681 100644 --- a/src/protocol/kademlia/impl/get_value_executor.cpp +++ b/src/protocol/kademlia/impl/get_value_executor.cpp @@ -29,7 +29,6 @@ namespace libp2p::protocol::kademlia { std::shared_ptr host, std::shared_ptr scheduler, std::shared_ptr session_host, - std::shared_ptr peer_routing, std::shared_ptr content_routing_table, const std::shared_ptr &peer_routing_table, std::shared_ptr executor_factory, @@ -40,24 +39,22 @@ namespace libp2p::protocol::kademlia { host_(std::move(host)), scheduler_(std::move(scheduler)), session_host_(std::move(session_host)), - peer_routing_(std::move(peer_routing)), content_routing_table_(std::move(content_routing_table)), executor_factory_(std::move(executor_factory)), validator_(std::move(validator)), key_(std::move(key)), handler_(std::move(handler)), - target_(key_), + target_{NodeId::hash(key_)}, log_("KademliaExecutor", "kademlia", "GetValue", ++instance_number) { BOOST_ASSERT(host_ != nullptr); BOOST_ASSERT(scheduler_ != nullptr); BOOST_ASSERT(session_host_ != nullptr); - BOOST_ASSERT(peer_routing_ != nullptr); BOOST_ASSERT(content_routing_table_ != nullptr); BOOST_ASSERT(executor_factory_ != nullptr); BOOST_ASSERT(validator_ != nullptr); auto nearest_peer_ids = peer_routing_table->getNearestPeers( - target_, config_.closerPeerCount * 2); + target_, config_.query_initial_peers); nearest_peer_ids_.insert(std::move_iterator(nearest_peer_ids.begin()), std::move_iterator(nearest_peer_ids.end())); diff --git a/src/protocol/kademlia/impl/kademlia_impl.cpp b/src/protocol/kademlia/impl/kademlia_impl.cpp index a09843c5..81017ed3 100644 --- a/src/protocol/kademlia/impl/kademlia_impl.cpp +++ b/src/protocol/kademlia/impl/kademlia_impl.cpp @@ -99,10 +99,22 @@ namespace libp2p::protocol::kademlia { addPeer( peer::PeerInfo{std::move(remote_peer_res.value()), {std::move(remote_peer_addr_res.value())}}, - false); + false, + true); } } }); + on_disconnected_ = + host_->getBus() + .getChannel() + .subscribe([weak_self{weak_from_this()}](const PeerId &peer) { + auto self = weak_self.lock(); + if (not self) { + return; + } + std::ignore = + self->peer_routing_table_->update(peer, false, false); + }); // start random walking if (config_.randomWalk.enabled) { @@ -434,7 +446,7 @@ namespace libp2p::protocol::kademlia { } peer_ids = peer_routing_table_->getNearestPeers( - NodeId(msg.key), config_.closerPeerCount * 2); + NodeId::hash(msg.key), config_.closerPeerCount * 2); if (not peer_ids.empty()) { std::vector peers; @@ -491,7 +503,7 @@ namespace libp2p::protocol::kademlia { log_.debug("MSG: FindNode ({})", multi::detail::encodeBase58(msg.key)); auto ids = peer_routing_table_->getNearestPeers( - NodeId(msg.key), config_.closerPeerCount * 2); + NodeId::hash(msg.key), config_.closerPeerCount * 2); std::vector peers; peers.reserve(config_.closerPeerCount); @@ -639,7 +651,6 @@ namespace libp2p::protocol::kademlia { host_, scheduler_, shared_from_this(), - shared_from_this(), content_routing_table_, peer_routing_table_, shared_from_this(), @@ -676,7 +687,6 @@ namespace libp2p::protocol::kademlia { host_, scheduler_, shared_from_this(), - shared_from_this(), peer_routing_table_, std::move(peer_id), std::move(handler)); diff --git a/src/protocol/kademlia/impl/peer_routing_table_impl.cpp b/src/protocol/kademlia/impl/peer_routing_table_impl.cpp index ccc56b77..460edfb7 100644 --- a/src/protocol/kademlia/impl/peer_routing_table_impl.cpp +++ b/src/protocol/kademlia/impl/peer_routing_table_impl.cpp @@ -27,15 +27,6 @@ OUTCOME_CPP_DEFINE_CATEGORY(libp2p::protocol::kademlia, return "unknown error"; } -namespace { - using libp2p::protocol::kademlia::Bucket; - - size_t getBucketId(const std::vector &buckets, size_t cpl) { - BOOST_ASSERT(not buckets.empty()); - return cpl >= buckets.size() ? buckets.size() - 1 : cpl; - } -} // namespace - namespace libp2p::protocol::kademlia { size_t Bucket::size() const { @@ -47,19 +38,23 @@ namespace libp2p::protocol::kademlia { } void Bucket::sort(const NodeId &node_id) { - XorDistanceComparator cmp(node_id); + XorDistanceComparator cmp{node_id}; peers_.sort(cmp); } + auto findPeer(auto &peers, const peer::PeerId &p) { + return std::ranges::find_if(peers, + [&p](const auto &i) { return i.peer_id == p; }); + } + auto Bucket::find(const peer::PeerId &p) const { - return std::find_if(peers_.begin(), peers_.end(), [&p](const auto &i) { - return i.peer_id == p; - }); + return findPeer(peers_, p); } bool Bucket::moveToFront(const PeerId &pid) { - auto it = find(pid); + auto it = findPeer(peers_, pid); if (it != peers_.end()) { + it->is_connected = true; if (it != peers_.begin()) { peers_.splice(peers_.begin(), peers_, it); } @@ -68,15 +63,18 @@ namespace libp2p::protocol::kademlia { return true; } - void Bucket::emplaceToFront(const PeerId &pid, bool is_replaceable) { - peers_.emplace(peers_.begin(), pid, is_replaceable); + void Bucket::emplaceToFront(const PeerId &pid, + bool is_replaceable, + bool is_connected) { + peers_.emplace(peers_.begin(), pid, is_replaceable, is_connected); } boost::optional Bucket::removeReplaceableItem() { boost::optional result; for (auto it = peers_.rbegin(); it != peers_.rend(); ++it) { - if (it->is_replaceable) { + // https://github.com/libp2p/rust-libp2p/blob/3837e33cd4c40ae703138e6aed6f6c9d52928a80/protocols/kad/src/kbucket/bucket.rs#L310-L366 + if (it->is_replaceable and not it->is_connected) { result = std::move(it->peer_id); peers_.erase((++it).base()); break; @@ -119,25 +117,6 @@ namespace libp2p::protocol::kademlia { return false; } - Bucket Bucket::split(size_t commonLenPrefix, const NodeId &target) { - Bucket b{}; - - std::list new_peers; - - while (!peers_.empty()) { - auto it = peers_.begin(); - if (it->node_id.commonPrefixLen(target) > commonLenPrefix) { - b.peers_.splice(b.peers_.end(), peers_, it); - } else { - new_peers.splice(new_peers.end(), peers_, it); - } - } - - peers_.swap(new_peers); - - return b; - } - PeerRoutingTableImpl::PeerRoutingTableImpl( const Config &config, std::shared_ptr identity_manager, @@ -148,55 +127,65 @@ namespace libp2p::protocol::kademlia { local_([this] { BOOST_ASSERT(identity_manager_ != nullptr); return identity_manager_->getId(); - }()), - log_("PeerRoutingTable", "kademlia") { + }()) { BOOST_ASSERT(identity_manager_ != nullptr); BOOST_ASSERT(bus_ != nullptr); BOOST_ASSERT(config_.maxBucketSize > 1); - buckets_.emplace_back(); // create initial bucket } void PeerRoutingTableImpl::remove(const peer::PeerId &peer_id) { - size_t cpl = NodeId(peer_id).commonPrefixLen(local_); - auto bucket_id = getBucketId(buckets_, cpl); - auto &bucket = buckets_.at(bucket_id); + auto bucket_index = getBucketIndex(NodeId{peer_id}); + if (not bucket_index) { + return; + } + auto &bucket = buckets_.at(*bucket_index); bucket.remove(peer_id); bus_->getChannel().publish( peer_id); } + // https://github.com/libp2p/rust-libp2p/blob/3837e33cd4c40ae703138e6aed6f6c9d52928a80/protocols/kad/src/kbucket.rs#L400-L461 std::vector PeerRoutingTableImpl::getNearestPeers( const NodeId &node_id, size_t count) { - size_t cpl = node_id.commonPrefixLen(local_); - size_t bucketId = getBucketId(buckets_, cpl); - - // make a copy of a bucket - auto bucket = buckets_.at(bucketId); - if (bucket.size() < count) { - // In the case of an unusual split, one bucket may be short or empty. - // if this happens, search both surrounding buckets for nearby peers - if (bucketId > 0) { - auto &left = buckets_.at(bucketId - 1); - bucket.append(left); + auto distance = local_.distance(node_id); + // check if distance bit is set + // https://github.com/libp2p/rust-libp2p/blob/3837e33cd4c40ae703138e6aed6f6c9d52928a80/protocols/kad/src/kbucket.rs#L409-L428 + auto bit = [&](size_t i) { + auto j = 255 - i; + return ((distance[j / 8] >> (7 - j % 8)) & 1) != 0; + }; + auto bucket_index = getBucketIndex(node_id); + Bucket result; + auto done = [&] { return result.size() >= count; }; + auto append = [&](size_t i) { result.append(buckets_.at(i)); }; + if (bucket_index) { + if (auto i = *bucket_index) { + append(i); + for (--i; i != 0 and not done(); --i) { + if (bit(i)) { + append(i); + } + } } - if (bucketId < buckets_.size() - 1) { - auto &right = buckets_.at(bucketId + 1); - bucket.append(right); + } + if (not done()) { + append(0); + } + for (size_t i = 1; i < 256 and not done(); ++i) { + if (not bit(i)) { + append(i); } } - - // sort bucket in ascending order by XOR distance from local peer. - bucket.sort(node_id); - - bucket.truncate(count); - - return bucket.peerIds(); + result.sort(node_id); + result.truncate(count); + return result.peerIds(); } namespace { outcome::result replacePeer(Bucket &bucket, const peer::PeerId &pid, bool is_replaceable, + bool is_connected, event::Bus &bus) { const auto removed = bucket.removeReplaceableItem(); if (!removed.has_value()) { @@ -204,7 +193,7 @@ namespace libp2p::protocol::kademlia { } bus.getChannel().publish( removed.value()); - bucket.emplaceToFront(pid, is_replaceable); + bucket.emplaceToFront(pid, is_replaceable, is_connected); bus.getChannel().publish( pid); return true; @@ -214,11 +203,11 @@ namespace libp2p::protocol::kademlia { outcome::result PeerRoutingTableImpl::update(const peer::PeerId &pid, bool is_permanent, bool is_connected) { - NodeId nodeId(pid); - size_t cpl = nodeId.commonPrefixLen(local_); - - auto bucketId = getBucketId(buckets_, cpl); - auto &bucket = buckets_.at(bucketId); + auto bucket_index = getBucketIndex(NodeId{pid}); + if (not bucket_index) { + return true; + } + auto &bucket = buckets_.at(*bucket_index); // Trying to find and move to front if its a long lived connected peer if (is_connected) { @@ -230,52 +219,13 @@ namespace libp2p::protocol::kademlia { } if (bucket.size() < config_.maxBucketSize) { - bucket.emplaceToFront(pid, !is_permanent); + bucket.emplaceToFront(pid, not is_permanent, is_connected); bus_->getChannel().publish( pid); return true; } - if (bucketId == buckets_.size() - 1) { - // this is last bucket - // if the bucket is too large and this is the last bucket (i.e. wildcard), - // unfold it. - nextBucket(); - - // the structure of the table has changed, so let's recheck if the peer - // now has a dedicated bucket. - auto resizedBucketId = getBucketId(buckets_, cpl); - auto &resizedBucket = buckets_.at(resizedBucketId); - if (resizedBucket.size() < config_.maxBucketSize) { - resizedBucket.emplaceToFront(pid, !is_permanent); - bus_->getChannel().publish( - pid); - return true; - } - - return replacePeer(resizedBucket, pid, !is_permanent, *bus_); - } - - return replacePeer(bucket, pid, !is_permanent, *bus_); - } - - void PeerRoutingTableImpl::nextBucket() { - // This is the last bucket, which allegedly is a mixed bag containing - // peers not belonging in dedicated (unfolded) buckets. _allegedly_ is - // used here to denote that *all* peers in the last bucket might feasibly - // belong to another bucket. This could happen if e.g. we've unfolded 4 - // buckets, and all peers in folded bucket 5 really belong in bucket 8. - - // get last bucket - auto bucket = buckets_.rbegin(); - // split it - auto newBucket = bucket->split(buckets_.size() - 1, local_); - buckets_.push_back(std::move(newBucket)); - - auto newLastBucket = buckets_.rbegin(); - if (newLastBucket->size() > config_.maxBucketSize) { - nextBucket(); - } + return replacePeer(bucket, pid, not is_permanent, is_connected, *bus_); } size_t PeerRoutingTableImpl::size() const { @@ -294,4 +244,13 @@ namespace libp2p::protocol::kademlia { } return vec; } + + // https://github.com/libp2p/rust-libp2p/blob/3837e33cd4c40ae703138e6aed6f6c9d52928a80/protocols/kad/src/kbucket.rs#L141-L150 + std::optional PeerRoutingTableImpl::getBucketIndex( + const NodeId &key) const { + if (local_ == key) { + return std::nullopt; + } + return 255 - local_.commonPrefixLen(key); + } } // namespace libp2p::protocol::kademlia diff --git a/test/libp2p/protocol/kademlia/node_id_test.cpp b/test/libp2p/protocol/kademlia/node_id_test.cpp index 6d6503a1..bd31935b 100644 --- a/test/libp2p/protocol/kademlia/node_id_test.cpp +++ b/test/libp2p/protocol/kademlia/node_id_test.cpp @@ -76,13 +76,13 @@ TEST(KadDistance, SortsHashes) { size_t peersTotal = 1000; srand(0); // make test deterministic PeerId us = "1"_peerid; - XorDistanceComparator comp(us); + XorDistanceComparator comp{NodeId{us}}; std::vector peers; std::generate_n(std::back_inserter(peers), peersTotal, []() { - return BucketPeerInfo(testutil::randomPeerId(), false); + return BucketPeerInfo(testutil::randomPeerId(), false, false); }); - peers.emplace_back(us, false); + peers.emplace_back(us, false, false); ASSERT_EQ(peers.size(), peersTotal + 1); std::cout << "unsorted ";