Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(kad): add refresh_interval config used to poll bootstrap #4838

Merged
merged 45 commits into from
Mar 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
dc770aa
add poll function in kademlia behaviour that polls bootstrap function
PanGan21 Nov 12, 2023
30559da
bumb kad version and add changelog
PanGan21 Nov 12, 2023
a7fcd26
bumb server version and add server changelog
PanGan21 Nov 12, 2023
695b94a
Fix doc comments
PanGan21 Nov 12, 2023
0b54f9a
Rename to bootstrap_interval
PanGan21 Nov 12, 2023
d749cbd
Update protocols/kad/src/behaviour.rs
PanGan21 Nov 12, 2023
7f720ce
fix terminology across behaviour
PanGan21 Nov 12, 2023
3a7737c
move polling into the internal poll function
PanGan21 Nov 14, 2023
ac0fdd6
fix conflicts
PanGan21 Nov 14, 2023
7343bb2
do not reference private fields in doc
PanGan21 Nov 14, 2023
271ed03
Merge branch 'master' into kademlia-poll-bootstrap
PanGan21 Nov 23, 2023
17e941c
Merge branch 'master' into kademlia-poll-bootstrap
PanGan21 Nov 25, 2023
ea694e5
Merge branch 'master' into kademlia-poll-bootstrap
PanGan21 Nov 27, 2023
f492105
call bootstrap on new kademlia node connected
PanGan21 Nov 27, 2023
dcf8495
add enum to track the state of the initial bootstrap
PanGan21 Nov 28, 2023
e7595a0
Merge branch 'master' into kademlia-poll-bootstrap
PanGan21 Nov 28, 2023
72bc4be
Merge branch 'master' into kademlia-poll-bootstrap
PanGan21 Nov 29, 2023
f72a8a1
fix conflicts
PanGan21 Nov 30, 2023
f2aaad2
track if there was a successfull bootstrap and the query id of the au…
PanGan21 Nov 30, 2023
4d43c33
Merge branch 'master' into kademlia-poll-bootstrap
PanGan21 Dec 1, 2023
8604f72
fix conflicts
PanGan21 Dec 2, 2023
179db10
add link in doc, handle successful bootstrap, reanable polling
PanGan21 Dec 2, 2023
9c7b8e8
fix doc and remove test change
PanGan21 Dec 2, 2023
75889e1
Use defensive programming
thomaseizinger Dec 3, 2023
091cb10
Merge branch 'master' into kademlia-poll-bootstrap
thomaseizinger Dec 3, 2023
f14b988
Refactor using enum that represends the bootstrap status
PanGan21 Dec 5, 2023
a7d2bc0
fix existing unit tests
PanGan21 Dec 5, 2023
987b89a
Merge branch 'master' into kademlia-poll-bootstrap
PanGan21 Dec 5, 2023
f0e563e
satisfy clippy
PanGan21 Dec 5, 2023
82332a8
Merge branch 'master' into kademlia-poll-bootstrap
PanGan21 Dec 5, 2023
3aa9101
Slightly re-design `bootstrap::Status`
thomaseizinger Dec 6, 2023
c796150
fix conflicts
PanGan21 Jan 17, 2024
850bc22
feat(kad): Add periodic and automatic bootstrap
PanGan21 Nov 12, 2023
fe3e558
Merge pull request #1 from stormshield-frb/PanGan21-automatic-bootstrap
PanGan21 Jan 24, 2024
bb8ca9f
fix conflicts
PanGan21 Jan 25, 2024
99458a7
Preventing automatic_throttle configuration
stormshield-frb Feb 15, 2024
394d86b
Merge pull request #2 from stormshield-frb/PanGan21-automatic-bootstrap
PanGan21 Feb 20, 2024
b18c8d1
fix conflicts
PanGan21 Feb 20, 2024
fcafa60
satisfy clippy
PanGan21 Feb 20, 2024
cc2f533
Merge branch 'master' into kademlia-poll-bootstrap
PanGan21 Feb 25, 2024
89b011a
fix conflicts
PanGan21 Mar 3, 2024
245c2c8
fix: use current kad version
PanGan21 Mar 6, 2024
3000dd1
Merge branch 'master' into kademlia-poll-bootstrap
PanGan21 Mar 6, 2024
5f8ef81
reference automatic_bootstrap_throttle in the docs
PanGan21 Mar 7, 2024
a58ed37
fix bootstrap doc to omit private config
PanGan21 Mar 7, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ libp2p-quic = { version = "0.10.2", path = "transports/quic" }
libp2p-relay = { version = "0.17.1", path = "protocols/relay" }
libp2p-rendezvous = { version = "0.14.0", path = "protocols/rendezvous" }
libp2p-request-response = { version = "0.26.2", path = "protocols/request-response" }
libp2p-server = { version = "0.12.6", path = "misc/server" }
libp2p-server = { version = "0.12.7", path = "misc/server" }
libp2p-stream = { version = "0.1.0-alpha.1", path = "protocols/stream" }
libp2p-swarm = { version = "0.44.2", path = "swarm" }
libp2p-swarm-derive = { version = "=0.34.3", path = "swarm-derive" } # `libp2p-swarm-derive` may not be compatible with different `libp2p-swarm` non-breaking releases. E.g. `libp2p-swarm` might introduce a new enum variant `FromSwarm` (which is `#[non-exhaustive]`) in a non-breaking release. Older versions of `libp2p-swarm-derive` would not forward this enum variant within the `NetworkBehaviour` hierarchy. Thus the version pinning is required.
Expand Down
8 changes: 8 additions & 0 deletions misc/server/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
## 0.12.7

### Changed

- Use periodic and automatic bootstrap of Kademlia.
See [PR 4838](https://github.com/libp2p/rust-libp2p/pull/4838).

## 0.12.6

### Changed

- Stop using kad default protocol.
See [PR 5122](https://github.com/libp2p/rust-libp2p/pull/5122)

Expand Down
2 changes: 1 addition & 1 deletion misc/server/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "libp2p-server"
version = "0.12.6"
version = "0.12.7"
authors = ["Max Inden <mail@max-inden.de>"]
edition = "2021"
repository = "https://github.com/libp2p/rust-libp2p"
Expand Down
16 changes: 0 additions & 16 deletions misc/server/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use base64::Engine;
use clap::Parser;
use futures::stream::StreamExt;
use futures_timer::Delay;
use libp2p::identity;
use libp2p::identity::PeerId;
use libp2p::kad;
Expand All @@ -14,17 +13,13 @@ use prometheus_client::registry::Registry;
use std::error::Error;
use std::path::PathBuf;
use std::str::FromStr;
use std::task::Poll;
use std::time::Duration;
use tracing_subscriber::EnvFilter;
use zeroize::Zeroizing;

mod behaviour;
mod config;
mod http_service;

const BOOTSTRAP_INTERVAL: Duration = Duration::from_secs(5 * 60);

#[derive(Debug, Parser)]
#[clap(name = "libp2p server", about = "A rust-libp2p server binary.")]
struct Opts {
Expand Down Expand Up @@ -127,18 +122,7 @@ async fn main() -> Result<(), Box<dyn Error>> {
}
});

let mut bootstrap_timer = Delay::new(BOOTSTRAP_INTERVAL);

loop {
if let Poll::Ready(()) = futures::poll!(&mut bootstrap_timer) {
bootstrap_timer.reset(BOOTSTRAP_INTERVAL);
let _ = swarm
.behaviour_mut()
.kademlia
.as_mut()
.map(|k| k.bootstrap());
}

let event = swarm.next().await.expect("Swarm not to terminate.");
metrics.record(&event);
match event {
Expand Down
2 changes: 2 additions & 0 deletions protocols/kad/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
## 0.45.4

- Add periodic and automatic bootstrap.
See [PR 4838](https://github.com/libp2p/rust-libp2p/pull/4838).
- Make it mandatory to provide protocol names when creating a `kad::Config`.
Deprecate `kad::Config::default()`, replaced by `kad::Config::new(StreamProtocol)`.
See [PR 5122](https://github.com/libp2p/rust-libp2p/pull/5122).
Expand Down
59 changes: 59 additions & 0 deletions protocols/kad/src/behaviour.rs
thomaseizinger marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
mod test;

use crate::addresses::Addresses;
use crate::bootstrap;
use crate::handler::{Handler, HandlerEvent, HandlerIn, RequestId};
use crate::kbucket::{self, Distance, KBucketsTable, NodeStatus};
use crate::protocol::{ConnectionType, KadPeer, ProtocolConfig};
Expand Down Expand Up @@ -116,6 +117,9 @@ pub struct Behaviour<TStore> {

/// The record storage.
store: TStore,

/// Tracks the status of the current bootstrap.
bootstrap_status: bootstrap::Status,
}

/// The configurable strategies for the insertion of peers
Expand Down Expand Up @@ -181,6 +185,8 @@ pub struct Config {
provider_publication_interval: Option<Duration>,
kbucket_inserts: BucketInserts,
caching: Caching,
periodic_bootstrap_interval: Option<Duration>,
automatic_bootstrap_throttle: Option<Duration>,
}

impl Default for Config {
Expand Down Expand Up @@ -222,6 +228,8 @@ impl Config {
provider_record_ttl: Some(Duration::from_secs(24 * 60 * 60)),
kbucket_inserts: BucketInserts::OnConnected,
caching: Caching::Enabled { max_peers: 1 },
periodic_bootstrap_interval: Some(Duration::from_secs(5 * 60)),
automatic_bootstrap_throttle: Some(bootstrap::DEFAULT_AUTOMATIC_THROTTLE),
}
}

Expand Down Expand Up @@ -408,6 +416,34 @@ impl Config {
self.caching = c;
self
}

/// Sets the interval on which [`Behaviour::bootstrap`] is called periodically.
///
/// * Default to `5` minutes.
/// * Set to `None` to disable periodic bootstrap.
pub fn set_periodic_bootstrap_interval(&mut self, interval: Option<Duration>) -> &mut Self {
self.periodic_bootstrap_interval = interval;
self
}

/// Sets the time to wait before calling [`Behaviour::bootstrap`] after a new peer is inserted in the routing table.
/// This prevent cascading bootstrap requests when multiple peers are inserted into the routing table "at the same time".
/// This also allows to wait a little bit for other potential peers to be inserted into the routing table before
/// triggering a bootstrap, giving more context to the future bootstrap request.
///
/// * Default to `500` ms.
/// * Set to `Some(Duration::ZERO)` to never wait before triggering a bootstrap request when a new peer
/// is inserted in the routing table.
/// * Set to `None` to disable automatic bootstrap (no bootstrap request will be triggered when a new
/// peer is inserted in the routing table).
#[cfg(test)]
pub(crate) fn set_automatic_bootstrap_throttle(
&mut self,
duration: Option<Duration>,
) -> &mut Self {
self.automatic_bootstrap_throttle = duration;
self
}
}

impl<TStore> Behaviour<TStore>
Expand Down Expand Up @@ -465,6 +501,10 @@ where
mode: Mode::Client,
auto_mode: true,
no_events_waker: None,
bootstrap_status: bootstrap::Status::new(
config.periodic_bootstrap_interval,
config.automatic_bootstrap_throttle,
),
}
}

Expand Down Expand Up @@ -566,6 +606,7 @@ where
};
match entry.insert(addresses.clone(), status) {
kbucket::InsertResult::Inserted => {
self.bootstrap_status.on_new_peer_in_routing_table();
self.queued_events.push_back(ToSwarm::GenerateEvent(
Event::RoutingUpdated {
peer: *peer,
Expand Down Expand Up @@ -884,6 +925,13 @@ where
///
/// > **Note**: Bootstrapping requires at least one node of the DHT to be known.
/// > See [`Behaviour::add_address`].
///
/// > **Note**: Bootstrap does not require to be called manually. It is periodically
/// invoked at regular intervals based on the configured `periodic_bootstrap_interval` (see
/// [`Config::set_periodic_bootstrap_interval`] for details) and it is also automatically invoked
/// when a new peer is inserted in the routing table.
/// This parameter is used to call [`Behaviour::bootstrap`] periodically and automatically
/// to ensure a healthy routing table.
pub fn bootstrap(&mut self) -> Result<QueryId, NoKnownPeers> {
let local_key = self.kbuckets.local_key().clone();
let info = QueryInfo::Bootstrap {
Expand All @@ -895,6 +943,7 @@ where
if peers.is_empty() {
Err(NoKnownPeers())
} else {
self.bootstrap_status.on_started();
let inner = QueryInner::new(info);
Ok(self.queries.add_iter_closest(local_key, peers, inner))
}
Expand Down Expand Up @@ -1291,6 +1340,7 @@ where
let addresses = Addresses::new(a);
match entry.insert(addresses.clone(), new_status) {
kbucket::InsertResult::Inserted => {
self.bootstrap_status.on_new_peer_in_routing_table();
let event = Event::RoutingUpdated {
peer,
is_new_peer: true,
Expand Down Expand Up @@ -1406,6 +1456,7 @@ where
.continue_iter_closest(query_id, target.clone(), peers, inner);
} else {
step.last = true;
self.bootstrap_status.on_finish();
};

Some(Event::OutboundQueryProgressed {
Expand Down Expand Up @@ -1608,6 +1659,7 @@ where
.continue_iter_closest(query_id, target.clone(), peers, inner);
} else {
step.last = true;
self.bootstrap_status.on_finish();
}

Some(Event::OutboundQueryProgressed {
Expand Down Expand Up @@ -2480,6 +2532,13 @@ where
self.put_record_job = Some(job);
}

// Poll bootstrap periodically and automatically.
if let Poll::Ready(()) = self.bootstrap_status.poll_next_bootstrap(cx) {
if let Err(e) = self.bootstrap() {
tracing::warn!("Failed to trigger bootstrap: {e}");
}
}

loop {
// Drain queued events first.
if let Some(event) = self.queued_events.pop_front() {
Expand Down
18 changes: 17 additions & 1 deletion protocols/kad/src/behaviour/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,9 @@ fn bootstrap() {
let num_group = rng.gen_range(1..(num_total % K_VALUE.get()) + 2);

let mut cfg = Config::new(PROTOCOL_NAME);
// Disabling periodic bootstrap and automatic bootstrap to prevent the bootstrap from triggering automatically.
cfg.set_periodic_bootstrap_interval(None);
cfg.set_automatic_bootstrap_throttle(None);
if rng.gen() {
cfg.disjoint_query_paths(true);
}
Expand Down Expand Up @@ -252,7 +255,11 @@ fn query_iter() {

fn run(rng: &mut impl Rng) {
let num_total = rng.gen_range(2..20);
let mut swarms = build_connected_nodes(num_total, 1)
let mut config = Config::new(PROTOCOL_NAME);
// Disabling periodic bootstrap and automatic bootstrap to prevent the bootstrap from triggering automatically.
config.set_periodic_bootstrap_interval(None);
config.set_automatic_bootstrap_throttle(None);
let mut swarms = build_connected_nodes_with_config(num_total, 1, config)
.into_iter()
.map(|(_a, s)| s)
.collect::<Vec<_>>();
Expand Down Expand Up @@ -500,6 +507,9 @@ fn put_record() {

let mut config = Config::new(PROTOCOL_NAME);
config.set_replication_factor(replication_factor);
// Disabling periodic bootstrap and automatic bootstrap to prevent the bootstrap from triggering automatically.
config.set_periodic_bootstrap_interval(None);
config.set_automatic_bootstrap_throttle(None);
if rng.gen() {
config.disjoint_query_paths(true);
}
Expand Down Expand Up @@ -869,6 +879,9 @@ fn add_provider() {

let mut config = Config::new(PROTOCOL_NAME);
config.set_replication_factor(replication_factor);
// Disabling periodic bootstrap and automatic bootstrap to prevent the bootstrap from triggering automatically.
config.set_periodic_bootstrap_interval(None);
config.set_automatic_bootstrap_throttle(None);
if rng.gen() {
config.disjoint_query_paths(true);
}
Expand Down Expand Up @@ -1094,6 +1107,9 @@ fn disjoint_query_does_not_finish_before_all_paths_did() {
config.disjoint_query_paths(true);
// I.e. setting the amount disjoint paths to be explored to 2.
config.set_parallelism(NonZeroUsize::new(2).unwrap());
// Disabling periodic bootstrap and automatic bootstrap to prevent the bootstrap from triggering automatically.
config.set_periodic_bootstrap_interval(None);
config.set_automatic_bootstrap_throttle(None);

let mut alice = build_node_with_config(config);
let mut trudy = build_node(); // Trudy the intrudor, an adversary.
Expand Down
Loading
Loading