Skip to content

Commit

Permalink
feat: add discovery domain
Browse files Browse the repository at this point in the history
  • Loading branch information
zsluedem committed Jul 28, 2023
1 parent 7afddf2 commit 3ff0a38
Show file tree
Hide file tree
Showing 13 changed files with 975 additions and 493 deletions.
444 changes: 375 additions & 69 deletions Cargo.lock

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions crates/p2p/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@ ethereum_ssz_derive = "0.5.0"
snap = "1"
silius-primitives = { path = "../primitives" }
silius-uopool = {path = "../uopool"}

discv5 = {version = "0.3.0", features = ["libp2p"]}
tokio = { workspace = true }

[dependencies.libp2p]
version = "0.51.3"
default-features = false
features = [ "identify", "mplex", "yamux", "noise", "gossipsub", "dns", "tcp", "tokio", "secp256k1", "macros", "request-response"]
41 changes: 38 additions & 3 deletions crates/p2p/src/behaviour.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
use crate::config::Config;
use crate::discovery::{self, Discovery};
use crate::enr::{build_enr, CombineKeyPubExt};
use crate::gossipsub::Gossipsub;
use crate::reqrep::reqrep::{BundlerRequestResponse, Request, Response};
use crate::reqrep::protocol::SUPPORTED_PROTOCOL;
use crate::reqrep::{BundlerCodec, BundlerRequestResponse, Request, Response};
use discv5::enr::CombinedKey;
use libp2p::gossipsub;
use libp2p::request_response;
use libp2p::swarm::NetworkBehaviour;
Expand All @@ -9,11 +14,34 @@ use libp2p::swarm::NetworkBehaviour;
pub struct Behaviour {
gossipsub: Gossipsub,
reqrep: BundlerRequestResponse,
discv5: Discovery,
}

impl Behaviour {
pub fn new(key: CombinedKey, config: Config) -> anyhow::Result<Self> {
let enr = build_enr(&key, &config)?;
let gossipsub = Gossipsub::new(
gossipsub::MessageAuthenticity::Author(enr.public_key().to_peer_id()?),
gossipsub::Config::default(),
)
.map_err(|e| anyhow::anyhow!(e))?;
let reqrep = BundlerRequestResponse::new(
BundlerCodec {},
SUPPORTED_PROTOCOL.clone().into_iter(),
request_response::Config::default(),
);
let discovery = Discovery::new(enr, key, config)?;
Ok(Self {
gossipsub,
reqrep,
discv5: discovery,
})
}
}

impl From<gossipsub::Event> for Event {
fn from(value: gossipsub::Event) -> Self {
Event::GossipSub(value)
Event::GossipSub(Box::new(value))
}
}

Expand All @@ -23,8 +51,15 @@ impl From<request_response::Event<Request, Response>> for Event {
}
}

impl From<discovery::Event> for Event {
fn from(_value: discovery::Event) -> Self {
Event::Discovery(discovery::Event::Nothing)
}
}

#[derive(Debug)]
pub enum Event {
GossipSub(gossipsub::Event),
GossipSub(Box<gossipsub::Event>),
Reqrep(request_response::Event<Request, Response>),
Discovery(discovery::Event),
}
60 changes: 60 additions & 0 deletions crates/p2p/src/config.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
use std::net::{Ipv4Addr, Ipv6Addr};

use discv5::ListenConfig;

const DEFAULT_UDP_PORT: u16 = 9000;

pub struct Config {
/// The ipv4 address to broadcast to peers about which address we are listening on.
pub ipv4_addr: Option<Ipv4Addr>,

/// The ipv6 address to broadcast to peers about which address we are listening on.
pub ipv6_addr: Option<Ipv6Addr>,

/// The udp4 port to broadcast to peers in order to reach back for discovery.
pub enr_udp4_port: Option<u16>,

/// The tcp4 port to broadcast to peers in order to reach back for libp2p services.
pub enr_tcp4_port: Option<u16>,

/// The udp6 port to broadcast to peers in order to reach back for discovery.
pub enr_udp6_port: Option<u16>,

/// The tcp6 port to broadcast to peers in order to reach back for libp2p services.
pub enr_tcp6_port: Option<u16>,
}

impl Default for Config {
fn default() -> Self {
Self {
ipv4_addr: Some(Ipv4Addr::UNSPECIFIED),
ipv6_addr: None,
enr_udp4_port: Some(DEFAULT_UDP_PORT),
enr_tcp4_port: None,
enr_udp6_port: None,
enr_tcp6_port: None,
}
}
}

impl Config {
pub fn to_listen_config(&self) -> ListenConfig {
match (self.ipv4_addr, self.ipv6_addr) {
(None, None) => todo!(),
(None, Some(ip)) => ListenConfig::Ipv6 {
ip,
port: self.enr_udp6_port.unwrap_or(DEFAULT_UDP_PORT),
},
(Some(ip), None) => ListenConfig::Ipv4 {
ip,
port: self.enr_udp4_port.unwrap_or(DEFAULT_UDP_PORT),
},
(Some(ipv4), Some(ipv6)) => ListenConfig::DualStack {
ipv4,
ipv4_port: self.enr_udp4_port.unwrap_or(DEFAULT_UDP_PORT),
ipv6,
ipv6_port: self.enr_udp6_port.unwrap_or(DEFAULT_UDP_PORT),
},
}
}
}
52 changes: 51 additions & 1 deletion crates/p2p/src/discovery.rs
Original file line number Diff line number Diff line change
@@ -1 +1,51 @@
pub struct Discovery {}
use std::task::Poll;

use discv5::{enr::CombinedKey, Discv5, Discv5ConfigBuilder, Enr};
use libp2p::swarm::{dummy::ConnectionHandler, NetworkBehaviour};

use crate::config::Config;

pub struct Discovery {
pub discovery: Discv5,
}

impl Discovery {
pub fn new(enr: Enr, key: CombinedKey, config: Config) -> anyhow::Result<Self> {
let config = Discv5ConfigBuilder::new(config.to_listen_config()).build();
let discovery: Discv5<_> = Discv5::new(enr, key, config).map_err(|e| anyhow::anyhow!(e))?;
Ok(Self { discovery })
}
}

#[derive(Debug)]
pub enum Event {
Nothing,
}

impl NetworkBehaviour for Discovery {
type ConnectionHandler = ConnectionHandler;
type OutEvent = Event;
fn new_handler(&mut self) -> Self::ConnectionHandler {
ConnectionHandler
}

fn addresses_of_peer(&mut self, _: &libp2p::PeerId) -> Vec<libp2p::Multiaddr> {
todo!()
}
fn poll(
&mut self,
_cx: &mut std::task::Context<'_>,
_params: &mut impl libp2p::swarm::PollParameters,
) -> Poll<libp2p::swarm::ToSwarm<Self::OutEvent, libp2p::swarm::THandlerInEvent<Self>>> {
Poll::Pending
}
fn on_swarm_event(&mut self, _event: libp2p::swarm::FromSwarm<Self::ConnectionHandler>) {}

fn on_connection_handler_event(
&mut self,
_peer_id: libp2p::PeerId,
_connection_id: libp2p::swarm::ConnectionId,
_event: libp2p::swarm::THandlerOutEvent<Self>,
) {
}
}
68 changes: 68 additions & 0 deletions crates/p2p/src/enr.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
use discv5::{
enr::{
k256::{ecdsa::VerifyingKey, CompressedPoint},
CombinedKey, CombinedPublicKey, EnrBuilder,
},
Enr,
};
use libp2p::{
identity::{secp256k1, Keypair, PublicKey},
PeerId,
};

use crate::config::Config;

pub fn keypair_to_combine(keypair: Keypair) -> anyhow::Result<CombinedKey> {
match keypair.try_into_secp256k1() {
Ok(key) => {
let secret =
discv5::enr::k256::ecdsa::SigningKey::from_bytes(&key.secret().to_bytes().into())
.expect("libp2p key must be valid");
Ok(CombinedKey::Secp256k1(secret))
}
Err(_) => anyhow::bail!("libp2p key must be either secp256k1"),
}
}

pub fn build_enr(enr_key: &CombinedKey, config: &Config) -> anyhow::Result<Enr> {
let mut enr_builder = EnrBuilder::new("v4");
if let Some(ip) = config.ipv4_addr {
enr_builder.ip4(ip);
}
if let Some(ip) = config.ipv6_addr {
enr_builder.ip6(ip);
}
if let Some(port) = config.enr_tcp4_port {
enr_builder.tcp4(port);
}
if let Some(port) = config.enr_tcp6_port {
enr_builder.tcp6(port);
}
if let Some(port) = config.enr_udp4_port {
enr_builder.udp4(port);
}
if let Some(port) = config.enr_udp6_port {
enr_builder.udp6(port);
}

let enr = enr_builder.build(enr_key)?;
Ok(enr)
}

pub trait CombineKeyPubExt {
fn to_peer_id(&self) -> anyhow::Result<PeerId>;
}

impl CombineKeyPubExt for CombinedPublicKey {
fn to_peer_id(&self) -> anyhow::Result<PeerId> {
let pub_key: PublicKey = match self {
CombinedPublicKey::Secp256k1(pk) => {
PublicKey::from(secp256k1::PublicKey::try_from_bytes(
<&VerifyingKey as Into<CompressedPoint>>::into(pk).as_slice(),
)?)
}
_ => anyhow::bail!("Only secp256k1 is supported"),
};
Ok(PeerId::from_public_key(&pub_key))
}
}
7 changes: 7 additions & 0 deletions crates/p2p/src/gossipsub.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,13 @@ impl SnappyTransform {
}
}
}
impl Default for SnappyTransform {
fn default() -> Self {
SnappyTransform {
max_size_per_message: MAX_GOSSIP_SNAP_SIZE,
}
}
}

impl DataTransform for SnappyTransform {
// Provides the snappy decompression from RawGossipsubMessages
Expand Down
25 changes: 24 additions & 1 deletion crates/p2p/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,41 @@
use std::time::Duration;

use behaviour::Behaviour;
use enr::keypair_to_combine;
use enr::CombineKeyPubExt;
use libp2p::core::muxing::StreamMuxerBox;
use libp2p::core::transport::Boxed;
use libp2p::identity::Keypair;
use libp2p::noise;
use libp2p::swarm::SwarmBuilder;
use libp2p::PeerId;
use libp2p::Swarm;
use libp2p::{core, Transport};

pub mod behaviour;
pub mod config;
pub mod discovery;
pub mod enr;
pub mod gossipsub;
pub mod reqrep;

pub fn setup() -> () {}
struct TokioExecutor;
impl libp2p::swarm::Executor for TokioExecutor {
fn exec(&self, future: std::pin::Pin<Box<dyn std::future::Future<Output = ()> + Send>>) {
tokio::spawn(future);
}
}

pub fn setup(private_key: Keypair) -> anyhow::Result<Swarm<behaviour::Behaviour>> {
let transport = build_transport(private_key.clone())?;
let combine_key = keypair_to_combine(private_key)?;
let config = config::Config::default();
let enr = enr::build_enr(&combine_key, &config)?;
let behaviour = Behaviour::new(combine_key, config)?;
let peer_id = enr.public_key().to_peer_id()?;

Ok(SwarmBuilder::with_executor(transport, behaviour, peer_id, TokioExecutor).build())
}

pub fn build_transport(private_key: Keypair) -> std::io::Result<Boxed<(PeerId, StreamMuxerBox)>> {
let tcp = libp2p::tcp::tokio::Transport::new(libp2p::tcp::Config::default().nodelay(true));
Expand Down
Loading

0 comments on commit 3ff0a38

Please sign in to comment.