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

Two sockets #1

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
14 changes: 9 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,9 @@ A simple example of creating this service is as follows:

```rust
use discv5::{enr, enr::{CombinedKey, NodeId}, TokioExecutor, Discv5, Discv5ConfigBuilder};
use discv5::socket::ListenConfig;
use std::net::SocketAddr;

// listening address and port
let listen_addr = "0.0.0.0:9000".parse::<SocketAddr>().unwrap();

// construct a local ENR
let enr_key = CombinedKey::generate_secp256k1();
let enr = enr::EnrBuilder::new("v4").build(&enr_key).unwrap();
Expand All @@ -57,15 +55,21 @@ A simple example of creating this service is as follows:
// default configuration
let config = Discv5ConfigBuilder::new().build();

// configuration for the sockets to listen on
let listen_config = ListenConfig::Ipv4 {
ip: Ipv4Addr::UNSPECIFIED,
port: 9000,
};

// construct the discv5 server
let mut discv5 = Discv5::new(enr, enr_key, config).unwrap();
let mut discv5 = Discv5::new(enr, enr_key, config, listen_config).unwrap();

// In order to bootstrap the routing table an external ENR should be added
// This can be done via add_enr. I.e.:
// discv5.add_enr(<ENR>)

// start the discv5 server
runtime.block_on(discv5.start(listen_addr));
runtime.block_on(discv5.start());

// run a find_node query
runtime.block_on(async {
Expand Down
15 changes: 10 additions & 5 deletions examples/custom_executor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@
//! $ cargo run --example custom_executor <BASE64ENR>
//! ```

use discv5::{enr, enr::CombinedKey, Discv5, Discv5ConfigBuilder, Discv5Event};
use std::net::SocketAddr;
use discv5::{
enr, enr::CombinedKey, socket::ListenConfig, Discv5, Discv5ConfigBuilder, Discv5Event,
};
use std::net::Ipv4Addr;

fn main() {
// allows detailed logging with the RUST_LOG env variable
Expand All @@ -22,7 +24,10 @@ fn main() {
.try_init();

// listening address and port
let listen_addr = "0.0.0.0:9000".parse::<SocketAddr>().unwrap();
let listen_config = ListenConfig::Ipv4 {
ip: Ipv4Addr::UNSPECIFIED,
port: 9000,
};

let enr_key = CombinedKey::generate_secp256k1();
// construct a local ENR
Expand All @@ -39,7 +44,7 @@ fn main() {
let config = Discv5ConfigBuilder::new().build();

// construct the discv5 server
let mut discv5 = Discv5::new(enr, enr_key, config).unwrap();
let mut discv5 = Discv5::new(enr, enr_key, config, listen_config).unwrap();

// if we know of another peer's ENR, add it known peers
if let Some(base64_enr) = std::env::args().nth(1) {
Expand All @@ -61,7 +66,7 @@ fn main() {

runtime.block_on(async {
// start the discv5 service
discv5.start(listen_addr).await.unwrap();
discv5.start().await.unwrap();
println!("Server started");

// get an event stream
Expand Down
57 changes: 34 additions & 23 deletions examples/find_nodes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,18 +19,18 @@ use clap::Parser;
use discv5::{
enr,
enr::{k256, CombinedKey},
socket::ListenConfig,
Discv5, Discv5ConfigBuilder, Discv5Event,
};
use std::{
net::{Ipv4Addr, Ipv6Addr, SocketAddr},
net::{Ipv4Addr, Ipv6Addr},
time::Duration,
};
use tracing::{info, warn};

#[derive(Parser)]
struct FindNodesArgs {
/// Type of socket to bind ['ds', 'ip4', 'ip6']. The dual stack option will enable mapped
/// addresses over an IpV6 socket.
/// Type of socket to bind ['ds', 'ip4', 'ip6'].
#[clap(long, default_value_t = SocketKind::Ds)]
socket_kind: SocketKind,
/// IpV4 to advertise in the ENR. This is needed so that other IpV4 nodes can connect to us.
Expand All @@ -43,6 +43,10 @@ struct FindNodesArgs {
/// randomly.
#[clap(long)]
port: Option<u16>,
/// Port to bind for ipv6. If none is provided, a random one in the 9000 - 9999 range will be picked
/// randomly.
#[clap(long)]
port6: Option<u16>,
/// Use a default test key.
#[clap(long)]
use_test_key: bool,
Expand All @@ -67,6 +71,12 @@ async fn main() {
let port = args
.port
.unwrap_or_else(|| (rand::random::<u16>() % 1000) + 9000);
let port6 = args.port.unwrap_or_else(|| loop {
let port6 = (rand::random::<u16>() % 1000) + 9000;
if port6 != port {
return port6;
}
});

let enr_key = if args.use_test_key {
// A fixed key for testing
Expand All @@ -93,9 +103,9 @@ async fn main() {
if let Some(ip6) = args.enr_ip6 {
// if the given address is the UNSPECIFIED address we want to advertise localhost
if ip6.is_unspecified() {
builder.ip6(Ipv6Addr::LOCALHOST).udp6(port);
builder.ip6(Ipv6Addr::LOCALHOST).udp6(port6);
} else {
builder.ip6(ip6).udp6(port);
builder.ip6(ip6).udp6(port6);
}
}
builder.build(&enr_key).unwrap()
Expand All @@ -105,17 +115,7 @@ async fn main() {
// let config = Discv5ConfigBuilder::new().enable_packet_filter().build();

// default configuration without packet filtering
let config = Discv5ConfigBuilder::new()
.ip_mode(match args.socket_kind {
SocketKind::Ip4 => discv5::IpMode::Ip4,
SocketKind::Ip6 => discv5::IpMode::Ip6 {
enable_mapped_addresses: false,
},
SocketKind::Ds => discv5::IpMode::Ip6 {
enable_mapped_addresses: true,
},
})
.build();
let config = Discv5ConfigBuilder::new().build();

info!("Node Id: {}", enr.node_id());
if args.enr_ip6.is_some() || args.enr_ip4.is_some() {
Expand All @@ -128,14 +128,25 @@ async fn main() {
);
}
// the address to listen on.
let bind_addr = match args.socket_kind {
SocketKind::Ip4 => Ipv4Addr::UNSPECIFIED.into(),
SocketKind::Ip6 | SocketKind::Ds => Ipv6Addr::UNSPECIFIED.into(),
let listen_config = match args.socket_kind {
SocketKind::Ip4 => ListenConfig::Ipv4 {
ip: Ipv4Addr::UNSPECIFIED,
port,
},
SocketKind::Ip6 => ListenConfig::Ipv6 {
ip: Ipv6Addr::UNSPECIFIED,
port: port6,
},
SocketKind::Ds => ListenConfig::DualStack {
ipv4: Ipv4Addr::UNSPECIFIED,
ipv4_port: port,
ipv6: Ipv6Addr::UNSPECIFIED,
ipv6_port: port6,
},
};
let socket_addr = SocketAddr::new(bind_addr, port);

// construct the discv5 server
let mut discv5 = Discv5::new(enr, enr_key, config).unwrap();
let mut discv5 = Discv5::new(enr, enr_key, config, listen_config).unwrap();

// if we know of another peer's ENR, add it known peers
for enr in args.remote_peer {
Expand All @@ -154,12 +165,12 @@ async fn main() {
}

// start the discv5 service
discv5.start(socket_addr).await.unwrap();
discv5.start().await.unwrap();
let mut event_stream = discv5.event_stream().await.unwrap();
let check_evs = args.events;

// construct a 30 second interval to search for new peers.
let mut query_interval = tokio::time::interval(Duration::from_secs(30));
let mut query_interval = tokio::time::interval(Duration::from_secs(1));

loop {
tokio::select! {
Expand Down
14 changes: 9 additions & 5 deletions examples/request_enr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,10 @@
//!
//! This requires the "libp2p" feature.
#[cfg(feature = "libp2p")]
use discv5::{enr, enr::CombinedKey, Discv5, Discv5Config};
use discv5::socket::ListenConfig;
#[cfg(feature = "libp2p")]
use std::net::SocketAddr;
use discv5::{enr, enr::CombinedKey, Discv5, Discv5Config};
use std::net::Ipv4Addr;

#[cfg(not(feature = "libp2p"))]
fn main() {}
Expand All @@ -31,7 +32,10 @@ async fn main() {
.try_init();

// listening address and port
let listen_addr = "0.0.0.0:9000".parse::<SocketAddr>().unwrap();
let listen_config = ListenConfig::Ipv4 {
ip: Ipv4Addr::UNSPECIFIED,
port: 9000,
};

// generate a new enr key
let enr_key = CombinedKey::generate_secp256k1();
Expand All @@ -46,10 +50,10 @@ async fn main() {
.expect("A multiaddr must be supplied");

// construct the discv5 server
let mut discv5 = Discv5::new(enr, enr_key, config).unwrap();
let mut discv5 = Discv5::new(enr, enr_key, config, listen_config).unwrap();

// start the discv5 service
discv5.start(listen_addr).await.unwrap();
discv5.start().await.unwrap();

// search for the ENR
match discv5.request_enr(multiaddr).await {
Expand Down
13 changes: 8 additions & 5 deletions examples/simple_server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@
//! $ cargo run --example simple_server -- <ENR-IP> <ENR-PORT> <BASE64ENR>
//! ```

use discv5::{enr, enr::CombinedKey, Discv5, Discv5Config, Discv5Event};
use std::net::{Ipv4Addr, SocketAddr};
use discv5::{enr, enr::CombinedKey, socket::ListenConfig, Discv5, Discv5Config, Discv5Event};
use std::net::Ipv4Addr;

#[tokio::main]
async fn main() {
Expand All @@ -37,7 +37,10 @@ async fn main() {
};

// listening address and port
let listen_addr = "0.0.0.0:9000".parse::<SocketAddr>().unwrap();
let listen_config = ListenConfig::Ipv4 {
ip: Ipv4Addr::UNSPECIFIED,
port: 9000,
};

let enr_key = CombinedKey::generate_secp256k1();

Expand Down Expand Up @@ -72,7 +75,7 @@ async fn main() {
let config = Discv5Config::default();

// construct the discv5 server
let mut discv5 = Discv5::new(enr, enr_key, config).unwrap();
let mut discv5 = Discv5::new(enr, enr_key, config, listen_config).unwrap();

// if we know of another peer's ENR, add it known peers
if let Some(base64_enr) = std::env::args().nth(3) {
Expand All @@ -93,7 +96,7 @@ async fn main() {
}

// start the discv5 service
discv5.start(listen_addr).await.unwrap();
discv5.start().await.unwrap();
println!("Server started");

// get an event stream
Expand Down
10 changes: 1 addition & 9 deletions src/config.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
use crate::{
ipmode::IpMode, kbucket::MAX_NODES_PER_BUCKET, Enr, Executor, PermitBanList, RateLimiter,
RateLimiterBuilder,
kbucket::MAX_NODES_PER_BUCKET, Enr, Executor, PermitBanList, RateLimiter, RateLimiterBuilder,
};
///! A set of configuration parameters to tune the discovery protocol.
use std::time::Duration;
Expand Down Expand Up @@ -302,13 +301,6 @@ impl Discv5ConfigBuilder {
self
}

/// Configures the type of socket to bind to. This also affects the selection of address to use
/// to contact an ENR.
pub fn ip_mode(&mut self, ip_mode: IpMode) -> &mut Self {
self.config.ip_mode = ip_mode;
self
}

pub fn build(&mut self) -> Discv5Config {
// If an executor is not provided, assume a current tokio runtime is running.
if self.config.executor.is_none() {
Expand Down
22 changes: 17 additions & 5 deletions src/discv5.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ use crate::{
},
node_info::NodeContact,
service::{QueryKind, Service, ServiceRequest, TalkRequest},
Discv5Config, Enr,
Discv5Config, Enr, IpMode,
};
use enr::{CombinedKey, EnrError, EnrKey, NodeId};
use parking_lot::RwLock;
Expand All @@ -37,7 +37,10 @@ use tracing::{debug, warn};
use libp2p_core::Multiaddr;

// Create lazy static variable for the global permit/ban list
use crate::metrics::{Metrics, METRICS};
use crate::{
metrics::{Metrics, METRICS},
socket::ListenConfig,
};
lazy_static! {
pub static ref PERMIT_BAN_LIST: RwLock<crate::PermitBanList> =
RwLock::new(crate::PermitBanList::default());
Expand Down Expand Up @@ -83,13 +86,18 @@ pub struct Discv5 {
local_enr: Arc<RwLock<Enr>>,
/// The key associated with the local ENR, required for updating the local ENR.
enr_key: Arc<RwLock<CombinedKey>>,
/// Type of socket to create.
listen_config: ListenConfig,
// Type of socket we are using
ip_mode: IpMode,
}

impl Discv5 {
pub fn new(
local_enr: Enr,
enr_key: CombinedKey,
mut config: Discv5Config,
listen_config: ListenConfig,
) -> Result<Self, &'static str> {
// ensure the keypair matches the one that signed the enr.
if local_enr.public_key() != enr_key.public() {
Expand Down Expand Up @@ -126,13 +134,17 @@ impl Discv5 {
// Update the PermitBan list based on initial configuration
*PERMIT_BAN_LIST.write() = config.permit_ban_list.clone();

let ip_mode = IpMode::new_from_listen_config(&listen_config);

Ok(Discv5 {
config,
service_channel: None,
service_exit: None,
kbuckets,
local_enr,
enr_key,
listen_config,
ip_mode,
})
}

Expand All @@ -149,7 +161,7 @@ impl Discv5 {
self.enr_key.clone(),
self.kbuckets.clone(),
self.config.clone(),
listen_socket,
self.listen_config.clone(),
)
.await?;
self.service_exit = Some(service_exit);
Expand Down Expand Up @@ -178,7 +190,7 @@ impl Discv5 {
/// them upfront.
pub fn add_enr(&self, enr: Enr) -> Result<(), &'static str> {
// only add ENR's that have a valid udp socket.
if self.config.ip_mode.get_contactable_addr(&enr).is_none() {
if self.ip_mode.get_contactable_addr(&enr).is_none() {
warn!("ENR attempted to be added without an UDP socket compatible with configured IpMode has been ignored.");
return Err("ENR has no compatible UDP socket to connect to");
}
Expand Down Expand Up @@ -474,7 +486,7 @@ impl Discv5 {

let (callback_send, callback_recv) = oneshot::channel();
let channel = self.clone_channel();
let ip_mode = self.config.ip_mode;
let ip_mode = self.ip_mode;

async move {
let node_contact = NodeContact::try_from_enr(enr, ip_mode)?;
Expand Down
Loading