diff --git a/crates/json-rpc/README.md b/crates/json-rpc/README.md index e63e7d15538..ac69e913bf6 100644 --- a/crates/json-rpc/README.md +++ b/crates/json-rpc/README.md @@ -29,8 +29,6 @@ Requests are sent via transports (see [alloy-transports]). This results in 1 of ### Limitations -- This library models the method name as a `&'static str`, and is therefore - unsuitable for use with RPC servers with dynamic method names. - This library does not support borrowing response data from the deserializer. This is intended to simplify client implementations, but makes the library poorly suited for use in a high-performance server. diff --git a/crates/json-rpc/src/request.rs b/crates/json-rpc/src/request.rs index b5bc2021185..d7e960da217 100644 --- a/crates/json-rpc/src/request.rs +++ b/crates/json-rpc/src/request.rs @@ -2,12 +2,13 @@ use crate::{common::Id, RpcParam}; use alloy_primitives::{keccak256, B256}; use serde::{de::DeserializeOwned, ser::SerializeMap, Deserialize, Serialize}; use serde_json::value::RawValue; +use std::borrow::Cow; /// `RequestMeta` contains the [`Id`] and method name of a request. #[derive(Debug, Clone)] pub struct RequestMeta { /// The method name. - pub method: &'static str, + pub method: Cow<'static, str>, /// The request ID. pub id: Id, /// Whether the request is a subscription, other than `eth_subscribe`. @@ -16,13 +17,13 @@ pub struct RequestMeta { impl RequestMeta { /// Create a new `RequestMeta`. - pub const fn new(method: &'static str, id: Id) -> Self { + pub const fn new(method: Cow<'static, str>, id: Id) -> Self { Self { method, id, is_subscription: false } } /// Returns `true` if the request is a subscription. - pub const fn is_subscription(&self) -> bool { - self.is_subscription || matches!(self.method.as_bytes(), b"eth_subscribe") + pub fn is_subscription(&self) -> bool { + self.is_subscription || self.method == "eth_subscribe" } /// Indicates that the request is a non-standard subscription (i.e. not @@ -51,12 +52,12 @@ pub struct Request { impl Request { /// Create a new `Request`. - pub const fn new(method: &'static str, id: Id, params: Params) -> Self { - Self { meta: RequestMeta::new(method, id), params } + pub fn new(method: impl Into>, id: Id, params: Params) -> Self { + Self { meta: RequestMeta::new(method.into(), id), params } } /// Returns `true` if the request is a subscription. - pub const fn is_subscription(&self) -> bool { + pub fn is_subscription(&self) -> bool { self.meta.is_subscription() } @@ -146,7 +147,7 @@ where let sized_params = std::mem::size_of::() != 0; let mut map = serializer.serialize_map(Some(3 + sized_params as usize))?; - map.serialize_entry("method", self.meta.method)?; + map.serialize_entry("method", &self.meta.method[..])?; // Params may be omitted if it is 0-sized if sized_params { @@ -194,8 +195,8 @@ impl SerializedRequest { } /// Returns the request method. - pub const fn method(&self) -> &'static str { - self.meta.method + pub fn method(&self) -> &str { + &self.meta.method } /// Mark the request as a non-standard subscription (i.e. not @@ -205,7 +206,7 @@ impl SerializedRequest { } /// Returns `true` if the request is a subscription. - pub const fn is_subscription(&self) -> bool { + pub fn is_subscription(&self) -> bool { self.meta.is_subscription() } diff --git a/crates/provider/src/provider.rs b/crates/provider/src/provider.rs index 5ef291db0ba..66c29a21c30 100644 --- a/crates/provider/src/provider.rs +++ b/crates/provider/src/provider.rs @@ -24,6 +24,7 @@ use alloy_transport::{BoxTransport, Transport, TransportErrorKind, TransportResu use alloy_transport_http::Http; use serde_json::value::RawValue; use std::{ + borrow::Cow, fmt, marker::PhantomData, sync::{Arc, OnceLock}, @@ -897,7 +898,7 @@ pub trait Provider: Send + Sync /* ---------------------------------------- raw calls --------------------------------------- */ /// Sends a raw JSON-RPC request. - async fn raw_request(&self, method: &'static str, params: P) -> TransportResult + async fn raw_request(&self, method: Cow<'static, str>, params: P) -> TransportResult where P: RpcParam, R: RpcReturn, @@ -909,7 +910,7 @@ pub trait Provider: Send + Sync /// Sends a raw JSON-RPC request with type-erased parameters and return. async fn raw_request_dyn( &self, - method: &'static str, + method: Cow<'static, str>, params: &RawValue, ) -> TransportResult> { self.client().request(method, params).await @@ -1086,7 +1087,7 @@ mod tests { init_tracing(); let (provider, _anvil) = spawn_anvil(); - let num: U64 = provider.raw_request("eth_blockNumber", ()).await.unwrap(); + let num: U64 = provider.raw_request("eth_blockNumber".into(), ()).await.unwrap(); assert_eq!(0, num.to::()) } @@ -1128,7 +1129,7 @@ mod tests { let block = provider.get_block_by_number(tag, true).await.unwrap().unwrap(); let hash = block.header.hash.unwrap(); let block: Block = provider - .raw_request::<(B256, bool), Block>("eth_getBlockByHash", (hash, true)) + .raw_request::<(B256, bool), Block>("eth_getBlockByHash".into(), (hash, true)) .await .unwrap(); assert_eq!(block.header.hash.unwrap(), hash); diff --git a/crates/pubsub/src/managers/in_flight.rs b/crates/pubsub/src/managers/in_flight.rs index fe466f91ba2..e89a61153b8 100644 --- a/crates/pubsub/src/managers/in_flight.rs +++ b/crates/pubsub/src/managers/in_flight.rs @@ -41,7 +41,7 @@ impl InFlight { } /// Check if the request is a subscription. - pub(crate) const fn is_subscription(&self) -> bool { + pub(crate) fn is_subscription(&self) -> bool { self.request.is_subscription() } diff --git a/crates/rpc-client/src/batch.rs b/crates/rpc-client/src/batch.rs index 1f208266a9d..7871cdd9415 100644 --- a/crates/rpc-client/src/batch.rs +++ b/crates/rpc-client/src/batch.rs @@ -114,7 +114,6 @@ impl<'a, Conn> BatchRequest<'a, Conn> where Conn: Transport + Clone, { - #[must_use = "Waiters do nothing unless polled. A Waiter will never resolve unless the batch is sent!"] /// Add a call to the batch. /// /// ### Errors @@ -122,7 +121,7 @@ where /// If the request cannot be serialized, this will return an error. pub fn add_call( &mut self, - method: &'static str, + method: impl Into>, params: &Params, ) -> TransportResult> { let request = self.transport.make_request(method, Cow::Borrowed(params)); diff --git a/crates/rpc-client/src/client.rs b/crates/rpc-client/src/client.rs index 54fa77b65b2..7960e8deae4 100644 --- a/crates/rpc-client/src/client.rs +++ b/crates/rpc-client/src/client.rs @@ -3,6 +3,7 @@ use alloy_json_rpc::{Id, Request, RpcParam, RpcReturn}; use alloy_transport::{BoxTransport, Transport, TransportConnect, TransportError}; use alloy_transport_http::Http; use std::{ + borrow::Cow, ops::Deref, sync::{ atomic::{AtomicU64, Ordering}, @@ -91,7 +92,7 @@ impl RpcClient { /// See [`PollerBuilder`] for examples and more details. pub fn prepare_static_poller( &self, - method: &'static str, + method: impl Into>, params: Params, ) -> PollerBuilder where @@ -198,7 +199,7 @@ impl RpcClientInner { #[inline] pub fn make_request( &self, - method: &'static str, + method: impl Into>, params: Params, ) -> Request { Request::new(method, self.next_id(), params) @@ -248,7 +249,7 @@ impl RpcClientInner { #[doc(alias = "prepare")] pub fn request( &self, - method: &'static str, + method: impl Into>, params: Params, ) -> RpcCall { let request = self.make_request(method, params); diff --git a/crates/rpc-client/src/poller.rs b/crates/rpc-client/src/poller.rs index c13adb20475..81e83418307 100644 --- a/crates/rpc-client/src/poller.rs +++ b/crates/rpc-client/src/poller.rs @@ -5,6 +5,7 @@ use futures::{Stream, StreamExt}; use serde::Serialize; use serde_json::value::RawValue; use std::{ + borrow::Cow, marker::PhantomData, ops::{Deref, DerefMut}, time::Duration, @@ -61,7 +62,7 @@ pub struct PollerBuilder { client: WeakClient, /// Request Method - method: &'static str, + method: Cow<'static, str>, params: Params, // config options @@ -79,12 +80,16 @@ where Resp: RpcReturn + Clone, { /// Create a new poller task. - pub fn new(client: WeakClient, method: &'static str, params: Params) -> Self { + pub fn new( + client: WeakClient, + method: impl Into>, + params: Params, + ) -> Self { let poll_interval = client.upgrade().map_or_else(|| Duration::from_secs(7), |c| c.default_poll_interval()); Self { client, - method, + method: method.into(), params, channel_size: 16, poll_interval, @@ -144,7 +149,7 @@ where /// Starts the poller in a new Tokio task, returning a channel to receive the responses on. pub fn spawn(self) -> PollChannel { let (tx, rx) = broadcast::channel(self.channel_size); - let span = debug_span!("poller", method = self.method); + let span = debug_span!("poller", method = %self.method); let fut = async move { let mut params = ParamsOnce::Typed(self.params); let mut retries = MAX_RETRIES; @@ -165,7 +170,7 @@ where loop { trace!("polling"); - match client.request(self.method, params).await { + match client.request(self.method.clone(), params).await { Ok(resp) => { if tx.send(resp).is_err() { debug!("channel closed");