From e7e8b661eee845e4db62f4d077744478b33ecc5f Mon Sep 17 00:00:00 2001 From: Chen Kai <281165273grape@gmail.com> Date: Wed, 28 Aug 2024 21:40:30 +0800 Subject: [PATCH 1/2] feat:add listen config for network and disc builder Signed-off-by: Chen Kai <281165273grape@gmail.com> --- crates/net/src/builder.rs | 39 ++++++++++++++++++++++++----- crates/net/src/discovery/builder.rs | 14 +++++++++-- 2 files changed, 45 insertions(+), 8 deletions(-) diff --git a/crates/net/src/builder.rs b/crates/net/src/builder.rs index ff90911..50bde93 100644 --- a/crates/net/src/builder.rs +++ b/crates/net/src/builder.rs @@ -3,6 +3,8 @@ use alloy::primitives::Address; use eyre::Result; use std::net::{IpAddr, SocketAddr}; +use discv5::ListenConfig; +use discv5::ListenConfig::{DualStack, Ipv4, Ipv6}; use tokio::sync::watch::channel; use libp2p::{ @@ -26,6 +28,8 @@ pub struct NetworkDriverBuilder { pub unsafe_block_signer: Option
, /// The socket address that the service is listening on. pub socket: Option, + /// The listen config that the service is listening on. + pub listen_config: Option, /// The [GossipConfig] constructs the config for `gossipsub`. pub gossip_config: Option, /// The [Keypair] for the node. @@ -62,6 +66,12 @@ impl NetworkDriverBuilder { self } + /// Specifies the listen config that the service is listening on. + pub fn with_listen_config(&mut self, listen_config: ListenConfig) -> &mut Self { + self.listen_config = Some(listen_config); + self + } + /// Specifies the keypair for the node. pub fn with_keypair(&mut self, keypair: Keypair) -> &mut Self { self.keypair = Some(keypair); @@ -126,7 +136,10 @@ impl NetworkDriverBuilder { /// Returns an error if any of the following required fields are not set: /// - [NetworkDriverBuilder::unsafe_block_signer] /// - [NetworkDriverBuilder::chain_id] + /// + /// Returns an error if neither of the following required fields are set: /// - [NetworkDriverBuilder::socket] + /// - [NetworkDriverBuilder::listen_config] /// /// Set these fields using the respective methods on the [NetworkDriverBuilder] /// before calling this method. @@ -179,18 +192,32 @@ impl NetworkDriverBuilder { )? .with_behaviour(|_| behaviour)? .build(); - let socket = self.socket.take().ok_or(eyre::eyre!("socket address not set"))?; + let listen_config = self.listen_config.take().ok_or_else(|| { + let addr = self.socket.ok_or_else(|| eyre::eyre!("address not set"))?; + Ok(ListenConfig::from_ip(addr.ip(), addr.port())) + })?; let mut multiaddr = Multiaddr::empty(); - match socket.ip() { - IpAddr::V4(ip) => multiaddr.push(Protocol::Ip4(ip)), - IpAddr::V6(ip) => multiaddr.push(Protocol::Ip6(ip)), + match listen_config { + Ipv4 { ip: addr, port } => { + multiaddr.push(Protocol::Ip4(addr)); + multiaddr.push(Protocol::Tcp(port)); + } + Ipv6 { ip: addr, port } => { + multiaddr.push(Protocol::Ip6(addr)); + multiaddr.push(Protocol::Tcp(port)); + } + DualStack { ipv4: v4addr, ipv4_port: v4port, ipv6: v6addr, ipv6_port: v6port, .. } => { + multiaddr.push(Protocol::Ip4(v4addr)); + multiaddr.push(Protocol::Tcp(v4port)); + multiaddr.push(Protocol::Ip6(v6addr)); + multiaddr.push(Protocol::Tcp(v6port)); + } } - multiaddr.push(Protocol::Tcp(socket.port())); let gossip = GossipDriver::new(swarm, multiaddr, handler); // Build the discovery service let discovery = - DiscoveryBuilder::new().with_address(socket).with_chain_id(chain_id).build()?; + DiscoveryBuilder::new().with_listen_config(listen_config).with_chain_id(chain_id).build()?; Ok(NetworkDriver { unsafe_block_recv, unsafe_block_signer_sender, gossip, discovery }) } diff --git a/crates/net/src/discovery/builder.rs b/crates/net/src/discovery/builder.rs index 1a092b4..7a408bb 100644 --- a/crates/net/src/discovery/builder.rs +++ b/crates/net/src/discovery/builder.rs @@ -17,6 +17,8 @@ pub struct DiscoveryBuilder { address: Option, /// The chain ID of the network. chain_id: Option, + /// The listen config for the discovery service. + listen_config: Option, } impl DiscoveryBuilder { @@ -37,9 +39,14 @@ impl DiscoveryBuilder { self } + /// Sets the listen config for the discovery service. + pub fn with_listen_config(mut self, listen_config: ListenConfig) -> Self { + self.listen_config = Some(listen_config); + self + } + /// Builds a [DiscoveryDriver]. pub fn build(&mut self) -> Result { - let addr = self.address.ok_or_else(|| eyre::eyre!("address not set"))?; let chain_id = self.chain_id.ok_or_else(|| eyre::eyre!("chain ID not set"))?; let opstack = OpStackEnr::new(chain_id, 0); let mut opstack_data = Vec::new(); @@ -48,7 +55,10 @@ impl DiscoveryBuilder { let key = CombinedKey::generate_secp256k1(); let enr = Enr::builder().add_value_rlp(OP_CL_KEY, opstack_data.into()).build(&key)?; - let listen_config = ListenConfig::from_ip(addr.ip(), addr.port()); + let listen_config = self.listen_config.take().unwrap_or_else(|| { + let addr = self.address.expect("address not set"); + ListenConfig::from_ip(addr.ip(), addr.port()) + }); let config = ConfigBuilder::new(listen_config).build(); let disc = Discv5::new(enr, key, config) From ceda34a4098698f1dfbfb5a3ed49433ccb6d1854 Mon Sep 17 00:00:00 2001 From: Chen Kai <281165273grape@gmail.com> Date: Thu, 29 Aug 2024 13:15:32 +0800 Subject: [PATCH 2/2] feat:use listen config in network driver Signed-off-by: Chen Kai <281165273grape@gmail.com> --- crates/net/README.md | 2 +- crates/net/src/builder.rs | 110 +++++++++++++++++----------- crates/net/src/discovery/builder.rs | 29 ++++++-- 3 files changed, 92 insertions(+), 49 deletions(-) diff --git a/crates/net/README.md b/crates/net/README.md index e484424..206c232 100644 --- a/crates/net/README.md +++ b/crates/net/README.md @@ -15,7 +15,7 @@ let socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 9099); let mut driver = NetworkDriver::builder() .with_chain_id(10) // op mainnet chain id .with_unsafe_block_signer(signer) - .with_socket(socket) + .with_gossip_addr(socket) .build() .expect("Failed to builder network driver"); diff --git a/crates/net/src/builder.rs b/crates/net/src/builder.rs index 50bde93..d049d81 100644 --- a/crates/net/src/builder.rs +++ b/crates/net/src/builder.rs @@ -1,10 +1,9 @@ //! Network Builder Module. use alloy::primitives::Address; +use discv5::ListenConfig; use eyre::Result; use std::net::{IpAddr, SocketAddr}; -use discv5::ListenConfig; -use discv5::ListenConfig::{DualStack, Ipv4, Ipv6}; use tokio::sync::watch::channel; use libp2p::{ @@ -26,10 +25,10 @@ pub struct NetworkDriverBuilder { pub chain_id: Option, /// The unsafe block signer. pub unsafe_block_signer: Option
, - /// The socket address that the service is listening on. - pub socket: Option, - /// The listen config that the service is listening on. - pub listen_config: Option, + /// The socket address that the gossip service is listening on. + pub gossip_addr: Option, + /// The listen config that the discovery service is listening on. + pub discovery_addr: Option, /// The [GossipConfig] constructs the config for `gossipsub`. pub gossip_config: Option, /// The [Keypair] for the node. @@ -60,15 +59,15 @@ impl NetworkDriverBuilder { self } - /// Specifies the socket address that the service is listening on. - pub fn with_socket(&mut self, socket: SocketAddr) -> &mut Self { - self.socket = Some(socket); + /// Specifies the socket address that the gossip service is listening on. + pub fn with_gossip_addr(&mut self, socket: SocketAddr) -> &mut Self { + self.gossip_addr = Some(socket); self } - /// Specifies the listen config that the service is listening on. - pub fn with_listen_config(&mut self, listen_config: ListenConfig) -> &mut Self { - self.listen_config = Some(listen_config); + /// Specifies the listen config that the discovery service is listening on. + pub fn with_discovery_addr(&mut self, listen_config: ListenConfig) -> &mut Self { + self.discovery_addr = Some(listen_config); self } @@ -119,7 +118,7 @@ impl NetworkDriverBuilder { /// let mut builder = NetworkDriverBuilder::new() /// .with_unsafe_block_signer(signer) /// .with_chain_id(chain_id) - /// .with_socket(socket) + /// .with_gossip_addr(socket) /// .with_gossip_config(cfg); /// .build() /// .unwrap(); @@ -136,10 +135,11 @@ impl NetworkDriverBuilder { /// Returns an error if any of the following required fields are not set: /// - [NetworkDriverBuilder::unsafe_block_signer] /// - [NetworkDriverBuilder::chain_id] + /// - [NetworkDriverBuilder::gossip_addr] /// - /// Returns an error if neither of the following required fields are set: - /// - [NetworkDriverBuilder::socket] - /// - [NetworkDriverBuilder::listen_config] + /// If explicitly set, the following fields are used for discovery address, otherwise the gossip + /// address is used: + /// - [NetworkDriverBuilder::discovery_addr] /// /// Set these fields using the respective methods on the [NetworkDriverBuilder] /// before calling this method. @@ -156,7 +156,21 @@ impl NetworkDriverBuilder { /// let driver = NetworkDriverBuilder::new() /// .with_unsafe_block_signer(signer) /// .with_chain_id(chain_id) - /// .with_socket(socket) + /// .with_gossip_addr(socket) + /// .build() + /// .unwrap(); + /// + /// Or if you want to use a different discovery address: + /// + /// let chain_id = 10; + /// let signer = Address::random(); + /// let socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 9099); + /// let listen_config = ListenConfig::from_ip(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 9999); + /// let driver = NetworkDriverBuilder::new() + /// .with_unsafe_block_signer(signer) + /// .with_chain_id(chain_id) + /// .with_gossip_addr(socket) + /// .with_discovery_addr(listen_config) /// .build() /// .unwrap(); /// ``` @@ -192,33 +206,27 @@ impl NetworkDriverBuilder { )? .with_behaviour(|_| behaviour)? .build(); - let listen_config = self.listen_config.take().ok_or_else(|| { - let addr = self.socket.ok_or_else(|| eyre::eyre!("address not set"))?; - Ok(ListenConfig::from_ip(addr.ip(), addr.port())) - })?; + + let gossip_addr = + self.gossip_addr.take().ok_or(eyre::eyre!("gossip_addr address not set"))?; let mut multiaddr = Multiaddr::empty(); - match listen_config { - Ipv4 { ip: addr, port } => { - multiaddr.push(Protocol::Ip4(addr)); - multiaddr.push(Protocol::Tcp(port)); - } - Ipv6 { ip: addr, port } => { - multiaddr.push(Protocol::Ip6(addr)); - multiaddr.push(Protocol::Tcp(port)); - } - DualStack { ipv4: v4addr, ipv4_port: v4port, ipv6: v6addr, ipv6_port: v6port, .. } => { - multiaddr.push(Protocol::Ip4(v4addr)); - multiaddr.push(Protocol::Tcp(v4port)); - multiaddr.push(Protocol::Ip6(v6addr)); - multiaddr.push(Protocol::Tcp(v6port)); - } + match gossip_addr.ip() { + IpAddr::V4(ip) => multiaddr.push(Protocol::Ip4(ip)), + IpAddr::V6(ip) => multiaddr.push(Protocol::Ip6(ip)), } - let gossip = GossipDriver::new(swarm, multiaddr, handler); + multiaddr.push(Protocol::Tcp(gossip_addr.port())); + let gossip = GossipDriver::new(swarm, multiaddr, handler.clone()); // Build the discovery service - let discovery = - DiscoveryBuilder::new().with_listen_config(listen_config).with_chain_id(chain_id).build()?; + let discovery_builder = + DiscoveryBuilder::new().with_address(gossip_addr).with_chain_id(chain_id); + let discovery = if let Some(discovery_addr) = self.discovery_addr.take() { + discovery_builder.with_listen_config(discovery_addr) + } else { + discovery_builder + } + .build()?; Ok(NetworkDriver { unsafe_block_recv, unsafe_block_signer_sender, gossip, discovery }) } } @@ -254,7 +262,7 @@ mod tests { else { panic!("expected error when building NetworkDriver without socket"); }; - assert_eq!(err.to_string(), "socket address not set"); + assert_eq!(err.to_string(), "gossip_addr address not set"); } #[test] @@ -266,7 +274,7 @@ mod tests { let driver = NetworkDriverBuilder::new() .with_unsafe_block_signer(signer) .with_chain_id(id) - .with_socket(socket) + .with_gossip_addr(socket) .with_gossip_config(cfg) .build() .unwrap(); @@ -299,7 +307,7 @@ mod tests { let driver = NetworkDriverBuilder::new() .with_unsafe_block_signer(signer) .with_chain_id(id) - .with_socket(socket) + .with_gossip_addr(socket) .build() .unwrap(); let mut multiaddr = Multiaddr::empty(); @@ -312,6 +320,7 @@ mod tests { // Driver Assertions assert_eq!(driver.gossip.addr, multiaddr); assert_eq!(driver.discovery.chain_id, id); + assert_eq!(driver.discovery.disc.local_enr().tcp4().unwrap(), 9099); // Block Handler Assertions assert_eq!(driver.gossip.handler.chain_id, id); @@ -322,4 +331,21 @@ mod tests { let v3 = IdentTopic::new(format!("/optimism/{}/2/blocks", id)); assert_eq!(driver.gossip.handler.blocks_v3_topic.hash(), v3.hash()); } + + #[test] + fn test_build_network_driver_with_discovery_addr() { + let id = 10; + let signer = Address::random(); + let socket = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 9099); + let discovery_addr = ListenConfig::from_ip(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)), 9098); + let driver = NetworkDriverBuilder::new() + .with_unsafe_block_signer(signer) + .with_chain_id(id) + .with_gossip_addr(socket) + .with_discovery_addr(discovery_addr) + .build() + .unwrap(); + + assert_eq!(driver.discovery.disc.local_enr().tcp4().unwrap(), 9098); + } } diff --git a/crates/net/src/discovery/builder.rs b/crates/net/src/discovery/builder.rs index 7a408bb..b86c262 100644 --- a/crates/net/src/discovery/builder.rs +++ b/crates/net/src/discovery/builder.rs @@ -5,7 +5,7 @@ use discv5::{ enr::{CombinedKey, Enr}, ConfigBuilder, Discv5, ListenConfig, }; -use eyre::Result; +use eyre::{Report, Result}; use std::net::SocketAddr; use crate::types::enr::OP_CL_KEY; @@ -54,11 +54,28 @@ impl DiscoveryBuilder { opstack.encode(&mut opstack_data); let key = CombinedKey::generate_secp256k1(); - let enr = Enr::builder().add_value_rlp(OP_CL_KEY, opstack_data.into()).build(&key)?; - let listen_config = self.listen_config.take().unwrap_or_else(|| { - let addr = self.address.expect("address not set"); - ListenConfig::from_ip(addr.ip(), addr.port()) - }); + let mut enr_builder = Enr::builder(); + enr_builder.add_value_rlp(OP_CL_KEY, opstack_data.into()); + let listen_config = self.listen_config.take().map_or_else( + || { + let addr = self.address.ok_or(eyre::eyre!("address not set"))?; + Ok::(ListenConfig::from(addr)) + }, + Ok, + )?; + match listen_config { + ListenConfig::Ipv4 { ip, port } => { + enr_builder.ip4(ip).tcp4(port); + } + ListenConfig::Ipv6 { ip, port } => { + enr_builder.ip6(ip).tcp6(port); + } + ListenConfig::DualStack { ipv4, ipv4_port, ipv6, ipv6_port } => { + enr_builder.ip4(ipv4).tcp4(ipv4_port); + enr_builder.ip6(ipv6).tcp6(ipv6_port); + } + } + let enr = enr_builder.build(&key)?; let config = ConfigBuilder::new(listen_config).build(); let disc = Discv5::new(enr, key, config)