diff --git a/crates/rpc/rpc-builder/src/lib.rs b/crates/rpc/rpc-builder/src/lib.rs index 06c3af69a9..6bd4223f60 100644 --- a/crates/rpc/rpc-builder/src/lib.rs +++ b/crates/rpc/rpc-builder/src/lib.rs @@ -1966,6 +1966,25 @@ impl TransportRpcModules { self.add_or_replace_ipc(other)?; Ok(()) } + /// Adds or replaces the given [`Methods`] in the transport modules where the specified + /// [`RethRpcModule`] is configured. + pub fn add_or_replace_if_module_configured( + &mut self, + module: RethRpcModule, + other: impl Into, + ) -> Result<(), RegisterMethodError> { + let other = other.into(); + if self.module_config().contains_http(&module) { + self.add_or_replace_http(other.clone())?; + } + if self.module_config().contains_ws(&module) { + self.add_or_replace_ws(other.clone())?; + } + if self.module_config().contains_ipc(&module) { + self.add_or_replace_ipc(other)?; + } + Ok(()) + } } /// Returns the methods installed in the given module that match the given filter. @@ -2522,4 +2541,56 @@ mod tests { assert!(modules.ipc.as_ref().unwrap().method("anything").is_some()); assert!(modules.ws.as_ref().unwrap().method("anything").is_some()); } + + #[test] + fn test_add_or_replace_if_module_configured() { + // Create a config that enables RethRpcModule::Eth for HTTP and WS, but NOT IPC + let config = TransportRpcModuleConfig::default() + .with_http([RethRpcModule::Eth]) + .with_ws([RethRpcModule::Eth]); + + // Create HTTP module with an existing method (to test "replace") + let mut http_module = RpcModule::new(()); + http_module.register_method("eth_existing", |_, _, _| "original").unwrap(); + + // Create WS module with the same existing method + let mut ws_module = RpcModule::new(()); + ws_module.register_method("eth_existing", |_, _, _| "original").unwrap(); + + // Create IPC module (empty, to ensure no changes) + let ipc_module = RpcModule::new(()); + + // Set up TransportRpcModules with the config and modules + let mut modules = TransportRpcModules { + config, + http: Some(http_module), + ws: Some(ws_module), + ipc: Some(ipc_module), + }; + + // Create new methods: one to replace an existing method, one to add a new one + let mut new_module = RpcModule::new(()); + new_module.register_method("eth_existing", |_, _, _| "replaced").unwrap(); // Replace + new_module.register_method("eth_new", |_, _, _| "added").unwrap(); // Add + let new_methods: Methods = new_module.into(); + + // Call the function for RethRpcModule::Eth + let result = modules.add_or_replace_if_module_configured(RethRpcModule::Eth, new_methods); + assert!(result.is_ok(), "Function should succeed"); + + // Verify HTTP: existing method still exists (replaced), new method added + let http = modules.http.as_ref().unwrap(); + assert!(http.method("eth_existing").is_some()); + assert!(http.method("eth_new").is_some()); + + // Verify WS: existing method still exists (replaced), new method added + let ws = modules.ws.as_ref().unwrap(); + assert!(ws.method("eth_existing").is_some()); + assert!(ws.method("eth_new").is_some()); + + // Verify IPC: no changes (Eth not configured for IPC) + let ipc = modules.ipc.as_ref().unwrap(); + assert!(ipc.method("eth_existing").is_none()); + assert!(ipc.method("eth_new").is_none()); + } }