diff --git a/bin/reth/src/args/rpc_server_args.rs b/bin/reth/src/args/rpc_server_args.rs index 433708ef4..0efebcfd3 100644 --- a/bin/reth/src/args/rpc_server_args.rs +++ b/bin/reth/src/args/rpc_server_args.rs @@ -550,6 +550,25 @@ mod tests { ); } + #[test] + fn test_unique_rpc_modules() { + let args = CommandParser::::parse_from([ + "reth", + "--http.api", + " eth, admin, debug, eth,admin", + "--http", + "--ws", + ]) + .args; + let config = args.transport_rpc_module_config(); + let expected = vec![RethRpcModule::Eth, RethRpcModule::Admin, RethRpcModule::Debug]; + assert_eq!(config.http().cloned().unwrap().into_selection(), expected); + assert_eq!( + config.ws().cloned().unwrap().into_selection(), + RpcModuleSelection::standard_modules() + ); + } + #[test] fn test_rpc_server_config() { let args = CommandParser::::parse_from([ diff --git a/crates/rpc/rpc-builder/src/lib.rs b/crates/rpc/rpc-builder/src/lib.rs index 581c4cbcc..8d4ad0caf 100644 --- a/crates/rpc/rpc-builder/src/lib.rs +++ b/crates/rpc/rpc-builder/src/lib.rs @@ -504,7 +504,11 @@ impl RpcModuleSelection { Self::all_modules() } - /// Creates a new [RpcModuleSelection::Selection] from the given items. + /// Creates a new _unique_ [RpcModuleSelection::Selection] from the given items. + /// + /// # Note + /// + /// This will dedupe the selection and remove duplicates while preserving the order. /// /// # Example /// @@ -516,14 +520,30 @@ impl RpcModuleSelection { /// let config = RpcModuleSelection::try_from_selection(selection).unwrap(); /// assert_eq!(config, RpcModuleSelection::Selection(vec![RethRpcModule::Eth, RethRpcModule::Admin])); /// ``` + /// + /// Create a unique selection from the [RethRpcModule] string identifiers + /// + /// ``` + /// use reth_rpc_builder::{RethRpcModule, RpcModuleSelection}; + /// let selection = vec!["eth", "admin", "eth", "admin"]; + /// let config = RpcModuleSelection::try_from_selection(selection).unwrap(); + /// assert_eq!(config, RpcModuleSelection::Selection(vec![RethRpcModule::Eth, RethRpcModule::Admin])); + /// ``` pub fn try_from_selection(selection: I) -> Result where I: IntoIterator, T: TryInto, { - let selection = - selection.into_iter().map(TryInto::try_into).collect::, _>>()?; - Ok(RpcModuleSelection::Selection(selection)) + let mut unique = HashSet::new(); + + let mut s = Vec::new(); + for item in selection.into_iter() { + let item = item.try_into()?; + if unique.insert(item) { + s.push(item); + } + } + Ok(RpcModuleSelection::Selection(s)) } /// Returns true if no selection is configured @@ -1834,6 +1854,19 @@ mod tests { assert_eq!(selection, RpcModuleSelection::All); } + #[test] + fn parse_rpc_unique_module_selection() { + let selection = "eth,admin,eth,net".parse::().unwrap(); + assert_eq!( + selection, + RpcModuleSelection::Selection(vec![ + RethRpcModule::Eth, + RethRpcModule::Admin, + RethRpcModule::Net, + ]) + ); + } + #[test] fn identical_selection() { assert!(RpcModuleSelection::are_identical(