Skip to content

Commit

Permalink
Merge pull request #1 from ackintosh/two-sockets-ackintosh
Browse files Browse the repository at this point in the history
Two sockets
  • Loading branch information
divagant-martian authored Mar 28, 2023
2 parents cb42618 + 5cd9409 commit e418016
Show file tree
Hide file tree
Showing 18 changed files with 575 additions and 177 deletions.
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

0 comments on commit e418016

Please sign in to comment.