diff --git a/Makefile b/Makefile index a15388bf..e592de5a 100644 --- a/Makefile +++ b/Makefile @@ -23,7 +23,7 @@ run-silius-p2p-bootnode: cargo run --release -- node --eth-client-address http://127.0.0.1:8545 --mnemonic-file ./bundler-spec-tests/keys/0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 --beneficiary 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 --entry-points 0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789 --http --http.port 4000 --eth-client-proxy-address http://127.0.0.1:8545 --p2p.baddr 127.0.0.1 --enable-p2p run-silius-p2p-peer: - cargo run --release -- node --eth-client-address http://127.0.0.1:8545 --mnemonic-file ./bundler-spec-tests/keys/0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 --beneficiary 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 --entry-points 0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789 --http --http.port 4000 --eth-client-proxy-address http://127.0.0.1:8545 --p2p.baddr 127.0.0.1 --bootnodes "enr:-J24QMMKCYqEBAs659G2f4MtvjI8wp3dbAvrvRbTxIEaapZfb9Pi0La0QOs6HoGfVeGk8fsFvZF7WiM_arx43rxSHwQBiGNoYWluX2lkiDkFAAAAAAAAgmlkgnY0gmlwhH8AAAGJc2VjcDI1NmsxoQLigwYFOcf1lit2x918h4_6upE1lZ1kK3tD029ZZioW0IN0Y3CCIyiDdWRwgiMo" --enable-p2p --discovery.port 4338 --p2p.port 4338 --datadir ./.local/node1 + cargo run --release -- node --eth-client-address http://127.0.0.1:8545 --mnemonic-file ./bundler-spec-tests/keys/0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 --beneficiary 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 --entry-points 0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789 --http --http.port 4000 --eth-client-proxy-address http://127.0.0.1:8545 --p2p.baddr 127.0.0.1 --bootnodes "enr:-J24QDPWQny36hS9qIFZcbIVSj2APHVP6cGT8hMc-365q2tjWU9Wq_NTyo0QMiXWaGkFfyeE32Pj2HetGHBfEL2QgpQBiGNoYWluX2lkiDkFAAAAAAAAgmlkgnY0gmlwhH8AAAGJc2VjcDI1NmsxoQL_3hI8PSmgjpFl83Nps5MTBjBf3pMm8Bo2TysjqnMGBoN0Y3CCIyiDdWRwgiMo" --enable-p2p --discovery.port 4338 --p2p.port 4338 --datadir ./.local/node1 run-silius-debug: cargo run --release -- node --eth-client-address ws://127.0.0.1:8546 --mnemonic-file ${HOME}/.silius/0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 --beneficiary 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 --entry-points 0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789 --http --ws --http.api eth,debug,web3 --ws.api eth,debug,web3 diff --git a/bin/silius/src/cli/args.rs b/bin/silius/src/cli/args.rs index 49edcc6a..821f9174 100644 --- a/bin/silius/src/cli/args.rs +++ b/bin/silius/src/cli/args.rs @@ -306,6 +306,11 @@ pub struct P2PArgs { /// The path to the file where the p2p enr is stored. #[clap(long = "nodeenr")] pub node_enr: Option, + + /// List of whitelisted ENRs (for permissioned mempools). + /// If empty, all ENRs are allowed. + #[clap(long = "p2p.whitelist", value_delimiter = ',', value_parser=parse_enr)] + pub peers_whitelist: Vec, } impl P2PArgs { @@ -334,6 +339,7 @@ impl P2PArgs { .enr_udp4_port(Some(self.udp4_port)) .chain_spec(ChainSpec::from_chain_id(chain.id())) .bootnodes(self.bootnodes.clone()) + .peers_whitelist(self.peers_whitelist.clone()) .gs_config(gossipsub_config()) .discv5_config(discv5::ConfigBuilder::new(listen_addr.to_listen_config()).build()); @@ -778,6 +784,8 @@ mod tests { "~/.silius/p2p/node-key", "--nodeenr", "~/.silius/p2p/node-enr", + "--p2p.whitelist", + &binding, ]; assert_eq!( P2PArgs { @@ -786,9 +794,10 @@ mod tests { p2p_broadcast_address: Some(Ipv4Addr::new(127, 0, 0, 1)), tcp4_port: 4337, udp4_port: 4337, - bootnodes: vec![enr], + bootnodes: vec![enr.clone()], node_key: Some(PathBuf::from("~/.silius/p2p/node-key")), - node_enr: Some(PathBuf::from("~/.silius/p2p/node-enr")) + node_enr: Some(PathBuf::from("~/.silius/p2p/node-enr")), + peers_whitelist: vec![enr], }, P2PArgs::try_parse_from(args).unwrap() ) diff --git a/crates/p2p/src/config.rs b/crates/p2p/src/config.rs index 5f6dea8e..efde1811 100644 --- a/crates/p2p/src/config.rs +++ b/crates/p2p/src/config.rs @@ -57,6 +57,9 @@ pub struct Config { /// List of bootnodes. pub bootnodes: Vec, + + /// List of whitelisted peer ENRs + pub peers_whitelist: Vec, } impl Default for Config { @@ -85,6 +88,7 @@ impl Default for Config { chain_spec: ChainSpec::dev(), target_peers: TARGET_PEERS, bootnodes: vec![], + peers_whitelist: vec![], } } } @@ -194,6 +198,12 @@ impl ConfigBuilder { self.config.bootnodes = bootnodes; self } + + /// Set the peers whitelist. + pub fn peers_whitelist(mut self, peers_whitelist: Vec) -> Self { + self.config.peers_whitelist = peers_whitelist; + self + } } /// Create a `GossipsubConfig`. diff --git a/crates/p2p/src/peer_manager/mod.rs b/crates/p2p/src/peer_manager/mod.rs index 7bba9ca5..31c61b4e 100644 --- a/crates/p2p/src/peer_manager/mod.rs +++ b/crates/p2p/src/peer_manager/mod.rs @@ -55,12 +55,14 @@ pub struct PeerManager { target_peers: usize, /// Peers needs to be dialed. peers_to_dial: Vec, + /// The list of whitelisted ENRs. + peers_whitelist: Vec, /// The heartbeat interval for peer management. heartbeat: tokio::time::Interval, } impl PeerManager { - pub fn new(network_globals: Arc) -> Self { + pub fn new(network_globals: Arc, peers_whitelist: Vec) -> Self { Self { network_globals, events: Default::default(), @@ -68,6 +70,7 @@ impl PeerManager { outbound_ping_peers: HashSetDelay::new(Duration::from_secs(PING_INTERVAL_OUTBOUND)), target_peers: TARGET_PEERS, peers_to_dial: Vec::new(), + peers_whitelist, heartbeat: tokio::time::interval(Duration::from_secs(HEARTBEAT_INTERVAL)), } } diff --git a/crates/p2p/src/peer_manager/network_behaviour.rs b/crates/p2p/src/peer_manager/network_behaviour.rs index 1dfbb71e..0010bd57 100644 --- a/crates/p2p/src/peer_manager/network_behaviour.rs +++ b/crates/p2p/src/peer_manager/network_behaviour.rs @@ -50,20 +50,34 @@ impl NetworkBehaviour for PeerManager { fn handle_established_inbound_connection( &mut self, _connection_id: libp2p::swarm::ConnectionId, - _peer: PeerId, + peer_id: PeerId, _local_addr: &libp2p::Multiaddr, _remote_addr: &libp2p::Multiaddr, ) -> Result, libp2p::swarm::ConnectionDenied> { + // check if whitelist exists and if the peer is in the whitelist + if !self.peers_whitelist.is_empty() && + self.peers_whitelist.iter().filter(|enr| enr.peer_id() == peer_id).count() == 0 + { + return Err(libp2p::swarm::ConnectionDenied::new("Peer not in the whitelist")); + } + Ok(ConnectionHandler) } fn handle_established_outbound_connection( &mut self, _connection_id: libp2p::swarm::ConnectionId, - _peer: PeerId, + peer_id: PeerId, _addr: &libp2p::Multiaddr, _role_override: libp2p::core::Endpoint, ) -> Result, libp2p::swarm::ConnectionDenied> { + // check if whitelist exists and if the peer is in the whitelist + if !self.peers_whitelist.is_empty() && + self.peers_whitelist.iter().filter(|enr| enr.peer_id() == peer_id).count() == 0 + { + return Err(libp2p::swarm::ConnectionDenied::new("Peer not in the whitelist")); + } + Ok(ConnectionHandler) } diff --git a/crates/p2p/src/service/mod.rs b/crates/p2p/src/service/mod.rs index c8a1757f..5a5584c4 100644 --- a/crates/p2p/src/service/mod.rs +++ b/crates/p2p/src/service/mod.rs @@ -221,7 +221,8 @@ impl Network { let rpc = RPC::new(); - let peer_manager = PeerManager::new(network_globals.clone()); + let peer_manager = + PeerManager::new(network_globals.clone(), config.clone().peers_whitelist); let mut discovery = Discovery::new(combined_key, config.clone(), network_globals.clone()).await?; diff --git a/crates/p2p/tests/common.rs b/crates/p2p/tests/common.rs index 1eb41cd1..eabd2774 100644 --- a/crates/p2p/tests/common.rs +++ b/crates/p2p/tests/common.rs @@ -59,6 +59,7 @@ async fn build_p2p_instance(bootnode: Option) -> eyre::Result { chain_spec: chain_spec.clone(), target_peers: TARGET_PEERS, bootnodes: if let Some(bootnode) = bootnode { vec![bootnode] } else { vec![] }, + peers_whitelist: vec![], }; let (_, receiver) = unbounded();