diff --git a/crates/consensus/src/lib.rs b/crates/consensus/src/lib.rs index 7e71696225c..afad9e7cdee 100644 --- a/crates/consensus/src/lib.rs +++ b/crates/consensus/src/lib.rs @@ -9,6 +9,9 @@ extern crate alloc; +#[cfg(feature = "arbitrary")] +use rand as _; + pub use alloy_trie::TrieAccount; #[deprecated(since = "0.7.3", note = "use TrieAccount instead")] diff --git a/crates/contract/src/call.rs b/crates/contract/src/call.rs index 68f9b0f4a0c..fc33ee306c8 100644 --- a/crates/contract/src/call.rs +++ b/crates/contract/src/call.rs @@ -7,13 +7,15 @@ use alloy_primitives::{Address, Bytes, ChainId, TxKind, U256}; use alloy_provider::{PendingTransactionBuilder, Provider}; use alloy_rpc_types_eth::{state::StateOverride, AccessList, BlobTransactionSidecar, BlockId}; use alloy_sol_types::SolCall; -use alloy_transport::Transport; use std::{ future::{Future, IntoFuture}, marker::PhantomData, pin::Pin, }; +// NOTE: The `T` generic here is kept to mitigate breakage with the `sol!` macro. +// It should always be `()` and has no effect on the implementation. + /// [`CallBuilder`] using a [`SolCall`] type as the call decoder. // NOTE: please avoid changing this type due to its use in the `sol!` macro. pub type SolCallBuilder = CallBuilder, N>; @@ -51,7 +53,7 @@ pub type RawCallBuilder = CallBuilder; /// Using [`sol!`][sol]: /// /// ```no_run -/// # async fn test(provider: P) -> Result<(), Box> { +/// # async fn test(provider: P) -> Result<(), Box> { /// use alloy_contract::SolCallBuilder; /// use alloy_primitives::{Address, U256}; /// use alloy_sol_types::sol; @@ -87,7 +89,7 @@ pub type RawCallBuilder = CallBuilder; /// Using [`ContractInstance`](crate::ContractInstance): /// /// ```no_run -/// # async fn test(provider: P, dynamic_abi: alloy_json_abi::JsonAbi) -> Result<(), Box> { +/// # async fn test(provider: P, dynamic_abi: alloy_json_abi::JsonAbi) -> Result<(), Box> { /// use alloy_primitives::{Address, Bytes, U256}; /// use alloy_dyn_abi::DynSolValue; /// use alloy_contract::{CallBuilder, ContractInstance, DynCallBuilder, Interface, RawCallBuilder}; @@ -101,16 +103,16 @@ pub type RawCallBuilder = CallBuilder; /// let provider = ...; /// # ); /// let address = Address::ZERO; -/// let contract: ContractInstance<_, _, _> = interface.connect(address, &provider); +/// let contract: ContractInstance<_, _> = interface.connect(address, &provider); /// /// // Build and call the function: -/// let call_builder: DynCallBuilder<_, _, _> = contract.function("doStuff", &[U256::ZERO.into(), true.into()])?; +/// let call_builder: DynCallBuilder<(), _, _> = contract.function("doStuff", &[U256::ZERO.into(), true.into()])?; /// let result: Vec = call_builder.call().await?; /// /// // You can also decode the output manually. Get the raw bytes: /// let raw_result: Bytes = call_builder.call_raw().await?; /// // Or, equivalently: -/// let raw_builder: RawCallBuilder<_, _, _> = call_builder.clone().clear_decoder(); +/// let raw_builder: RawCallBuilder<(), _, _> = call_builder.clone().clear_decoder(); /// let raw_result: Bytes = raw_builder.call().await?; /// // Decode the raw bytes: /// let decoded_result: Vec = call_builder.decode_output(raw_result, false)?; @@ -129,7 +131,7 @@ pub struct CallBuilder { // NOTE: This is public due to usage in `sol!`, please avoid changing it. pub provider: P, decoder: D, - transport: PhantomData, + fake_transport: PhantomData, } impl CallBuilder { @@ -146,7 +148,7 @@ impl AsRef for CallBuilder, N: Network> DynCallBuilder { +impl, N: Network> DynCallBuilder { pub(crate) fn new_dyn( provider: P, address: &Address, @@ -170,15 +172,13 @@ impl, N: Network> DynCallBuilder, C: SolCall, N: Network> - SolCallBuilder -{ +impl<'a, T, P: Provider, C: SolCall, N: Network> SolCallBuilder { // `sol!` macro constructor, see `#[sol(rpc)]`. Not public API. // NOTE: please avoid changing this function due to its use in the `sol!` macro. pub fn new_sol(provider: &'a P, address: &Address, call: &C) -> Self { @@ -186,7 +186,7 @@ impl<'a, T: Transport + Clone, P: Provider, C: SolCall, N: Network> } } -impl, C: SolCall, N: Network> SolCallBuilder { +impl, C: SolCall, N: Network> SolCallBuilder { /// Clears the decoder, returning a raw call builder. #[inline] pub fn clear_decoder(self) -> RawCallBuilder { @@ -196,12 +196,12 @@ impl, C: SolCall, N: Network> SolCallBui state: self.state, provider: self.provider, decoder: (), - transport: PhantomData, + fake_transport: PhantomData, } } } -impl, N: Network> RawCallBuilder { +impl, N: Network> RawCallBuilder { /// Sets the decoder to the provided [`SolCall`]. /// /// Converts the raw call builder into a sol call builder. @@ -261,12 +261,12 @@ impl, N: Network> RawCallBuilder, - transport: PhantomData, + fake_transport: PhantomData, } } } -impl, N: Network> RawCallBuilder { +impl, N: Network> RawCallBuilder { /// Creates a new call builder with the provided provider and ABI encoded input. /// /// Will not decode the output of the call, meaning that [`call`](Self::call) will behave the @@ -286,7 +286,7 @@ impl, N: Network> RawCallBuilder, D: CallDecoder, N: Network> CallBuilder { +impl, D: CallDecoder, N: Network> CallBuilder { fn new_inner_deploy(provider: P, input: Bytes, decoder: D) -> Self { Self { request: ::default().with_deploy_code(input), @@ -294,7 +294,7 @@ impl, D: CallDecoder, N: Network> CallBu provider, block: BlockId::default(), state: None, - transport: PhantomData, + fake_transport: PhantomData, } } @@ -305,7 +305,7 @@ impl, D: CallDecoder, N: Network> CallBu provider, block: BlockId::default(), state: None, - transport: PhantomData, + fake_transport: PhantomData, } } @@ -447,7 +447,7 @@ impl, D: CallDecoder, N: Network> CallBu /// If this is not desired, use [`call_raw`](Self::call_raw) to get the raw output data. #[doc(alias = "eth_call")] #[doc(alias = "call_with_overrides")] - pub fn call(&self) -> EthCall<'_, '_, D, T, N> { + pub fn call(&self) -> EthCall<'_, '_, D, N> { self.call_raw().with_decoder(&self.decoder) } @@ -457,7 +457,7 @@ impl, D: CallDecoder, N: Network> CallBu /// Does not decode the output of the call, returning the raw output data instead. /// /// See [`call`](Self::call) for more information. - pub fn call_raw(&self) -> EthCall<'_, '_, (), T, N> { + pub fn call_raw(&self) -> EthCall<'_, '_, (), N> { let call = self.provider.call(&self.request).block(self.block); let call = match &self.state { Some(state) => call.overrides(state), @@ -495,7 +495,7 @@ impl, D: CallDecoder, N: Network> CallBu /// /// Returns a builder for configuring the pending transaction watcher. /// See [`Provider::send_transaction`] for more information. - pub async fn send(&self) -> Result> { + pub async fn send(&self) -> Result> { Ok(self.provider.send_transaction(self.request.clone()).await?) } @@ -508,7 +508,7 @@ impl, D: CallDecoder, N: Network> CallBu } } -impl CallBuilder { +impl CallBuilder { /// Clones the provider and returns a new builder with the cloned provider. pub fn with_cloned_provider(self) -> CallBuilder { CallBuilder { @@ -517,7 +517,7 @@ impl CallBuilder { state: self.state, provider: self.provider.clone(), decoder: self.decoder, - transport: PhantomData, + fake_transport: PhantomData, } } } @@ -534,8 +534,8 @@ impl CallBuilder { /// stable yet. See [rust-lang/rust#63063](https://github.com/rust-lang/rust/issues/63063). impl IntoFuture for CallBuilder where - T: Transport + Clone, - P: Provider, + T: Send + Sync, + P: Provider, D: CallDecoder + Send + Sync + Unpin, N: Network, Self: 'static, @@ -621,11 +621,8 @@ mod tests { /// Creates a new call_builder to test field modifications, taken from [call_encoding] #[allow(clippy::type_complexity)] - fn build_call_builder() -> CallBuilder< - alloy_transport::BoxTransport, - AnvilProvider, alloy_transport::BoxTransport>, - PhantomData, - > { + fn build_call_builder( + ) -> CallBuilder<(), AnvilProvider, PhantomData> { let provider = ProviderBuilder::new().on_anvil(); let contract = MyContract::new(Address::ZERO, provider); let call_builder = contract.doStuff(U256::ZERO, true).with_cloned_provider(); diff --git a/crates/contract/src/eth_call.rs b/crates/contract/src/eth_call.rs index bb7eefb757e..ba0818f0ef6 100644 --- a/crates/contract/src/eth_call.rs +++ b/crates/contract/src/eth_call.rs @@ -6,7 +6,6 @@ use alloy_network::Network; use alloy_primitives::Bytes; use alloy_rpc_types_eth::{state::StateOverride, BlockId}; use alloy_sol_types::SolCall; -use alloy_transport::Transport; use crate::{Error, Result}; @@ -24,46 +23,39 @@ mod private { /// An [`alloy_provider::EthCall`] with an abi decoder. #[must_use = "EthCall must be awaited to execute the call"] #[derive(Clone, Debug)] -pub struct EthCall<'req, 'coder, D, T, N> +pub struct EthCall<'req, 'coder, D, N> where - T: Transport + Clone, N: Network, D: CallDecoder, { - inner: alloy_provider::EthCall<'req, T, N, Bytes>, + inner: alloy_provider::EthCall<'req, N, Bytes>, decoder: &'coder D, } -impl<'req, 'coder, D, T, N> EthCall<'req, 'coder, D, T, N> +impl<'req, 'coder, D, N> EthCall<'req, 'coder, D, N> where - T: Transport + Clone, N: Network, D: CallDecoder, { /// Create a new [`EthCall`]. - pub const fn new( - inner: alloy_provider::EthCall<'req, T, N, Bytes>, - decoder: &'coder D, - ) -> Self { + pub const fn new(inner: alloy_provider::EthCall<'req, N, Bytes>, decoder: &'coder D) -> Self { Self { inner, decoder } } } -impl<'req, T, N> EthCall<'req, 'static, (), T, N> +impl<'req, N> EthCall<'req, 'static, (), N> where - T: Transport + Clone, N: Network, { /// Create a new [`EthCall`]. - pub const fn new_raw(inner: alloy_provider::EthCall<'req, T, N, Bytes>) -> Self { + pub const fn new_raw(inner: alloy_provider::EthCall<'req, N, Bytes>) -> Self { Self::new(inner, &RAW_CODER) } } -impl<'req, D, T, N> EthCall<'req, '_, D, T, N> +impl<'req, D, N> EthCall<'req, '_, D, N> where - T: Transport + Clone, N: Network, D: CallDecoder, { @@ -71,7 +63,7 @@ where pub fn with_decoder<'new_coder, E>( self, decoder: &'new_coder E, - ) -> EthCall<'req, 'new_coder, E, T, N> + ) -> EthCall<'req, 'new_coder, E, N> where E: CallDecoder, { @@ -91,26 +83,23 @@ where } } -impl<'req, T, N> From> - for EthCall<'req, 'static, (), T, N> +impl<'req, N> From> for EthCall<'req, 'static, (), N> where - T: Transport + Clone, N: Network, { - fn from(inner: alloy_provider::EthCall<'req, T, N, Bytes>) -> Self { + fn from(inner: alloy_provider::EthCall<'req, N, Bytes>) -> Self { Self { inner, decoder: &RAW_CODER } } } -impl<'req, 'coder, D, T, N> std::future::IntoFuture for EthCall<'req, 'coder, D, T, N> +impl<'req, 'coder, D, N> std::future::IntoFuture for EthCall<'req, 'coder, D, N> where D: CallDecoder + Unpin, - T: Transport + Clone, N: Network, { type Output = Result; - type IntoFuture = EthCallFut<'req, 'coder, D, T, N>; + type IntoFuture = EthCallFut<'req, 'coder, D, N>; fn into_future(self) -> Self::IntoFuture { EthCallFut { inner: self.inner.into_future(), decoder: self.decoder } @@ -122,20 +111,18 @@ where #[must_use = "futures do nothing unless you `.await` or poll them"] #[derive(Debug)] #[allow(unnameable_types)] -pub struct EthCallFut<'req, 'coder, D, T, N> +pub struct EthCallFut<'req, 'coder, D, N> where - T: Transport + Clone, N: Network, D: CallDecoder, { - inner: as IntoFuture>::IntoFuture, + inner: as IntoFuture>::IntoFuture, decoder: &'coder D, } -impl std::future::Future for EthCallFut<'_, '_, D, T, N> +impl std::future::Future for EthCallFut<'_, '_, D, N> where D: CallDecoder + Unpin, - T: Transport + Clone, N: Network, { type Output = Result; diff --git a/crates/contract/src/event.rs b/crates/contract/src/event.rs index a735c9ffa40..0263eae6f27 100644 --- a/crates/contract/src/event.rs +++ b/crates/contract/src/event.rs @@ -4,7 +4,7 @@ use alloy_primitives::{Address, LogData, B256}; use alloy_provider::{FilterPollerBuilder, Network, Provider}; use alloy_rpc_types_eth::{BlockNumberOrTag, Filter, FilterBlockOption, Log, Topic, ValueOrArray}; use alloy_sol_types::SolEvent; -use alloy_transport::{Transport, TransportResult}; +use alloy_transport::TransportResult; use futures::Stream; use futures_util::StreamExt; use std::{fmt, marker::PhantomData}; @@ -30,7 +30,9 @@ impl fmt::Debug for Event { } #[doc(hidden)] -impl<'a, T: Transport + Clone, P: Provider, E: SolEvent, N: Network> Event { +impl<'a, T: crate::private::Transport, P: Provider, E: SolEvent, N: Network> + Event +{ // `sol!` macro constructor, see `#[sol(rpc)]`. Not public API. // NOTE: please avoid changing this function due to its use in the `sol!` macro. pub fn new_sol(provider: &'a P, address: &Address) -> Self { @@ -44,7 +46,7 @@ impl<'a, T: Transport + Clone, P: Provider, E: SolEvent, N: Network> Event } } -impl, E: SolEvent, N: Network> Event { +impl, E: SolEvent, N: Network> Event { /// Creates a new event with the provided provider and filter. pub const fn new(provider: P, filter: Filter) -> Self { Self { provider, filter, _phantom: PhantomData } @@ -67,7 +69,7 @@ impl, E: SolEvent, N: Network> Event TransportResult> { + pub async fn watch(&self) -> TransportResult> { let poller = self.provider.watch_logs(&self.filter).await?; Ok(poller.into()) } @@ -171,27 +173,27 @@ impl Event { /// An event poller. /// /// Polling configuration is available through the [`poller`](Self::poller) field. -pub struct EventPoller { +pub struct EventPoller { /// The inner poller. - pub poller: FilterPollerBuilder, + pub poller: FilterPollerBuilder, _phantom: PhantomData, } -impl AsRef> for EventPoller { +impl AsRef> for EventPoller { #[inline] - fn as_ref(&self) -> &FilterPollerBuilder { + fn as_ref(&self) -> &FilterPollerBuilder { &self.poller } } -impl AsMut> for EventPoller { +impl AsMut> for EventPoller { #[inline] - fn as_mut(&mut self) -> &mut FilterPollerBuilder { + fn as_mut(&mut self) -> &mut FilterPollerBuilder { &mut self.poller } } -impl fmt::Debug for EventPoller { +impl fmt::Debug for EventPoller { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("EventPoller") .field("poller", &self.poller) @@ -200,13 +202,13 @@ impl fmt::Debug for EventPoller { } } -impl From> for EventPoller { - fn from(poller: FilterPollerBuilder) -> Self { +impl From> for EventPoller { + fn from(poller: FilterPollerBuilder) -> Self { Self { poller, _phantom: PhantomData } } } -impl EventPoller { +impl EventPoller { /// Starts the poller and returns a stream that yields the decoded event and the raw log. /// /// Note that this stream will not return `None` until the provider is dropped. @@ -311,7 +313,7 @@ mod tests { let contract = MyContract::deploy(&provider).await.unwrap(); - let event: Event<_, _, MyContract::MyEvent, _> = Event::new(&provider, Filter::new()); + let event: Event<(), _, MyContract::MyEvent, _> = Event::new(&provider, Filter::new()); let all = event.query().await.unwrap(); assert_eq!(all.len(), 0); @@ -412,7 +414,7 @@ mod tests { let contract = MyContract::deploy(&provider).await.unwrap(); - let event: Event<_, _, MyContract::MyEvent, _> = Event::new(&provider, Filter::new()) + let event: Event<(), _, MyContract::MyEvent, _> = Event::new(&provider, Filter::new()) .address(*contract.address()) .event_signature(MyContract::MyEvent::SIGNATURE_HASH); let all = event.query().await.unwrap(); @@ -468,7 +470,7 @@ mod tests { .unwrap(); let contract = MyContract::new(*contract.address(), &provider); - let event: Event<_, _, MyContract::MyEvent, _> = Event::new(&provider, Filter::new()) + let event: Event<(), _, MyContract::MyEvent, _> = Event::new(&provider, Filter::new()) .address(*contract.address()) .event_signature(MyContract::MyEvent::SIGNATURE_HASH); diff --git a/crates/contract/src/instance.rs b/crates/contract/src/instance.rs index 8492a92d453..97484fedba8 100644 --- a/crates/contract/src/instance.rs +++ b/crates/contract/src/instance.rs @@ -6,7 +6,6 @@ use alloy_primitives::{Address, Selector}; use alloy_provider::Provider; use alloy_rpc_types_eth::Filter; use alloy_sol_types::SolEvent; -use alloy_transport::Transport; use std::marker::PhantomData; /// A handle to an Ethereum contract at a specific address. @@ -14,19 +13,18 @@ use std::marker::PhantomData; /// A contract is an abstraction of an executable program on Ethereum. Every deployed contract has /// an address, which is used to connect to it so that it may receive messages (transactions). #[derive(Clone)] -pub struct ContractInstance { +pub struct ContractInstance { address: Address, provider: P, interface: Interface, - transport: PhantomData, network: PhantomData, } -impl ContractInstance { +impl ContractInstance { /// Creates a new contract from the provided address, provider, and interface. #[inline] pub const fn new(address: Address, provider: P, interface: Interface) -> Self { - Self { address, provider, interface, transport: PhantomData, network: PhantomData } + Self { address, provider, interface, network: PhantomData } } /// Returns a reference to the contract's address. @@ -61,21 +59,20 @@ impl ContractInstance { } } -impl ContractInstance { +impl ContractInstance<&P, N> { /// Clones the provider and returns a new contract instance with the cloned provider. #[inline] - pub fn with_cloned_provider(self) -> ContractInstance { + pub fn with_cloned_provider(self) -> ContractInstance { ContractInstance { address: self.address, provider: self.provider.clone(), interface: self.interface, - transport: PhantomData, network: PhantomData, } } } -impl, N: Network> ContractInstance { +impl, N: Network> ContractInstance { /// Returns a transaction builder for the provided function name. /// /// If there are multiple functions with the same name due to overloading, consider using @@ -85,7 +82,7 @@ impl, N: Network> ContractInstance Result> { + ) -> Result> { let function = self.interface.get_from_name(name)?; CallBuilder::new_dyn(&self.provider, &self.address, function, args) } @@ -95,18 +92,18 @@ impl, N: Network> ContractInstance Result> { + ) -> Result> { let function = self.interface.get_from_selector(selector)?; CallBuilder::new_dyn(&self.provider, &self.address, function, args) } /// Returns an [`Event`] builder with the provided filter. - pub const fn event(&self, filter: Filter) -> Event { + pub const fn event(&self, filter: Filter) -> Event<(), &P, E, N> { Event::new(&self.provider, filter) } } -impl std::ops::Deref for ContractInstance { +impl std::ops::Deref for ContractInstance { type Target = Interface; fn deref(&self) -> &Self::Target { @@ -114,7 +111,7 @@ impl std::ops::Deref for ContractInstance { } } -impl std::fmt::Debug for ContractInstance { +impl std::fmt::Debug for ContractInstance { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("ContractInstance").field("address", &self.address).finish() } diff --git a/crates/contract/src/interface.rs b/crates/contract/src/interface.rs index 50ec7ba3b96..93ca79975e6 100644 --- a/crates/contract/src/interface.rs +++ b/crates/contract/src/interface.rs @@ -119,11 +119,7 @@ impl Interface { } /// Create a [`ContractInstance`] from this ABI for a contract at the given address. - pub const fn connect( - self, - address: Address, - provider: P, - ) -> ContractInstance { + pub const fn connect(self, address: Address, provider: P) -> ContractInstance { ContractInstance::new(address, provider, self) } } diff --git a/crates/contract/src/lib.rs b/crates/contract/src/lib.rs index cc31fbe3562..3ed87a4e10f 100644 --- a/crates/contract/src/lib.rs +++ b/crates/contract/src/lib.rs @@ -35,6 +35,13 @@ pub use call::*; #[doc(hidden)] pub mod private { pub use alloy_network::{Ethereum, Network}; - pub use alloy_provider::Provider; - pub use alloy_transport::Transport; + + // Fake traits to mitigate `sol!` macro breaking changes. + pub trait Provider: alloy_provider::Provider {} + impl> Provider<(), N> for P {} + + // This is done so that the compiler can infer the `T` type to be `()`, which is the only type + // that implements this fake `Transport` trait. + pub trait Transport {} + impl Transport for () {} } diff --git a/crates/provider/src/blocks.rs b/crates/provider/src/blocks.rs index 05d095fa7d3..1716a99ac76 100644 --- a/crates/provider/src/blocks.rs +++ b/crates/provider/src/blocks.rs @@ -1,7 +1,7 @@ use alloy_network::{Ethereum, Network}; use alloy_primitives::{BlockNumber, U64}; use alloy_rpc_client::{NoParams, PollerBuilder, WeakClient}; -use alloy_transport::{RpcError, Transport}; +use alloy_transport::RpcError; use async_stream::stream; use futures::{Stream, StreamExt}; use lru::LruCache; @@ -20,8 +20,8 @@ const MAX_RETRIES: usize = 3; const NO_BLOCK_NUMBER: BlockNumber = BlockNumber::MAX; /// Streams new blocks from the client. -pub(crate) struct NewBlocks { - client: WeakClient, +pub(crate) struct NewBlocks { + client: WeakClient, /// The next block to yield. /// [`NO_BLOCK_NUMBER`] indicates that it will be updated on the first poll. /// Only used by the polling task. @@ -31,8 +31,8 @@ pub(crate) struct NewBlocks { _phantom: PhantomData, } -impl NewBlocks { - pub(crate) fn new(client: WeakClient) -> Self { +impl NewBlocks { + pub(crate) fn new(client: WeakClient) -> Self { Self { client, next_yield: NO_BLOCK_NUMBER, @@ -99,7 +99,7 @@ impl NewBlocks { fn into_poll_stream(mut self) -> impl Stream + 'static { stream! { // Spawned lazily on the first `poll`. - let poll_task_builder: PollerBuilder = + let poll_task_builder: PollerBuilder = PollerBuilder::new(self.client.clone(), "eth_blockNumber", []); let mut poll_task = poll_task_builder.spawn().into_stream_raw(); 'task: loop { @@ -208,7 +208,7 @@ mod tests { let url = if ws { anvil.ws_endpoint() } else { anvil.endpoint() }; let provider = ProviderBuilder::new().on_builtin(&url).await.unwrap(); - let new_blocks = NewBlocks::<_, Ethereum>::new(provider.weak_client()).with_next_yield(1); + let new_blocks = NewBlocks::::new(provider.weak_client()).with_next_yield(1); let mut stream = Box::pin(new_blocks.into_stream()); if ws { let _ = try_timeout(stream.next()).await; // Subscribe to newHeads. @@ -239,7 +239,7 @@ mod tests { let url = if ws { anvil.ws_endpoint() } else { anvil.endpoint() }; let provider = ProviderBuilder::new().on_builtin(&url).await.unwrap(); - let new_blocks = NewBlocks::<_, Ethereum>::new(provider.weak_client()).with_next_yield(1); + let new_blocks = NewBlocks::::new(provider.weak_client()).with_next_yield(1); let mut stream = Box::pin(new_blocks.into_stream()); if ws { let _ = try_timeout(stream.next()).await; // Subscribe to newHeads. diff --git a/crates/provider/src/builder.rs b/crates/provider/src/builder.rs index 32f135f0f61..901db43be51 100644 --- a/crates/provider/src/builder.rs +++ b/crates/provider/src/builder.rs @@ -9,16 +9,16 @@ use crate::{ use alloy_chains::NamedChain; use alloy_network::{Ethereum, Network}; use alloy_primitives::ChainId; -use alloy_rpc_client::{BuiltInConnectionString, ClientBuilder, RpcClient}; -use alloy_transport::{BoxTransport, Transport, TransportError, TransportResult}; +use alloy_rpc_client::{ClientBuilder, RpcClient}; +use alloy_transport::{TransportError, TransportResult}; use std::marker::PhantomData; /// A layering abstraction in the vein of [`tower::Layer`] /// /// [`tower::Layer`]: https://docs.rs/tower/latest/tower/trait.Layer.html -pub trait ProviderLayer, T: Transport + Clone, N: Network = Ethereum> { +pub trait ProviderLayer, N: Network = Ethereum> { /// The provider constructed by this layer. - type Provider: Provider; + type Provider: Provider; /// Wrap the given provider in the layer's provider. fn layer(&self, inner: P) -> Self::Provider; @@ -40,7 +40,7 @@ where fn fill_sync(&self, _tx: &mut SendableTx) {} - async fn prepare( + async fn prepare

( &self, _provider: &P, _tx: &N::TransactionRequest, @@ -57,11 +57,10 @@ where } } -impl ProviderLayer for Identity +impl ProviderLayer for Identity where - T: Transport + Clone, N: Network, - P: Provider, + P: Provider, { type Provider = P; @@ -84,13 +83,12 @@ impl Stack { } } -impl ProviderLayer for Stack +impl ProviderLayer for Stack where - T: Transport + Clone, N: Network, - P: Provider, - Inner: ProviderLayer, - Outer: ProviderLayer, + P: Provider, + Inner: ProviderLayer, + Outer: ProviderLayer, { type Provider = Outer::Provider; @@ -257,15 +255,14 @@ impl ProviderBuilder { /// Finish the layer stack by providing a root [`Provider`], outputting /// the final [`Provider`] type with all stack components. - pub fn on_provider(self, provider: P) -> F::Provider + pub fn on_provider

(self, provider: P) -> F::Provider where - L: ProviderLayer, - F: TxFiller + ProviderLayer, - P: Provider, - T: Transport + Clone, + L: ProviderLayer, + F: TxFiller + ProviderLayer, + P: Provider, N: Network, { - let Self { layer, filler, .. } = self; + let Self { layer, filler, network: PhantomData } = self; let stack = Stack::new(layer, filler); stack.layer(provider) } @@ -275,11 +272,10 @@ impl ProviderBuilder { /// /// This is a convenience function for /// `ProviderBuilder::provider`. - pub fn on_client(self, client: RpcClient) -> F::Provider + pub fn on_client(self, client: RpcClient) -> F::Provider where - L: ProviderLayer, T, N>, - F: TxFiller + ProviderLayer, - T: Transport + Clone, + L: ProviderLayer, N>, + F: TxFiller + ProviderLayer, N: Network, { self.on_provider(RootProvider::new(client)) @@ -290,12 +286,11 @@ impl ProviderBuilder { /// components. pub async fn on_builtin(self, s: &str) -> Result where - L: ProviderLayer, BoxTransport, N>, - F: TxFiller + ProviderLayer, + L: ProviderLayer, N>, + F: TxFiller + ProviderLayer, N: Network, { - let connect: BuiltInConnectionString = s.parse()?; - let client = ClientBuilder::default().connect_boxed(connect).await?; + let client = ClientBuilder::default().connect(s).await?; Ok(self.on_client(client)) } @@ -306,12 +301,8 @@ impl ProviderBuilder { connect: alloy_transport_ws::WsConnect, ) -> Result where - L: ProviderLayer< - RootProvider, - alloy_pubsub::PubSubFrontend, - N, - >, - F: TxFiller + ProviderLayer, + L: ProviderLayer, N>, + F: TxFiller + ProviderLayer, N: Network, { let client = ClientBuilder::default().ws(connect).await?; @@ -326,12 +317,8 @@ impl ProviderBuilder { ) -> Result where alloy_transport_ipc::IpcConnect: alloy_pubsub::PubSubConnect, - L: ProviderLayer< - RootProvider, - alloy_pubsub::PubSubFrontend, - N, - >, - F: TxFiller + ProviderLayer, + L: ProviderLayer, N>, + F: TxFiller + ProviderLayer, N: Network, { let client = ClientBuilder::default().ipc(connect).await?; @@ -342,8 +329,8 @@ impl ProviderBuilder { #[cfg(any(test, feature = "reqwest"))] pub fn on_http(self, url: reqwest::Url) -> F::Provider where - L: ProviderLayer, alloy_transport_http::Http, N>, - F: TxFiller + ProviderLayer, N>, + L: ProviderLayer, N>, + F: TxFiller + ProviderLayer, N: Network, { let client = ClientBuilder::default().http(url); @@ -354,8 +341,8 @@ impl ProviderBuilder { #[cfg(feature = "hyper")] pub fn on_hyper_http(self, url: url::Url) -> F::Provider where - L: ProviderLayer, alloy_transport_http::HyperTransport, N>, - F: TxFiller + ProviderLayer, + L: ProviderLayer, N>, + F: TxFiller + ProviderLayer, N: Network, { let client = ClientBuilder::default().hyper_http(url); @@ -376,10 +363,9 @@ impl ProviderBuilder { /// Build this provider with anvil, using the BoxTransport. pub fn on_anvil(self) -> F::Provider where - F: TxFiller + ProviderLayer, + F: TxFiller + ProviderLayer, L: crate::builder::ProviderLayer< - crate::layers::AnvilProvider, BoxTransport>, - BoxTransport, + crate::layers::AnvilProvider, >, { self.on_anvil_with_config(std::convert::identity) @@ -390,12 +376,11 @@ impl ProviderBuilder { /// use in tests. pub fn on_anvil_with_wallet( self, - ) -> as ProviderLayer>::Provider + ) -> as ProviderLayer>::Provider where - F: TxFiller + ProviderLayer, + F: TxFiller + ProviderLayer, L: crate::builder::ProviderLayer< - crate::layers::AnvilProvider, BoxTransport>, - BoxTransport, + crate::layers::AnvilProvider, >, { self.on_anvil_with_wallet_and_config(std::convert::identity) @@ -408,16 +393,15 @@ impl ProviderBuilder { f: impl FnOnce(alloy_node_bindings::Anvil) -> alloy_node_bindings::Anvil, ) -> F::Provider where - F: TxFiller + ProviderLayer, + F: TxFiller + ProviderLayer, L: crate::builder::ProviderLayer< - crate::layers::AnvilProvider, BoxTransport>, - BoxTransport, + crate::layers::AnvilProvider, >, { let anvil_layer = crate::layers::AnvilLayer::from(f(Default::default())); let url = anvil_layer.endpoint_url(); - let rpc_client = ClientBuilder::default().http(url).boxed(); + let rpc_client = ClientBuilder::default().http(url); self.layer(anvil_layer).on_client(rpc_client) } @@ -427,12 +411,11 @@ impl ProviderBuilder { pub fn on_anvil_with_wallet_and_config( self, f: impl FnOnce(alloy_node_bindings::Anvil) -> alloy_node_bindings::Anvil, - ) -> as ProviderLayer>::Provider + ) -> as ProviderLayer>::Provider where - F: TxFiller + ProviderLayer, + F: TxFiller + ProviderLayer, L: crate::builder::ProviderLayer< - crate::layers::AnvilProvider, BoxTransport>, - BoxTransport, + crate::layers::AnvilProvider, >, { self.try_on_anvil_with_wallet_and_config(f).unwrap() @@ -445,14 +428,11 @@ impl ProviderBuilder { pub fn try_on_anvil_with_wallet_and_config( self, f: impl FnOnce(alloy_node_bindings::Anvil) -> alloy_node_bindings::Anvil, - ) -> AnvilProviderResult< - as ProviderLayer>::Provider, - > + ) -> AnvilProviderResult< as ProviderLayer>::Provider> where - F: TxFiller + ProviderLayer, + F: TxFiller + ProviderLayer, L: crate::builder::ProviderLayer< - crate::layers::AnvilProvider, BoxTransport>, - BoxTransport, + crate::layers::AnvilProvider, >, { use alloy_signer::Signer; @@ -472,7 +452,7 @@ impl ProviderBuilder { wallet.register_signer(alloy_signer_local::LocalSigner::from(key.clone())) } - let rpc_client = ClientBuilder::default().http(url).boxed(); + let rpc_client = ClientBuilder::default().http(url); Ok(self.wallet(wallet).layer(anvil_layer).on_client(rpc_client)) } diff --git a/crates/provider/src/ext/admin.rs b/crates/provider/src/ext/admin.rs index 6f2c1a73c8e..eb92cd121d3 100644 --- a/crates/provider/src/ext/admin.rs +++ b/crates/provider/src/ext/admin.rs @@ -2,12 +2,12 @@ use crate::Provider; use alloy_network::Network; use alloy_rpc_types_admin::{NodeInfo, PeerInfo}; -use alloy_transport::{Transport, TransportResult}; +use alloy_transport::TransportResult; /// Admin namespace rpc interface that gives access to several non-standard RPC methods. #[cfg_attr(target_arch = "wasm32", async_trait::async_trait(?Send))] #[cfg_attr(not(target_arch = "wasm32"), async_trait::async_trait)] -pub trait AdminApi: Send + Sync { +pub trait AdminApi: Send + Sync { /// Requests adding the given peer, returning a boolean representing /// whether or not the peer was accepted for tracking. async fn add_peer(&self, record: &str) -> TransportResult; @@ -41,11 +41,10 @@ pub trait AdminApi: Send + Sync { #[cfg_attr(target_arch = "wasm32", async_trait::async_trait(?Send))] #[cfg_attr(not(target_arch = "wasm32"), async_trait::async_trait)] -impl AdminApi for P +impl AdminApi for P where N: Network, - T: Transport + Clone, - P: Provider, + P: Provider, { async fn add_peer(&self, record: &str) -> TransportResult { self.client().request("admin_addPeer", (record,)).await diff --git a/crates/provider/src/ext/anvil.rs b/crates/provider/src/ext/anvil.rs index dfb411331fd..85f073ad28c 100644 --- a/crates/provider/src/ext/anvil.rs +++ b/crates/provider/src/ext/anvil.rs @@ -5,12 +5,12 @@ use alloy_network::Network; use alloy_primitives::{Address, Bytes, TxHash, B256, U256}; use alloy_rpc_types_anvil::{Forking, Metadata, MineOptions, NodeInfo, ReorgOptions}; use alloy_rpc_types_eth::Block; -use alloy_transport::{Transport, TransportResult}; +use alloy_transport::TransportResult; /// Anvil namespace rpc interface that gives access to several non-standard RPC methods. #[cfg_attr(target_arch = "wasm32", async_trait::async_trait(?Send))] #[cfg_attr(not(target_arch = "wasm32"), async_trait::async_trait)] -pub trait AnvilApi: Send + Sync { +pub trait AnvilApi: Send + Sync { // Not implemented: // - anvil_enable_traces: Not implemented in the Anvil RPC API. // - anvil_set_block: Not implemented / wired correctly in the Anvil RPC API. @@ -150,11 +150,10 @@ pub trait AnvilApi: Send + Sync { #[cfg_attr(target_arch = "wasm32", async_trait::async_trait(?Send))] #[cfg_attr(not(target_arch = "wasm32"), async_trait::async_trait)] -impl AnvilApi for P +impl AnvilApi for P where N: Network, - T: Transport + Clone, - P: Provider, + P: Provider, { async fn anvil_impersonate_account(&self, address: Address) -> TransportResult<()> { self.client().request("anvil_impersonateAccount", (address,)).await diff --git a/crates/provider/src/ext/debug.rs b/crates/provider/src/ext/debug.rs index 40574da50d0..5bf2bd8e7be 100644 --- a/crates/provider/src/ext/debug.rs +++ b/crates/provider/src/ext/debug.rs @@ -11,12 +11,12 @@ use alloy_rpc_types_trace::geth::{ BlockTraceResult, CallFrame, GethDebugTracingCallOptions, GethDebugTracingOptions, GethTrace, TraceResult, }; -use alloy_transport::{Transport, TransportResult}; +use alloy_transport::TransportResult; /// Debug namespace rpc interface that gives access to several non-standard RPC methods. #[cfg_attr(target_arch = "wasm32", async_trait::async_trait(?Send))] #[cfg_attr(not(target_arch = "wasm32"), async_trait::async_trait)] -pub trait DebugApi: Send + Sync { +pub trait DebugApi: Send + Sync { /// Returns an RLP-encoded header. async fn debug_get_raw_header(&self, block: BlockId) -> TransportResult; @@ -253,11 +253,10 @@ pub trait DebugApi: Send + Sync { #[cfg_attr(target_arch = "wasm32", async_trait::async_trait(?Send))] #[cfg_attr(not(target_arch = "wasm32"), async_trait::async_trait)] -impl DebugApi for P +impl DebugApi for P where N: Network, - T: Transport + Clone, - P: Provider, + P: Provider, { async fn debug_get_raw_header(&self, block: BlockId) -> TransportResult { self.client().request("debug_getRawHeader", (block,)).await diff --git a/crates/provider/src/ext/engine.rs b/crates/provider/src/ext/engine.rs index 52c0dfea200..c91ebfb570c 100644 --- a/crates/provider/src/ext/engine.rs +++ b/crates/provider/src/ext/engine.rs @@ -7,7 +7,7 @@ use alloy_rpc_types_engine::{ ExecutionPayloadV1, ExecutionPayloadV3, ForkchoiceState, ForkchoiceUpdated, PayloadAttributes, PayloadId, PayloadStatus, }; -use alloy_transport::{Transport, TransportResult}; +use alloy_transport::TransportResult; /// Extension trait that gives access to engine API RPC methods. /// @@ -15,7 +15,7 @@ use alloy_transport::{Transport, TransportResult}; /// > The provider should use a JWT authentication layer. #[cfg_attr(target_arch = "wasm32", async_trait::async_trait(?Send))] #[cfg_attr(not(target_arch = "wasm32"), async_trait::async_trait)] -pub trait EngineApi: Send + Sync { +pub trait EngineApi: Send + Sync { /// Sends the given payload to the execution layer client, as specified for the Paris fork. /// /// Caution: This should not accept the `withdrawals` field @@ -181,11 +181,10 @@ pub trait EngineApi: Send + Sync { #[cfg_attr(target_arch = "wasm32", async_trait::async_trait(?Send))] #[cfg_attr(not(target_arch = "wasm32"), async_trait::async_trait)] -impl EngineApi for P +impl EngineApi for P where N: Network, - T: Transport + Clone, - P: Provider, + P: Provider, { async fn new_payload_v1(&self, payload: ExecutionPayloadV1) -> TransportResult { self.client().request("engine_newPayloadV1", (payload,)).await diff --git a/crates/provider/src/ext/erc4337.rs b/crates/provider/src/ext/erc4337.rs index ffd0b050dd3..6f3a288a60e 100644 --- a/crates/provider/src/ext/erc4337.rs +++ b/crates/provider/src/ext/erc4337.rs @@ -4,7 +4,7 @@ use alloy_primitives::{Address, Bytes}; use alloy_rpc_types_eth::erc4337::{ SendUserOperation, SendUserOperationResponse, UserOperationGasEstimation, UserOperationReceipt, }; -use alloy_transport::{Transport, TransportResult}; +use alloy_transport::TransportResult; /// ERC-4337 Account Abstraction API /// @@ -12,7 +12,7 @@ use alloy_transport::{Transport, TransportResult}; /// as defined in ERC-4337. #[cfg_attr(target_arch = "wasm32", async_trait::async_trait(?Send))] #[cfg_attr(not(target_arch = "wasm32"), async_trait::async_trait)] -pub trait Erc4337Api: Send + Sync { +pub trait Erc4337Api: Send + Sync { /// Sends a user operation to the bundler, as defined in ERC-4337. /// /// Entry point changes based on the user operation type. @@ -45,11 +45,10 @@ pub trait Erc4337Api: Send + Sync { #[cfg_attr(target_arch = "wasm32", async_trait::async_trait(?Send))] #[cfg_attr(not(target_arch = "wasm32"), async_trait::async_trait)] -impl Erc4337Api for P +impl Erc4337Api for P where N: Network, - T: Transport + Clone, - P: Provider, + P: Provider, { async fn send_user_operation( &self, diff --git a/crates/provider/src/ext/net.rs b/crates/provider/src/ext/net.rs index 449f1772ed4..b915ed02baa 100644 --- a/crates/provider/src/ext/net.rs +++ b/crates/provider/src/ext/net.rs @@ -1,12 +1,12 @@ //! This module extends the Ethereum JSON-RPC provider with the Net namespace's RPC methods. use crate::Provider; use alloy_network::Network; -use alloy_transport::{Transport, TransportResult}; +use alloy_transport::TransportResult; /// Net namespace rpc interface that provides access to network information of the node. #[cfg_attr(target_arch = "wasm32", async_trait::async_trait(?Send))] #[cfg_attr(not(target_arch = "wasm32"), async_trait::async_trait)] -pub trait NetApi: Send + Sync { +pub trait NetApi: Send + Sync { /// Returns a `bool` indicating whether or not the node is listening for network connections. async fn net_listening(&self) -> TransportResult; /// Returns the number of peers connected to the node. @@ -17,11 +17,10 @@ pub trait NetApi: Send + Sync { #[cfg_attr(target_arch = "wasm32", async_trait::async_trait(?Send))] #[cfg_attr(not(target_arch = "wasm32"), async_trait::async_trait)] -impl NetApi for P +impl NetApi for P where N: Network, - T: Transport + Clone, - P: Provider, + P: Provider, { async fn net_listening(&self) -> TransportResult { self.client().request_noparams("net_listening").await diff --git a/crates/provider/src/ext/rpc.rs b/crates/provider/src/ext/rpc.rs index aea6828fd6e..0ae78d54244 100644 --- a/crates/provider/src/ext/rpc.rs +++ b/crates/provider/src/ext/rpc.rs @@ -2,24 +2,23 @@ use crate::Provider; use alloy_network::Network; use alloy_rpc_types::RpcModules; -use alloy_transport::{Transport, TransportResult}; +use alloy_transport::TransportResult; /// The rpc API provides methods to get information about the RPC server itself, such as the enabled /// namespaces. #[cfg_attr(target_arch = "wasm32", async_trait::async_trait(?Send))] #[cfg_attr(not(target_arch = "wasm32"), async_trait::async_trait)] -pub trait RpcApi: Send + Sync { +pub trait RpcApi: Send + Sync { /// Lists the enabled RPC namespaces and the versions of each. async fn rpc_modules(&self) -> TransportResult; } #[cfg_attr(target_arch = "wasm32", async_trait::async_trait(?Send))] #[cfg_attr(not(target_arch = "wasm32"), async_trait::async_trait)] -impl RpcApi for P +impl RpcApi for P where N: Network, - T: Transport + Clone, - P: Provider, + P: Provider, { async fn rpc_modules(&self) -> TransportResult { self.client().request_noparams("rpc_modules").await diff --git a/crates/provider/src/ext/trace.rs b/crates/provider/src/ext/trace.rs index 35e1caa825d..58c7a268fc1 100644 --- a/crates/provider/src/ext/trace.rs +++ b/crates/provider/src/ext/trace.rs @@ -8,7 +8,7 @@ use alloy_rpc_types_trace::{ filter::TraceFilter, parity::{LocalizedTransactionTrace, TraceResults, TraceResultsWithTransactionHash, TraceType}, }; -use alloy_transport::{Transport, TransportResult}; +use alloy_transport::TransportResult; /// List of trace calls for use with [`TraceApi::trace_call_many`] pub type TraceCallList<'a, N> = &'a [(::TransactionRequest, &'a [TraceType])]; @@ -16,10 +16,9 @@ pub type TraceCallList<'a, N> = &'a [(::TransactionRequest, &'a [T /// Trace namespace rpc interface that gives access to several non-standard RPC methods. #[cfg_attr(target_arch = "wasm32", async_trait::async_trait(?Send))] #[cfg_attr(not(target_arch = "wasm32"), async_trait::async_trait)] -pub trait TraceApi: Send + Sync +pub trait TraceApi: Send + Sync where N: Network, - T: Transport + Clone, { /// Executes the given transaction and returns a number of possible traces. /// @@ -30,7 +29,7 @@ where &self, request: &'a N::TransactionRequest, trace_type: &'b [TraceType], - ) -> RpcWithBlock; + ) -> RpcWithBlock<(&'a N::TransactionRequest, &'b [TraceType]), TraceResults>; /// Traces multiple transactions on top of the same block, i.e. transaction `n` will be executed /// on top of the given block with all `n - 1` transaction applied first. @@ -43,7 +42,7 @@ where fn trace_call_many<'a>( &self, request: TraceCallList<'a, N>, - ) -> RpcWithBlock,), Vec>; + ) -> RpcWithBlock<(TraceCallList<'a, N>,), Vec>; /// Parity trace transaction. async fn trace_transaction( @@ -100,25 +99,23 @@ where #[cfg_attr(target_arch = "wasm32", async_trait::async_trait(?Send))] #[cfg_attr(not(target_arch = "wasm32"), async_trait::async_trait)] -impl TraceApi for P +impl TraceApi for P where N: Network, - T: Transport + Clone, - P: Provider, + P: Provider, { fn trace_call<'a, 'b>( &self, request: &'a ::TransactionRequest, trace_types: &'b [TraceType], - ) -> RpcWithBlock::TransactionRequest, &'b [TraceType]), TraceResults> - { + ) -> RpcWithBlock<(&'a ::TransactionRequest, &'b [TraceType]), TraceResults> { self.client().request("trace_call", (request, trace_types)).into() } fn trace_call_many<'a>( &self, request: TraceCallList<'a, N>, - ) -> RpcWithBlock,), Vec> { + ) -> RpcWithBlock<(TraceCallList<'a, N>,), Vec> { self.client().request("trace_callMany", (request,)).into() } diff --git a/crates/provider/src/ext/txpool.rs b/crates/provider/src/ext/txpool.rs index 0250c2f468b..4fdb9344715 100644 --- a/crates/provider/src/ext/txpool.rs +++ b/crates/provider/src/ext/txpool.rs @@ -3,13 +3,13 @@ use crate::Provider; use alloy_network::{Ethereum, Network}; use alloy_primitives::Address; use alloy_rpc_types_txpool::{TxpoolContent, TxpoolContentFrom, TxpoolInspect, TxpoolStatus}; -use alloy_transport::{Transport, TransportResult}; +use alloy_transport::TransportResult; /// Txpool namespace rpc interface. #[allow(unused, unreachable_pub)] #[cfg_attr(target_arch = "wasm32", async_trait::async_trait(?Send))] #[cfg_attr(not(target_arch = "wasm32"), async_trait::async_trait)] -pub trait TxPoolApi: Send + Sync { +pub trait TxPoolApi: Send + Sync { /// Returns the content of the transaction pool. /// /// Lists the exact details of all the transactions currently pending for inclusion in the next @@ -47,10 +47,9 @@ pub trait TxPoolApi: Send + Sync { #[cfg_attr(target_arch = "wasm32", async_trait::async_trait(?Send))] #[cfg_attr(not(target_arch = "wasm32"), async_trait::async_trait)] -impl TxPoolApi for P +impl TxPoolApi for P where - P: Provider, - T: Transport + Clone, + P: Provider, N: Network, { async fn txpool_content(&self) -> TransportResult> { diff --git a/crates/provider/src/fillers/chain_id.rs b/crates/provider/src/fillers/chain_id.rs index 6e689d0d1f6..583228cbeeb 100644 --- a/crates/provider/src/fillers/chain_id.rs +++ b/crates/provider/src/fillers/chain_id.rs @@ -70,18 +70,17 @@ impl TxFiller for ChainIdFiller { if builder.chain_id().is_none() { builder.set_chain_id(*chain_id) } - }; + } } } - async fn prepare( + async fn prepare

( &self, provider: &P, _tx: &N::TransactionRequest, ) -> TransportResult where - P: crate::Provider, - T: alloy_transport::Transport + Clone, + P: crate::Provider, { match self.0.get().copied() { Some(chain_id) => Ok(chain_id), diff --git a/crates/provider/src/fillers/gas.rs b/crates/provider/src/fillers/gas.rs index 32155d38e28..ab66fb29513 100644 --- a/crates/provider/src/fillers/gas.rs +++ b/crates/provider/src/fillers/gas.rs @@ -10,7 +10,7 @@ use alloy_eips::eip4844::BLOB_TX_MIN_BLOB_GASPRICE; use alloy_json_rpc::RpcError; use alloy_network::{Network, TransactionBuilder, TransactionBuilder4844}; use alloy_rpc_types_eth::BlockNumberOrTag; -use alloy_transport::{Transport, TransportResult}; +use alloy_transport::TransportResult; use futures::FutureExt; /// An enum over the different types of gas fillable. @@ -65,14 +65,13 @@ pub enum GasFillable { pub struct GasFiller; impl GasFiller { - async fn prepare_legacy( + async fn prepare_legacy( &self, provider: &P, tx: &N::TransactionRequest, ) -> TransportResult where - P: Provider, - T: Transport + Clone, + P: Provider, N: Network, { let gas_price_fut = tx.gas_price().map_or_else( @@ -90,14 +89,13 @@ impl GasFiller { Ok(GasFillable::Legacy { gas_limit, gas_price }) } - async fn prepare_1559( + async fn prepare_1559( &self, provider: &P, tx: &N::TransactionRequest, ) -> TransportResult where - P: Provider, - T: Transport + Clone, + P: Provider, N: Network, { let gas_limit_fut = tx.gas_limit().map_or_else( @@ -142,14 +140,13 @@ impl TxFiller for GasFiller { fn fill_sync(&self, _tx: &mut SendableTx) {} - async fn prepare( + async fn prepare

( &self, provider: &P, tx: &::TransactionRequest, ) -> TransportResult where - P: Provider, - T: Transport + Clone, + P: Provider, { if tx.gas_price().is_some() { self.prepare_legacy(provider, tx).await @@ -209,14 +206,13 @@ where fn fill_sync(&self, _tx: &mut SendableTx) {} - async fn prepare( + async fn prepare

( &self, provider: &P, tx: &::TransactionRequest, ) -> TransportResult where - P: Provider, - T: Transport + Clone, + P: Provider, { if let Some(max_fee_per_blob_gas) = tx.max_fee_per_blob_gas() { if max_fee_per_blob_gas >= BLOB_TX_MIN_BLOB_GASPRICE { diff --git a/crates/provider/src/fillers/join_fill.rs b/crates/provider/src/fillers/join_fill.rs index 3709e96eb3f..5528aabada2 100644 --- a/crates/provider/src/fillers/join_fill.rs +++ b/crates/provider/src/fillers/join_fill.rs @@ -4,7 +4,7 @@ use crate::{ Provider, ProviderLayer, }; use alloy_network::Network; -use alloy_transport::{Transport, TransportResult}; +use alloy_transport::TransportResult; use futures::try_join; /// A layer that can fill in a [`TransactionRequest`] with additional information by joining two @@ -13,7 +13,7 @@ use futures::try_join; /// This struct is itself a [`TxFiller`], and can be nested to compose any number of fill layers. /// /// [`TransactionRequest`]: alloy_rpc_types_eth::TransactionRequest -#[derive(Clone, Copy, Debug)] +#[derive(Clone, Copy, Debug, Default)] pub struct JoinFill { left: L, right: R, @@ -45,14 +45,13 @@ impl JoinFill { impl JoinFill { /// Get a request for the left filler, if the left filler is ready. - async fn prepare_left( + async fn prepare_left( &self, provider: &P, tx: &N::TransactionRequest, ) -> TransportResult> where - P: Provider, - T: Transport + Clone, + P: Provider, L: TxFiller, N: Network, { @@ -64,14 +63,13 @@ impl JoinFill { } /// Get a prepare for the right filler, if the right filler is ready. - async fn prepare_right( + async fn prepare_right( &self, provider: &P, tx: &N::TransactionRequest, ) -> TransportResult> where - P: Provider, - T: Transport + Clone, + P: Provider, R: TxFiller, N: Network, { @@ -100,14 +98,13 @@ where self.right.fill_sync(tx); } - async fn prepare( + async fn prepare

( &self, provider: &P, tx: &N::TransactionRequest, ) -> TransportResult where - P: Provider, - T: Transport + Clone, + P: Provider, { try_join!(self.prepare_left(provider, tx), self.prepare_right(provider, tx)) } @@ -127,15 +124,14 @@ where } } -impl ProviderLayer for JoinFill +impl ProviderLayer for JoinFill where L: TxFiller, R: TxFiller, - P: Provider, - T: alloy_transport::Transport + Clone, + P: Provider, N: Network, { - type Provider = FillProvider; + type Provider = FillProvider; fn layer(&self, inner: P) -> Self::Provider { FillProvider::new(inner, self.clone()) } diff --git a/crates/provider/src/fillers/mod.rs b/crates/provider/src/fillers/mod.rs index 5448162dee9..2465f5d89a6 100644 --- a/crates/provider/src/fillers/mod.rs +++ b/crates/provider/src/fillers/mod.rs @@ -28,7 +28,7 @@ use crate::{ }; use alloy_json_rpc::RpcError; use alloy_network::{AnyNetwork, Ethereum, Network}; -use alloy_transport::{Transport, TransportResult}; +use alloy_transport::TransportResult; use async_trait::async_trait; use futures_utils_wasm::impl_future; use std::marker::PhantomData; @@ -167,14 +167,11 @@ pub trait TxFiller: Clone + Send + Sync + std::fmt::Debug fn fill_sync(&self, tx: &mut SendableTx); /// Prepares fillable properties, potentially by making an RPC request. - fn prepare( + fn prepare>( &self, provider: &P, tx: &N::TransactionRequest, - ) -> impl_future!(>) - where - P: Provider, - T: Transport + Clone; + ) -> impl_future!(>); /// Fills in the transaction request with the fillable properties. fn fill( @@ -184,14 +181,13 @@ pub trait TxFiller: Clone + Send + Sync + std::fmt::Debug ) -> impl_future!(>>); /// Prepares and fills the transaction request with the fillable properties. - fn prepare_and_fill( + fn prepare_and_fill

( &self, provider: &P, tx: SendableTx, ) -> impl_future!(>>) where - P: Provider, - T: Transport + Clone, + P: Provider, { async move { if tx.is_envelope() { @@ -218,23 +214,21 @@ pub trait TxFiller: Clone + Send + Sync + std::fmt::Debug /// /// [`ProviderBuilder::filler`]: crate::ProviderBuilder::filler #[derive(Clone, Debug)] -pub struct FillProvider +pub struct FillProvider where F: TxFiller, - P: Provider, - T: Transport + Clone, + P: Provider, N: Network, { pub(crate) inner: P, pub(crate) filler: F, - _pd: PhantomData (T, N)>, + _pd: PhantomData N>, } -impl FillProvider +impl FillProvider where F: TxFiller, - P: Provider, - T: Transport + Clone, + P: Provider, N: Network, { /// Creates a new `FillProvider` with the given filler and inner provider. @@ -246,7 +240,7 @@ where pub fn join_with>( self, other: Other, - ) -> FillProvider, P, T, N> { + ) -> FillProvider, P, N> { self.filler.join_with(other).layer(self.inner) } @@ -278,21 +272,20 @@ where #[cfg_attr(target_arch = "wasm32", async_trait(?Send))] #[cfg_attr(not(target_arch = "wasm32"), async_trait)] -impl Provider for FillProvider +impl Provider for FillProvider where F: TxFiller, - P: Provider, - T: Transport + Clone, + P: Provider, N: Network, { - fn root(&self) -> &RootProvider { + fn root(&self) -> &RootProvider { self.inner.root() } async fn send_transaction_internal( &self, mut tx: SendableTx, - ) -> TransportResult> { + ) -> TransportResult> { tx = self.fill_inner(tx).await?; if let Some(builder) = tx.as_builder() { @@ -323,13 +316,7 @@ impl RecommendedFillers for Ethereum { JoinFill>>; fn recommended_fillers() -> Self::RecommendedFillers { - JoinFill::new( - GasFiller, - JoinFill::new( - BlobGasFiller, - JoinFill::new(NonceFiller::default(), ChainIdFiller::default()), - ), - ) + Default::default() } } @@ -338,12 +325,6 @@ impl RecommendedFillers for AnyNetwork { JoinFill>>; fn recommended_fillers() -> Self::RecommendedFillers { - JoinFill::new( - GasFiller, - JoinFill::new( - BlobGasFiller, - JoinFill::new(NonceFiller::default(), ChainIdFiller::default()), - ), - ) + Default::default() } } diff --git a/crates/provider/src/fillers/nonce.rs b/crates/provider/src/fillers/nonce.rs index 2145bc35356..b52ea2c442e 100644 --- a/crates/provider/src/fillers/nonce.rs +++ b/crates/provider/src/fillers/nonce.rs @@ -5,7 +5,7 @@ use crate::{ }; use alloy_network::{Network, TransactionBuilder}; use alloy_primitives::Address; -use alloy_transport::{Transport, TransportResult}; +use alloy_transport::TransportResult; use async_trait::async_trait; use dashmap::DashMap; use futures::lock::Mutex; @@ -16,11 +16,10 @@ use std::sync::Arc; #[cfg_attr(not(target_arch = "wasm32"), async_trait)] pub trait NonceManager: Clone + Send + Sync + std::fmt::Debug { /// Get the next nonce for the given account. - async fn get_next_nonce(&self, provider: &P, address: Address) -> TransportResult + async fn get_next_nonce(&self, provider: &P, address: Address) -> TransportResult where - P: Provider, - N: Network, - T: Transport + Clone; + P: Provider, + N: Network; } /// This [`NonceManager`] implementation will fetch the transaction count for any new account it @@ -36,11 +35,10 @@ pub struct SimpleNonceManager; #[cfg_attr(target_arch = "wasm32", async_trait(?Send))] #[cfg_attr(not(target_arch = "wasm32"), async_trait)] impl NonceManager for SimpleNonceManager { - async fn get_next_nonce(&self, provider: &P, address: Address) -> TransportResult + async fn get_next_nonce(&self, provider: &P, address: Address) -> TransportResult where - P: Provider, + P: Provider, N: Network, - T: Transport + Clone, { provider.get_transaction_count(address).pending().await } @@ -62,11 +60,10 @@ pub struct CachedNonceManager { #[cfg_attr(target_arch = "wasm32", async_trait(?Send))] #[cfg_attr(not(target_arch = "wasm32"), async_trait)] impl NonceManager for CachedNonceManager { - async fn get_next_nonce(&self, provider: &P, address: Address) -> TransportResult + async fn get_next_nonce(&self, provider: &P, address: Address) -> TransportResult where - P: Provider, + P: Provider, N: Network, - T: Transport + Clone, { // Use `u64::MAX` as a sentinel value to indicate that the nonce has not been fetched yet. const NONE: u64 = u64::MAX; @@ -143,14 +140,13 @@ impl TxFiller for NonceFiller { fn fill_sync(&self, _tx: &mut SendableTx) {} - async fn prepare( + async fn prepare

( &self, provider: &P, tx: &N::TransactionRequest, ) -> TransportResult where - P: Provider, - T: Transport + Clone, + P: Provider, { let from = tx.from().expect("checked by 'ready()'"); self.nonce_manager.get_next_nonce(provider, from).await @@ -176,15 +172,14 @@ mod tests { use alloy_primitives::{address, U256}; use alloy_rpc_types_eth::TransactionRequest; - async fn check_nonces( + async fn check_nonces( filler: &NonceFiller, provider: &P, address: Address, start: u64, ) where - P: Provider, + P: Provider, N: Network, - T: Transport + Clone, M: NonceManager, { for i in start..start + 5 { diff --git a/crates/provider/src/fillers/wallet.rs b/crates/provider/src/fillers/wallet.rs index 81dd23e3a36..b5314ac91f2 100644 --- a/crates/provider/src/fillers/wallet.rs +++ b/crates/provider/src/fillers/wallet.rs @@ -1,7 +1,7 @@ use crate::{provider::SendableTx, Provider}; use alloy_json_rpc::RpcError; use alloy_network::{Network, NetworkWallet, TransactionBuilder}; -use alloy_transport::{Transport, TransportResult}; +use alloy_transport::TransportResult; use super::{FillerControlFlow, TxFiller}; @@ -76,14 +76,13 @@ where } } - async fn prepare( + async fn prepare

( &self, _provider: &P, _tx: &::TransactionRequest, ) -> TransportResult where - P: Provider, - T: Transport + Clone, + P: Provider, { Ok(()) } diff --git a/crates/provider/src/heart.rs b/crates/provider/src/heart.rs index 76ca4c20611..d57f034ace5 100644 --- a/crates/provider/src/heart.rs +++ b/crates/provider/src/heart.rs @@ -8,7 +8,7 @@ use alloy_primitives::{ map::{B256HashMap, B256HashSet}, TxHash, B256, }; -use alloy_transport::{utils::Spawnable, Transport, TransportError}; +use alloy_transport::{utils::Spawnable, TransportError}; use futures::{stream::StreamExt, FutureExt, Stream}; use std::{ collections::{BTreeMap, VecDeque}, @@ -83,22 +83,19 @@ pub enum PendingTransactionError { #[must_use = "this type does nothing unless you call `register`, `watch` or `get_receipt`"] #[derive(Debug)] #[doc(alias = "PendingTxBuilder")] -pub struct PendingTransactionBuilder { +pub struct PendingTransactionBuilder { config: PendingTransactionConfig, - provider: RootProvider, + provider: RootProvider, } -impl PendingTransactionBuilder { +impl PendingTransactionBuilder { /// Creates a new pending transaction builder. - pub const fn new(provider: RootProvider, tx_hash: TxHash) -> Self { + pub const fn new(provider: RootProvider, tx_hash: TxHash) -> Self { Self::from_config(provider, PendingTransactionConfig::new(tx_hash)) } /// Creates a new pending transaction builder from the given configuration. - pub const fn from_config( - provider: RootProvider, - config: PendingTransactionConfig, - ) -> Self { + pub const fn from_config(provider: RootProvider, config: PendingTransactionConfig) -> Self { Self { config, provider } } @@ -113,12 +110,12 @@ impl PendingTransactionBuilder { } /// Returns the provider. - pub const fn provider(&self) -> &RootProvider { + pub const fn provider(&self) -> &RootProvider { &self.provider } /// Consumes this builder, returning the provider and the configuration. - pub fn split(self) -> (RootProvider, PendingTransactionConfig) { + pub fn split(self) -> (RootProvider, PendingTransactionConfig) { (self.provider, self.config) } @@ -324,10 +321,10 @@ impl PendingTransactionConfig { } /// Wraps this configuration with a provider to expose watching methods. - pub const fn with_provider( + pub const fn with_provider( self, - provider: RootProvider, - ) -> PendingTransactionBuilder { + provider: RootProvider, + ) -> PendingTransactionBuilder { PendingTransactionBuilder::from_config(provider, self) } } diff --git a/crates/provider/src/layers/anvil.rs b/crates/provider/src/layers/anvil.rs index 3f512b67d17..2f92b54c9cc 100644 --- a/crates/provider/src/layers/anvil.rs +++ b/crates/provider/src/layers/anvil.rs @@ -1,11 +1,7 @@ use alloy_network::Ethereum; use alloy_node_bindings::{Anvil, AnvilInstance}; -use alloy_transport::Transport; use reqwest::Url; -use std::{ - marker::PhantomData, - sync::{Arc, OnceLock}, -}; +use std::sync::{Arc, OnceLock}; use crate::{Provider, ProviderLayer, RootProvider}; @@ -44,12 +40,11 @@ impl From for AnvilLayer { } } -impl ProviderLayer for AnvilLayer +impl

ProviderLayer for AnvilLayer where - P: Provider, - T: Transport + Clone, + P: Provider, { - type Provider = AnvilProvider; + type Provider = AnvilProvider

; fn layer(&self, inner: P) -> Self::Provider { let anvil = self.instance(); @@ -60,31 +55,29 @@ where /// A provider that wraps an [`AnvilInstance`], preventing the instance from /// being dropped while the provider is in use. #[derive(Clone, Debug)] -pub struct AnvilProvider { +pub struct AnvilProvider

{ inner: P, _anvil: Arc, - _pd: PhantomData T>, } -impl AnvilProvider +impl

AnvilProvider

where - P: Provider, - T: Transport + Clone, + P: Provider, { /// Creates a new `AnvilProvider` with the given inner provider and anvil /// instance. + #[allow(clippy::missing_const_for_fn)] pub fn new(inner: P, _anvil: Arc) -> Self { - Self { inner, _anvil, _pd: PhantomData } + Self { inner, _anvil } } } -impl Provider for AnvilProvider +impl

Provider for AnvilProvider

where - P: Provider, - T: Transport + Clone, + P: Provider, { #[inline(always)] - fn root(&self) -> &RootProvider { + fn root(&self) -> &RootProvider { self.inner.root() } } diff --git a/crates/provider/src/layers/cache.rs b/crates/provider/src/layers/cache.rs index 0538ecd5ae6..d0813f1c4cf 100644 --- a/crates/provider/src/layers/cache.rs +++ b/crates/provider/src/layers/cache.rs @@ -8,7 +8,7 @@ use alloy_primitives::{ use alloy_rpc_types_eth::{ BlockNumberOrTag, BlockTransactionsKind, EIP1186AccountProofResponse, Filter, Log, }; -use alloy_transport::{Transport, TransportErrorKind, TransportResult}; +use alloy_transport::{TransportErrorKind, TransportResult}; use parking_lot::RwLock; use schnellru::{ByLength, LruMap}; use serde::{Deserialize, Serialize}; @@ -45,13 +45,12 @@ impl CacheLayer { } } -impl ProviderLayer for CacheLayer +impl ProviderLayer for CacheLayer where - P: Provider, - T: Transport + Clone, + P: Provider, N: Network, { - type Provider = CacheProvider; + type Provider = CacheProvider; fn layer(&self, inner: P) -> Self::Provider { CacheProvider::new(inner, self.cache()) @@ -66,19 +65,18 @@ where /// to the provider interface, allowing users to save the cache to disk and load it /// from there on demand. #[derive(Debug, Clone)] -pub struct CacheProvider { +pub struct CacheProvider { /// Inner provider. inner: P, /// In-memory LRU cache, mapping requests to responses. cache: SharedCache, /// Phantom data - _pd: PhantomData<(T, N)>, + _pd: PhantomData, } -impl CacheProvider +impl CacheProvider where - P: Provider, - T: Transport + Clone, + P: Provider, N: Network, { /// Instantiate a new cache provider. @@ -142,14 +140,13 @@ macro_rules! cache_rpc_call_with_block { #[cfg_attr(target_arch = "wasm32", async_trait::async_trait(?Send))] #[cfg_attr(not(target_arch = "wasm32"), async_trait::async_trait)] -impl Provider for CacheProvider +impl Provider for CacheProvider where - P: Provider, - T: Transport + Clone, + P: Provider, N: Network, { #[inline(always)] - fn root(&self) -> &RootProvider { + fn root(&self) -> &RootProvider { self.inner.root() } @@ -186,7 +183,7 @@ where fn get_block_receipts( &self, block: BlockId, - ) -> ProviderCall>> { + ) -> ProviderCall<(BlockId,), Option>> { let req = RequestType::new("eth_getBlockReceipts", (block,)); let redirect = @@ -223,7 +220,7 @@ where })) } - fn get_code_at(&self, address: Address) -> RpcWithBlock { + fn get_code_at(&self, address: Address) -> RpcWithBlock { let client = self.inner.weak_client(); let cache = self.cache.clone(); RpcWithBlock::new_provider(move |block_id| { @@ -257,7 +254,7 @@ where &self, address: Address, keys: Vec, - ) -> RpcWithBlock), EIP1186AccountProofResponse> { + ) -> RpcWithBlock<(Address, Vec), EIP1186AccountProofResponse> { let client = self.inner.weak_client(); let cache = self.cache.clone(); RpcWithBlock::new_provider(move |block_id| { @@ -271,7 +268,7 @@ where &self, address: Address, key: U256, - ) -> RpcWithBlock { + ) -> RpcWithBlock<(Address, U256), StorageValue> { let client = self.inner.weak_client(); let cache = self.cache.clone(); RpcWithBlock::new_provider(move |block_id| { @@ -283,7 +280,7 @@ where fn get_transaction_by_hash( &self, hash: TxHash, - ) -> ProviderCall> { + ) -> ProviderCall<(TxHash,), Option> { let req = RequestType::new("eth_getTransactionByHash", (hash,)); let params_hash = req.params_hash().ok(); @@ -309,10 +306,7 @@ where })) } - fn get_raw_transaction_by_hash( - &self, - hash: TxHash, - ) -> ProviderCall> { + fn get_raw_transaction_by_hash(&self, hash: TxHash) -> ProviderCall<(TxHash,), Option> { let req = RequestType::new("eth_getRawTransactionByHash", (hash,)); let params_hash = req.params_hash().ok(); @@ -340,7 +334,7 @@ where })) } - fn get_transaction_count(&self, address: Address) -> RpcWithBlock { + fn get_transaction_count(&self, address: Address) -> RpcWithBlock { let client = self.inner.weak_client(); let cache = self.cache.clone(); RpcWithBlock::new_provider(move |block_id| { @@ -353,7 +347,7 @@ where fn get_transaction_receipt( &self, hash: TxHash, - ) -> ProviderCall> { + ) -> ProviderCall<(TxHash,), Option> { let req = RequestType::new("eth_getTransactionReceipt", (hash,)); let params_hash = req.params_hash().ok(); diff --git a/crates/provider/src/layers/chain.rs b/crates/provider/src/layers/chain.rs index 4f6e854068f..9e21838c753 100644 --- a/crates/provider/src/layers/chain.rs +++ b/crates/provider/src/layers/chain.rs @@ -1,6 +1,5 @@ use alloy_chains::NamedChain; use alloy_network::Ethereum; -use alloy_transport::Transport; use std::time::Duration; use crate::{Provider, ProviderLayer}; @@ -25,10 +24,9 @@ impl From for ChainLayer { } } -impl ProviderLayer for ChainLayer +impl

ProviderLayer for ChainLayer where - P: Provider, - T: Transport + Clone, + P: Provider, { type Provider = P; diff --git a/crates/provider/src/lib.rs b/crates/provider/src/lib.rs index dd2c09c3d51..269f276e0de 100644 --- a/crates/provider/src/lib.rs +++ b/crates/provider/src/lib.rs @@ -6,21 +6,25 @@ #![cfg_attr(not(test), warn(unused_crate_dependencies))] #![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] +// For features. +#[cfg(any(feature = "reqwest", feature = "hyper"))] +use alloy_transport_http as _; + /// Type alias for a [`RootProvider`] using the [`Http`] transport and a /// reqwest client. /// /// [`Http`]: alloy_transport_http::Http #[cfg(any(test, feature = "reqwest"))] -pub type ReqwestProvider = - crate::RootProvider, N>; +#[deprecated(since = "0.9.0", note = "use `RootProvider` instead")] +pub type ReqwestProvider = crate::RootProvider; /// Type alias for a [`RootProvider`] using the [`Http`] transport and a hyper /// client. /// /// [`Http`]: alloy_transport_http::Http #[cfg(feature = "hyper")] -pub type HyperProvider = - crate::RootProvider; +#[deprecated(since = "0.9.0", note = "use `RootProvider` instead")] +pub type HyperProvider = crate::RootProvider; #[macro_use] extern crate tracing; diff --git a/crates/provider/src/provider/caller.rs b/crates/provider/src/provider/caller.rs index da14eb2f64c..78cebeb0946 100644 --- a/crates/provider/src/provider/caller.rs +++ b/crates/provider/src/provider/caller.rs @@ -3,12 +3,11 @@ use crate::ProviderCall; use alloy_json_rpc::RpcReturn; use alloy_network::Network; use alloy_rpc_client::WeakClient; -use alloy_transport::{Transport, TransportErrorKind, TransportResult}; +use alloy_transport::{TransportErrorKind, TransportResult}; /// Trait that helpes convert `EthCall` into a `ProviderCall`. -pub trait Caller: Send + Sync +pub trait Caller: Send + Sync where - T: Transport + Clone, N: Network, Resp: RpcReturn, { @@ -18,42 +17,41 @@ where fn call( &self, params: EthCallParams<'_, N>, - ) -> TransportResult, Resp>>; + ) -> TransportResult, Resp>>; /// Method that needs to be implemented for estimating gas using "eth_estimateGas" for the /// transaction. fn estimate_gas( &self, params: EthCallParams<'_, N>, - ) -> TransportResult, Resp>>; + ) -> TransportResult, Resp>>; } -impl Caller for WeakClient +impl Caller for WeakClient where - T: Transport + Clone, N: Network, Resp: RpcReturn, { fn call( &self, params: EthCallParams<'_, N>, - ) -> TransportResult, Resp>> { + ) -> TransportResult, Resp>> { provider_rpc_call(self, "eth_call", params) } fn estimate_gas( &self, params: EthCallParams<'_, N>, - ) -> TransportResult, Resp>> { + ) -> TransportResult, Resp>> { provider_rpc_call(self, "eth_estimateGas", params) } } -fn provider_rpc_call( - client: &WeakClient, +fn provider_rpc_call( + client: &WeakClient, method: &'static str, params: EthCallParams<'_, N>, -) -> TransportResult, Resp>> { +) -> TransportResult, Resp>> { let client = client.upgrade().ok_or_else(TransportErrorKind::backend_gone)?; let rpc_call = client.request(method, params.into_owned()); diff --git a/crates/provider/src/provider/eth_call.rs b/crates/provider/src/provider/eth_call.rs index c9d41fa6a11..6934f8cf9d6 100644 --- a/crates/provider/src/provider/eth_call.rs +++ b/crates/provider/src/provider/eth_call.rs @@ -2,7 +2,7 @@ use alloy_eips::BlockId; use alloy_json_rpc::RpcReturn; use alloy_network::Network; use alloy_rpc_types_eth::state::StateOverride; -use alloy_transport::{Transport, TransportResult}; +use alloy_transport::TransportResult; use futures::FutureExt; use serde::ser::SerializeSeq; use std::{borrow::Cow, future::Future, marker::PhantomData, sync::Arc, task::Poll}; @@ -86,26 +86,24 @@ impl serde::Serialize for EthCallParams<'_, N> { #[doc(hidden)] // Not public API. #[allow(unnameable_types)] #[pin_project::pin_project] -pub struct EthCallFut<'req, T, N, Resp, Output, Map> +pub struct EthCallFut<'req, N, Resp, Output, Map> where - T: Transport + Clone, N: Network, Resp: RpcReturn, Output: 'static, Map: Fn(Resp) -> Output, { - inner: EthCallFutInner<'req, T, N, Resp, Output, Map>, + inner: EthCallFutInner<'req, N, Resp, Output, Map>, } -enum EthCallFutInner<'req, T, N, Resp, Output, Map> +enum EthCallFutInner<'req, N, Resp, Output, Map> where - T: Transport + Clone, N: Network, Resp: RpcReturn, Map: Fn(Resp) -> Output, { Preparing { - caller: Arc>, + caller: Arc>, data: &'req N::TransactionRequest, overrides: Option<&'req StateOverride>, block: Option, @@ -114,14 +112,13 @@ where }, Running { map: Map, - fut: ProviderCall, Resp>, + fut: ProviderCall, Resp>, }, Polling, } -impl core::fmt::Debug for EthCallFutInner<'_, T, N, Resp, Output, Map> +impl core::fmt::Debug for EthCallFutInner<'_, N, Resp, Output, Map> where - T: Transport + Clone, N: Network, Resp: RpcReturn, Output: 'static, @@ -142,9 +139,8 @@ where } } -impl EthCallFut<'_, T, N, Resp, Output, Map> +impl EthCallFut<'_, N, Resp, Output, Map> where - T: Transport + Clone, N: Network, Resp: RpcReturn, Output: 'static, @@ -190,9 +186,8 @@ where } } -impl Future for EthCallFut<'_, T, N, Resp, Output, Map> +impl Future for EthCallFut<'_, N, Resp, Output, Map> where - T: Transport + Clone, N: Network, Resp: RpcReturn, Output: 'static, @@ -221,14 +216,13 @@ where /// [`Provider::call`]: crate::Provider::call #[must_use = "EthCall must be awaited to execute the call"] #[derive(Clone)] -pub struct EthCall<'req, T, N, Resp, Output = Resp, Map = fn(Resp) -> Output> +pub struct EthCall<'req, N, Resp, Output = Resp, Map = fn(Resp) -> Output> where - T: Transport + Clone, N: Network, Resp: RpcReturn, Map: Fn(Resp) -> Output, { - caller: Arc>, + caller: Arc>, data: &'req N::TransactionRequest, overrides: Option<&'req StateOverride>, block: Option, @@ -237,9 +231,8 @@ where _pd: PhantomData (Resp, Output)>, } -impl core::fmt::Debug for EthCall<'_, T, N, Resp> +impl core::fmt::Debug for EthCall<'_, N, Resp> where - T: Transport + Clone, N: Network, Resp: RpcReturn, { @@ -253,17 +246,13 @@ where } } -impl<'req, T, N, Resp> EthCall<'req, T, N, Resp> +impl<'req, N, Resp> EthCall<'req, N, Resp> where - T: Transport + Clone, N: Network, Resp: RpcReturn, { /// Create a new CallBuilder. - pub fn new( - caller: impl Caller + 'static, - data: &'req N::TransactionRequest, - ) -> Self { + pub fn new(caller: impl Caller + 'static, data: &'req N::TransactionRequest) -> Self { Self { caller: Arc::new(caller), data, @@ -277,7 +266,7 @@ where /// Create new EthCall for gas estimates. pub fn gas_estimate( - caller: impl Caller + 'static, + caller: impl Caller + 'static, data: &'req N::TransactionRequest, ) -> Self { Self { @@ -292,9 +281,8 @@ where } } -impl<'req, T, N, Resp, Output, Map> EthCall<'req, T, N, Resp, Output, Map> +impl<'req, N, Resp, Output, Map> EthCall<'req, N, Resp, Output, Map> where - T: Transport + Clone, N: Network, Resp: RpcReturn, Map: Fn(Resp) -> Output, @@ -313,7 +301,7 @@ where pub fn map_resp( self, map: NewMap, - ) -> EthCall<'req, T, N, Resp, NewOutput, NewMap> + ) -> EthCall<'req, N, Resp, NewOutput, NewMap> where NewMap: Fn(Resp) -> NewOutput, { @@ -341,10 +329,8 @@ where } } -impl<'req, T, N, Resp, Output, Map> std::future::IntoFuture - for EthCall<'req, T, N, Resp, Output, Map> +impl<'req, N, Resp, Output, Map> std::future::IntoFuture for EthCall<'req, N, Resp, Output, Map> where - T: Transport + Clone, N: Network, Resp: RpcReturn, Output: 'static, @@ -352,7 +338,7 @@ where { type Output = TransportResult; - type IntoFuture = EthCallFut<'req, T, N, Resp, Output, Map>; + type IntoFuture = EthCallFut<'req, N, Resp, Output, Map>; fn into_future(self) -> Self::IntoFuture { EthCallFut { diff --git a/crates/provider/src/provider/prov_call.rs b/crates/provider/src/provider/prov_call.rs index e1cc40364ed..e6e2bc928fa 100644 --- a/crates/provider/src/provider/prov_call.rs +++ b/crates/provider/src/provider/prov_call.rs @@ -1,6 +1,6 @@ use alloy_json_rpc::{RpcParam, RpcReturn}; use alloy_rpc_client::{RpcCall, Waiter}; -use alloy_transport::{Transport, TransportResult}; +use alloy_transport::TransportResult; use futures::FutureExt; use pin_project::pin_project; use serde_json::value::RawValue; @@ -22,15 +22,14 @@ use tokio::sync::oneshot; /// /// [`Provider`]: crate::Provider #[pin_project(project = ProviderCallProj)] -pub enum ProviderCall Output> +pub enum ProviderCall Output> where - Conn: Transport + Clone, Params: RpcParam, Resp: RpcReturn, Map: Fn(Resp) -> Output, { /// An underlying call to an RPC server. - RpcCall(RpcCall), + RpcCall(RpcCall), /// A waiter for a batched call to a remote RPC server. Waiter(Waiter), /// A boxed future. @@ -39,9 +38,8 @@ where Ready(Option>), } -impl ProviderCall +impl ProviderCall where - Conn: Transport + Clone, Params: RpcParam, Resp: RpcReturn, Map: Fn(Resp) -> Output, @@ -57,7 +55,7 @@ where } /// Fallible cast to [`RpcCall`] - pub const fn as_rpc_call(&self) -> Option<&RpcCall> { + pub const fn as_rpc_call(&self) -> Option<&RpcCall> { match self { Self::RpcCall(call) => Some(call), _ => None, @@ -65,7 +63,7 @@ where } /// Fallible cast to mutable [`RpcCall`] - pub fn as_mut_rpc_call(&mut self) -> Option<&mut RpcCall> { + pub fn as_mut_rpc_call(&mut self) -> Option<&mut RpcCall> { match self { Self::RpcCall(call) => Some(call), _ => None, @@ -144,7 +142,7 @@ where pub fn map_resp( self, map: NewMap, - ) -> Result, Self> + ) -> Result, Self> where NewMap: Fn(Resp) -> NewOutput + Clone, { @@ -156,9 +154,8 @@ where } } -impl ProviderCall +impl ProviderCall<&Params, Resp, Output, Map> where - Conn: Transport + Clone, Params: RpcParam + ToOwned, Params::Owned: RpcParam, Resp: RpcReturn, @@ -169,7 +166,7 @@ where /// # Panics /// /// Panics if called after the request has been polled. - pub fn into_owned_params(self) -> ProviderCall { + pub fn into_owned_params(self) -> ProviderCall { match self { Self::RpcCall(call) => ProviderCall::RpcCall(call.into_owned_params()), _ => panic!(), @@ -177,9 +174,8 @@ where } } -impl std::fmt::Debug for ProviderCall +impl std::fmt::Debug for ProviderCall where - Conn: Transport + Clone, Params: RpcParam, Resp: RpcReturn, { @@ -193,23 +189,20 @@ where } } -impl From> - for ProviderCall +impl From> + for ProviderCall where - Conn: Transport + Clone, Params: RpcParam, Resp: RpcReturn, Map: Fn(Resp) -> Output, { - fn from(call: RpcCall) -> Self { + fn from(call: RpcCall) -> Self { Self::RpcCall(call) } } -impl From> - for ProviderCall Resp> +impl From> for ProviderCall Resp> where - Conn: Transport + Clone, Params: RpcParam, Resp: RpcReturn, { @@ -218,11 +211,9 @@ where } } -impl - From> + Send>>> - for ProviderCall +impl From> + Send>>> + for ProviderCall where - Conn: Transport + Clone, Params: RpcParam, Resp: RpcReturn, Map: Fn(Resp) -> Output, @@ -232,10 +223,9 @@ where } } -impl From>>> - for ProviderCall +impl From>>> + for ProviderCall where - Conn: Transport + Clone, Params: RpcParam, Resp: RpcReturn, { @@ -244,9 +234,8 @@ where } } -impl Future for ProviderCall +impl Future for ProviderCall where - Conn: Transport + Clone, Params: RpcParam, Resp: RpcReturn, Output: 'static, diff --git a/crates/provider/src/provider/root.rs b/crates/provider/src/provider/root.rs index 11e9ac369b0..0c929343e67 100644 --- a/crates/provider/src/provider/root.rs +++ b/crates/provider/src/provider/root.rs @@ -5,33 +5,30 @@ use crate::{ }; use alloy_network::{Ethereum, Network}; use alloy_rpc_client::{BuiltInConnectionString, ClientBuilder, ClientRef, RpcClient, WeakClient}; -use alloy_transport::{BoxTransport, BoxTransportConnect, Transport, TransportError}; +use alloy_transport::{TransportConnect, TransportError}; use std::{ fmt, marker::PhantomData, sync::{Arc, OnceLock}, }; -#[cfg(feature = "reqwest")] -use alloy_transport_http::Http; - #[cfg(feature = "pubsub")] use alloy_pubsub::{PubSubFrontend, Subscription}; /// The root provider manages the RPC client and the heartbeat. It is at the /// base of every provider stack. -pub struct RootProvider { +pub struct RootProvider { /// The inner state of the root provider. - pub(crate) inner: Arc>, + pub(crate) inner: Arc>, } -impl Clone for RootProvider { +impl Clone for RootProvider { fn clone(&self) -> Self { Self { inner: self.inner.clone() } } } -impl fmt::Debug for RootProvider { +impl fmt::Debug for RootProvider { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("RootProvider").field("client", &self.inner.client).finish_non_exhaustive() } @@ -43,45 +40,52 @@ pub fn builder() -> ProviderBuilder { ProviderBuilder::default() } -#[cfg(feature = "reqwest")] -impl RootProvider, N> { +impl RootProvider { /// Creates a new HTTP root provider from the given URL. + #[cfg(feature = "reqwest")] pub fn new_http(url: url::Url) -> Self { Self::new(RpcClient::new_http(url)) } -} -impl RootProvider { /// Creates a new root provider from the given RPC client. - pub fn new(client: RpcClient) -> Self { + pub fn new(client: RpcClient) -> Self { Self { inner: Arc::new(RootProviderInner::new(client)) } } -} -impl RootProvider { - /// Connects to a boxed transport with the given connector. - pub async fn connect_boxed(conn: C) -> Result { - let client = ClientBuilder::default().connect_boxed(conn).await?; - Ok(Self::new(client)) + /// Creates a new root provider from the provided string. + /// + /// See [`BuiltInConnectionString`] for more information. + pub async fn connect(s: &str) -> Result { + Self::connect_with(s.parse::()?).await } /// Creates a new root provider from the provided connection details. + #[deprecated(since = "0.9.0", note = "use `connect` instead")] pub async fn connect_builtin(s: &str) -> Result { - let conn: BuiltInConnectionString = s.parse()?; + Self::connect(s).await + } - let client = ClientBuilder::default().connect_boxed(conn).await?; - Ok(Self::new(client)) + /// Connects to a transport with the given connector. + pub async fn connect_with(conn: C) -> Result { + ClientBuilder::default().connect_with(conn).await.map(Self::new) + } + + /// Connects to a boxed transport with the given connector. + #[deprecated( + since = "0.9.0", + note = "`RootProvider` is now always boxed, use `connect_with` instead" + )] + pub async fn connect_boxed(conn: C) -> Result { + Self::connect_with(conn).await } } -impl RootProvider { +impl RootProvider { /// Boxes the inner client. - /// - /// This will create a new provider if this instance is not the only reference to the inner - /// client. - pub fn boxed(self) -> RootProvider { - let inner = Arc::unwrap_or_clone(self.inner); - RootProvider { inner: Arc::new(inner.boxed()) } + #[deprecated(since = "0.9.0", note = "`RootProvider` is now always boxed")] + #[allow(clippy::missing_const_for_fn)] + pub fn boxed(self) -> Self { + self } /// Gets the subscription corresponding to the given RPC subscription ID. @@ -110,7 +114,7 @@ impl RootProvider { #[inline] pub(crate) fn get_heart(&self) -> &HeartbeatHandle { self.inner.heart.get_or_init(|| { - let new_blocks = NewBlocks::::new(self.inner.weak_client()); + let new_blocks = NewBlocks::::new(self.inner.weak_client()); let stream = new_blocks.into_stream(); Heartbeat::new(Box::pin(stream)).spawn() }) @@ -119,34 +123,28 @@ impl RootProvider { /// The root provider manages the RPC client and the heartbeat. It is at the /// base of every provider stack. -pub(crate) struct RootProviderInner { - client: RpcClient, +pub(crate) struct RootProviderInner { + client: RpcClient, heart: OnceLock>, _network: PhantomData, } -impl Clone for RootProviderInner { +impl Clone for RootProviderInner { fn clone(&self) -> Self { Self { client: self.client.clone(), heart: self.heart.clone(), _network: PhantomData } } } -impl RootProviderInner { - pub(crate) fn new(client: RpcClient) -> Self { +impl RootProviderInner { + pub(crate) fn new(client: RpcClient) -> Self { Self { client, heart: Default::default(), _network: PhantomData } } - pub(crate) fn weak_client(&self) -> WeakClient { + pub(crate) fn weak_client(&self) -> WeakClient { self.client.get_weak() } - pub(crate) fn client_ref(&self) -> ClientRef<'_, T> { + pub(crate) fn client_ref(&self) -> ClientRef<'_> { self.client.get_ref() } } - -impl RootProviderInner { - fn boxed(self) -> RootProviderInner { - RootProviderInner { client: self.client.boxed(), heart: self.heart, _network: PhantomData } - } -} diff --git a/crates/provider/src/provider/trait.rs b/crates/provider/src/provider/trait.rs index 74420f10e2c..bc065c2ce3f 100644 --- a/crates/provider/src/provider/trait.rs +++ b/crates/provider/src/provider/trait.rs @@ -23,14 +23,14 @@ use alloy_rpc_types_eth::{ AccessListResult, BlockId, BlockNumberOrTag, EIP1186AccountProofResponse, FeeHistory, Filter, FilterChanges, Index, Log, SyncStatus, }; -use alloy_transport::{BoxTransport, Transport, TransportResult}; +use alloy_transport::TransportResult; use serde_json::value::RawValue; use std::borrow::Cow; /// A task that polls the provider with `eth_getFilterChanges`, returning a list of `R`. /// /// See [`PollerBuilder`] for more details. -pub type FilterPollerBuilder = PollerBuilder>; +pub type FilterPollerBuilder = PollerBuilder<(U256,), Vec>; // todo: adjust docs // todo: reorder @@ -70,11 +70,9 @@ pub type FilterPollerBuilder = PollerBuilder>; #[cfg_attr(target_arch = "wasm32", async_trait::async_trait(?Send))] #[cfg_attr(not(target_arch = "wasm32"), async_trait::async_trait)] #[auto_impl::auto_impl(&, &mut, Rc, Arc, Box)] -pub trait Provider: - Send + Sync -{ +pub trait Provider: Send + Sync { /// Returns the root provider. - fn root(&self) -> &RootProvider; + fn root(&self) -> &RootProvider; /// Returns the [`ProviderBuilder`](crate::ProviderBuilder) to build on. fn builder() -> ProviderBuilder @@ -88,7 +86,7 @@ pub trait Provider: /// /// NOTE: this method should not be overridden. #[inline] - fn client(&self) -> ClientRef<'_, T> { + fn client(&self) -> ClientRef<'_> { self.root().client() } @@ -96,18 +94,18 @@ pub trait Provider: /// /// NOTE: this method should not be overridden. #[inline] - fn weak_client(&self) -> WeakClient { + fn weak_client(&self) -> WeakClient { self.root().weak_client() } /// Gets the accounts in the remote node. This is usually empty unless you're using a local /// node. - fn get_accounts(&self) -> ProviderCall> { + fn get_accounts(&self) -> ProviderCall> { self.client().request_noparams("eth_accounts").into() } /// Returns the base fee per blob gas (blob gas price) in wei. - fn get_blob_base_fee(&self) -> ProviderCall { + fn get_blob_base_fee(&self) -> ProviderCall { self.client() .request_noparams("eth_blobBaseFee") .map_resp(utils::convert_u128 as fn(U128) -> u128) @@ -115,7 +113,7 @@ pub trait Provider: } /// Get the last block number available. - fn get_block_number(&self) -> ProviderCall { + fn get_block_number(&self) -> ProviderCall { self.client() .request_noparams("eth_blockNumber") .map_resp(utils::convert_u64 as fn(U64) -> u64) @@ -139,7 +137,7 @@ pub trait Provider: /// # use alloy_eips::BlockId; /// # use alloy_rpc_types_eth::state::StateOverride; /// # use alloy_transport::BoxTransport; - /// # async fn example>( + /// # async fn example( /// # provider: P, /// # my_overrides: StateOverride /// # ) -> Result<(), Box> { @@ -151,7 +149,7 @@ pub trait Provider: /// ``` #[doc(alias = "eth_call")] #[doc(alias = "call_with_overrides")] - fn call<'req>(&self, tx: &'req N::TransactionRequest) -> EthCall<'req, T, N, Bytes> { + fn call<'req>(&self, tx: &'req N::TransactionRequest) -> EthCall<'req, N, Bytes> { EthCall::new(self.weak_client(), tx).block(BlockNumberOrTag::Pending.into()) } @@ -162,12 +160,12 @@ pub trait Provider: fn simulate<'req>( &self, payload: &'req SimulatePayload, - ) -> RpcWithBlock>> { + ) -> RpcWithBlock<&'req SimulatePayload, Vec>> { self.client().request("eth_simulateV1", payload).into() } /// Gets the chain ID. - fn get_chain_id(&self) -> ProviderCall { + fn get_chain_id(&self) -> ProviderCall { self.client() .request_noparams("eth_chainId") .map_resp(utils::convert_u64 as fn(U64) -> u64) @@ -180,7 +178,7 @@ pub trait Provider: fn create_access_list<'a>( &self, request: &'a N::TransactionRequest, - ) -> RpcWithBlock { + ) -> RpcWithBlock<&'a N::TransactionRequest, AccessListResult> { self.client().request("eth_createAccessList", request).into() } @@ -197,7 +195,7 @@ pub trait Provider: /// # Note /// /// Not all client implementations support state overrides for eth_estimateGas. - fn estimate_gas<'req>(&self, tx: &'req N::TransactionRequest) -> EthCall<'req, T, N, U64, u64> { + fn estimate_gas<'req>(&self, tx: &'req N::TransactionRequest) -> EthCall<'req, N, U64, u64> { EthCall::gas_estimate(self.weak_client(), tx) .block(BlockNumberOrTag::Pending.into()) .map_resp(utils::convert_u64) @@ -257,7 +255,7 @@ pub trait Provider: } /// Gets the current gas price in wei. - fn get_gas_price(&self) -> ProviderCall { + fn get_gas_price(&self) -> ProviderCall { self.client() .request_noparams("eth_gasPrice") .map_resp(utils::convert_u128 as fn(U128) -> u128) @@ -266,14 +264,14 @@ pub trait Provider: /// Retrieves account information ([Account](alloy_consensus::Account)) for the given [Address] /// at the particular [BlockId]. - fn get_account(&self, address: Address) -> RpcWithBlock { + fn get_account(&self, address: Address) -> RpcWithBlock { self.client().request("eth_getAccount", address).into() } /// Gets the balance of the account. /// /// Defaults to the latest block. See also [`RpcWithBlock::block_id`]. - fn get_balance(&self, address: Address) -> RpcWithBlock { + fn get_balance(&self, address: Address) -> RpcWithBlock { self.client().request("eth_getBalance", address).into() } @@ -369,12 +367,12 @@ pub trait Provider: fn get_block_receipts( &self, block: BlockId, - ) -> ProviderCall>> { + ) -> ProviderCall<(BlockId,), Option>> { self.client().request("eth_getBlockReceipts", (block,)).into() } /// Gets the bytecode located at the corresponding [Address]. - fn get_code_at(&self, address: Address) -> RpcWithBlock { + fn get_code_at(&self, address: Address) -> RpcWithBlock { self.client().request("eth_getCode", address).into() } @@ -400,7 +398,7 @@ pub trait Provider: /// # Ok(()) /// # } /// ``` - async fn watch_blocks(&self) -> TransportResult> { + async fn watch_blocks(&self) -> TransportResult> { let id = self.new_block_filter().await?; Ok(PollerBuilder::new(self.weak_client(), "eth_getFilterChanges", (id,))) } @@ -427,7 +425,7 @@ pub trait Provider: /// # Ok(()) /// # } /// ``` - async fn watch_pending_transactions(&self) -> TransportResult> { + async fn watch_pending_transactions(&self) -> TransportResult> { let id = self.new_pending_transactions_filter(false).await?; Ok(PollerBuilder::new(self.weak_client(), "eth_getFilterChanges", (id,))) } @@ -460,7 +458,7 @@ pub trait Provider: /// # Ok(()) /// # } /// ``` - async fn watch_logs(&self, filter: &Filter) -> TransportResult> { + async fn watch_logs(&self, filter: &Filter) -> TransportResult> { let id = self.new_filter(filter).await?; Ok(PollerBuilder::new(self.weak_client(), "eth_getFilterChanges", (id,))) } @@ -493,7 +491,7 @@ pub trait Provider: /// ``` async fn watch_full_pending_transactions( &self, - ) -> TransportResult> { + ) -> TransportResult> { let id = self.new_pending_transactions_filter(true).await?; Ok(PollerBuilder::new(self.weak_client(), "eth_getFilterChanges", (id,))) } @@ -552,7 +550,7 @@ pub trait Provider: &self, address: Address, keys: Vec, - ) -> RpcWithBlock), EIP1186AccountProofResponse> { + ) -> RpcWithBlock<(Address, Vec), EIP1186AccountProofResponse> { self.client().request("eth_getProof", (address, keys)).into() } @@ -561,7 +559,7 @@ pub trait Provider: &self, address: Address, key: U256, - ) -> RpcWithBlock { + ) -> RpcWithBlock<(Address, U256), StorageValue> { self.client().request("eth_getStorageAt", (address, key)).into() } @@ -569,7 +567,7 @@ pub trait Provider: fn get_transaction_by_hash( &self, hash: TxHash, - ) -> ProviderCall> { + ) -> ProviderCall<(TxHash,), Option> { self.client().request("eth_getTransactionByHash", (hash,)).into() } @@ -578,7 +576,7 @@ pub trait Provider: &self, block_hash: B256, index: usize, - ) -> ProviderCall> { + ) -> ProviderCall<(B256, Index), Option> { self.client() .request("eth_getTransactionByBlockHashAndIndex", (block_hash, Index(index))) .into() @@ -589,7 +587,7 @@ pub trait Provider: &self, block_hash: B256, index: usize, - ) -> ProviderCall> { + ) -> ProviderCall<(B256, Index), Option> { self.client() .request("eth_getRawTransactionByBlockHashAndIndex", (block_hash, Index(index))) .into() @@ -600,7 +598,7 @@ pub trait Provider: &self, block_number: BlockNumberOrTag, index: usize, - ) -> ProviderCall> { + ) -> ProviderCall<(BlockNumberOrTag, Index), Option> { self.client() .request("eth_getTransactionByBlockNumberAndIndex", (block_number, Index(index))) .into() @@ -611,7 +609,7 @@ pub trait Provider: &self, block_number: BlockNumberOrTag, index: usize, - ) -> ProviderCall> { + ) -> ProviderCall<(BlockNumberOrTag, Index), Option> { self.client() .request("eth_getRawTransactionByBlockNumberAndIndex", (block_number, Index(index))) .into() @@ -625,10 +623,7 @@ pub trait Provider: /// [TxEip4844](alloy_consensus::transaction::eip4844::TxEip4844). /// /// This can be decoded into [TxEnvelope](alloy_consensus::transaction::TxEnvelope). - fn get_raw_transaction_by_hash( - &self, - hash: TxHash, - ) -> ProviderCall> { + fn get_raw_transaction_by_hash(&self, hash: TxHash) -> ProviderCall<(TxHash,), Option> { self.client().request("eth_getRawTransactionByHash", (hash,)).into() } @@ -638,7 +633,7 @@ pub trait Provider: fn get_transaction_count( &self, address: Address, - ) -> RpcWithBlock u64> { + ) -> RpcWithBlock u64> { self.client() .request("eth_getTransactionCount", address) .map_resp(utils::convert_u64 as fn(U64) -> u64) @@ -649,7 +644,7 @@ pub trait Provider: fn get_transaction_receipt( &self, hash: TxHash, - ) -> ProviderCall> { + ) -> ProviderCall<(TxHash,), Option> { self.client().request("eth_getTransactionReceipt", (hash,)).into() } @@ -685,7 +680,7 @@ pub trait Provider: } /// Returns a suggestion for the current `maxPriorityFeePerGas` in wei. - fn get_max_priority_fee_per_gas(&self) -> ProviderCall { + fn get_max_priority_fee_per_gas(&self) -> ProviderCall { self.client() .request_noparams("eth_maxPriorityFeePerGas") .map_resp(utils::convert_u128 as fn(U128) -> u128) @@ -731,7 +726,7 @@ pub trait Provider: async fn send_raw_transaction( &self, encoded_tx: &[u8], - ) -> TransportResult> { + ) -> TransportResult> { let rlp_hex = hex::encode_prefixed(encoded_tx); let tx_hash = self.client().request("eth_sendRawTransaction", (rlp_hex,)).await?; Ok(PendingTransactionBuilder::new(self.root().clone(), tx_hash)) @@ -760,7 +755,7 @@ pub trait Provider: async fn send_transaction( &self, tx: N::TransactionRequest, - ) -> TransportResult> { + ) -> TransportResult> { self.send_transaction_internal(SendableTx::Builder(tx)).await } @@ -771,7 +766,7 @@ pub trait Provider: async fn send_tx_envelope( &self, tx: N::TxEnvelope, - ) -> TransportResult> { + ) -> TransportResult> { self.send_transaction_internal(SendableTx::Envelope(tx)).await } @@ -786,7 +781,7 @@ pub trait Provider: async fn send_transaction_internal( &self, tx: SendableTx, - ) -> TransportResult> { + ) -> TransportResult> { // Make sure to initialize heartbeat before we submit transaction, so that // we don't miss it if user will subscriber to it immediately after sending. let _handle = self.root().get_heart(); @@ -972,24 +967,24 @@ pub trait Provider: } /// Gets syncing info. - fn syncing(&self) -> ProviderCall { + fn syncing(&self) -> ProviderCall { self.client().request_noparams("eth_syncing").into() } /// Gets the client version. #[doc(alias = "web3_client_version")] - fn get_client_version(&self) -> ProviderCall { + fn get_client_version(&self) -> ProviderCall { self.client().request_noparams("web3_clientVersion").into() } /// Gets the `Keccak-256` hash of the given data. #[doc(alias = "web3_sha3")] - fn get_sha3(&self, data: &[u8]) -> ProviderCall { + fn get_sha3(&self, data: &[u8]) -> ProviderCall<(String,), B256> { self.client().request("web3_sha3", (hex::encode_prefixed(data),)).into() } /// Gets the network ID. Same as `eth_chainId`. - fn get_net_version(&self) -> ProviderCall { + fn get_net_version(&self) -> ProviderCall { self.client() .request_noparams("net_version") .map_resp(utils::convert_u64 as fn(U64) -> u64) @@ -1068,19 +1063,19 @@ pub trait Provider: #[cfg_attr(target_arch = "wasm32", async_trait::async_trait(?Send))] #[cfg_attr(not(target_arch = "wasm32"), async_trait::async_trait)] -impl Provider for RootProvider { +impl Provider for RootProvider { #[inline] fn root(&self) -> &Self { self } #[inline] - fn client(&self) -> ClientRef<'_, T> { + fn client(&self) -> ClientRef<'_> { self.inner.client_ref() } #[inline] - fn weak_client(&self) -> WeakClient { + fn weak_client(&self) -> WeakClient { self.inner.weak_client() } @@ -1141,8 +1136,7 @@ mod tests { #[tokio::test] async fn test_provider_builder() { - let provider = - RootProvider::::builder().with_recommended_fillers().on_anvil(); + let provider = RootProvider::builder().with_recommended_fillers().on_anvil(); let num = provider.get_block_number().await.unwrap(); assert_eq!(0, num); } @@ -1162,7 +1156,7 @@ mod tests { let rpc_client = alloy_rpc_client::RpcClient::new(hyper_t, true); - let provider = RootProvider::<_, Ethereum>::new(rpc_client); + let provider = RootProvider::::new(rpc_client); let num = provider.get_block_number().await.unwrap(); assert_eq!(0, num); } @@ -1247,7 +1241,7 @@ mod tests { let rpc_client = alloy_rpc_client::RpcClient::new(http_hyper, true); - let provider = RootProvider::<_, Ethereum>::new(rpc_client); + let provider = RootProvider::::new(rpc_client); let num = provider.get_block_number().await.unwrap(); assert_eq!(0, num); @@ -1256,7 +1250,7 @@ mod tests { let rpc_client = alloy_rpc_client::RpcClient::new(cloned_t, true); - let provider = RootProvider::<_, Ethereum>::new(rpc_client); + let provider = RootProvider::::new(rpc_client); let num = provider.get_block_number().await.unwrap(); assert_eq!(0, num); } @@ -1294,7 +1288,7 @@ mod tests { let rpc_client = alloy_rpc_client::RpcClient::new(http_hyper, true); - let provider = RootProvider::<_, Ethereum>::new(rpc_client); + let provider = RootProvider::::new(rpc_client); let num = provider.get_block_number().await.unwrap(); assert_eq!(0, num); @@ -1316,33 +1310,8 @@ mod tests { async fn object_safety() { let provider = ProviderBuilder::new().on_anvil(); - // These blocks are not necessary. - { - let refdyn = &provider as &dyn Provider; - let num = refdyn.get_block_number().await.unwrap(); - assert_eq!(0, num); - } - - // Clones the underlying provider too. - { - let clone_boxed = provider.root().clone().boxed(); - let num = clone_boxed.get_block_number().await.unwrap(); - assert_eq!(0, num); - } - - // Note the `Http` arg, vs no arg (defaulting to `BoxedTransport`) below. - { - let refdyn = &provider as &dyn Provider; - let num = refdyn.get_block_number().await.unwrap(); - assert_eq!(0, num); - } - - let boxed = provider.root().clone().boxed(); - let num = boxed.get_block_number().await.unwrap(); - assert_eq!(0, num); - - let boxed_boxdyn = Box::new(boxed) as Box>; - let num = boxed_boxdyn.get_block_number().await.unwrap(); + let refdyn = &provider as &dyn Provider<_>; + let num = refdyn.get_block_number().await.unwrap(); assert_eq!(0, num); } @@ -1380,27 +1349,7 @@ mod tests { let anvil = Anvil::new().block_time(1).spawn(); let ws = alloy_rpc_client::WsConnect::new(anvil.ws_endpoint()); let client = alloy_rpc_client::RpcClient::connect_pubsub(ws).await.unwrap(); - let provider = RootProvider::<_, Ethereum>::new(client); - - let sub = provider.subscribe_blocks().await.unwrap(); - let mut stream = sub.into_stream().take(2); - let mut n = 1; - while let Some(header) = stream.next().await { - assert_eq!(header.number, n); - n += 1; - } - } - - #[cfg(all(feature = "ws", not(windows)))] - #[tokio::test] - async fn subscribe_blocks_ws_boxed() { - use futures::stream::StreamExt; - - let anvil = Anvil::new().block_time(1).spawn(); - let ws = alloy_rpc_client::WsConnect::new(anvil.ws_endpoint()); - let client = alloy_rpc_client::RpcClient::connect_pubsub(ws).await.unwrap(); - let provider = RootProvider::<_, Ethereum>::new(client); - let provider = provider.boxed(); + let provider = RootProvider::::new(client); let sub = provider.subscribe_blocks().await.unwrap(); let mut stream = sub.into_stream().take(2); @@ -1419,7 +1368,7 @@ mod tests { let url = "wss://eth-mainnet.g.alchemy.com/v2/viFmeVzhg6bWKVMIWWS8MhmzREB-D4f7"; let ws = alloy_rpc_client::WsConnect::new(url); let Ok(client) = alloy_rpc_client::RpcClient::connect_pubsub(ws).await else { return }; - let provider = RootProvider::<_, Ethereum>::new(client); + let provider = RootProvider::::new(client); let sub = provider.subscribe_blocks().await.unwrap(); let mut stream = sub.into_stream().take(1); while let Some(header) = stream.next().await { @@ -1449,7 +1398,7 @@ mod tests { let anvil = Anvil::new().spawn(); let client = RpcClient::builder().layer(retry_layer).http(anvil.endpoint_url()); - let provider = RootProvider::<_, Ethereum>::new(client); + let provider = RootProvider::::new(client); let num = provider.get_block_number().await.unwrap(); assert_eq!(0, num); } @@ -1791,9 +1740,7 @@ mod tests { async fn connect_boxed() { let anvil = Anvil::new().spawn(); - let provider = - RootProvider::::connect_builtin(anvil.endpoint().as_str()) - .await; + let provider = RootProvider::::connect(anvil.endpoint().as_str()).await; match provider { Ok(provider) => { @@ -1844,7 +1791,7 @@ mod tests { let client = alloy_rpc_client::RpcClient::new(transport, true); - let provider = RootProvider::::new(client); + let provider = RootProvider::::new(client); let num = provider.get_block_number().await.unwrap(); assert_eq!(0, num); diff --git a/crates/provider/src/provider/wallet.rs b/crates/provider/src/provider/wallet.rs index d77ba67de3b..cc204b90af3 100644 --- a/crates/provider/src/provider/wallet.rs +++ b/crates/provider/src/provider/wallet.rs @@ -4,7 +4,6 @@ use crate::{ }; use alloy_network::{Ethereum, Network, NetworkWallet}; use alloy_primitives::Address; -use alloy_transport::Transport; /// Trait for Providers, Fill stacks, etc, which contain [`NetworkWallet`]. pub trait WalletProvider { @@ -71,11 +70,10 @@ where } } -impl WalletProvider for FillProvider +impl WalletProvider for FillProvider where F: TxFiller + WalletProvider, - P: Provider, - T: Transport + Clone, + P: Provider, N: Network, { type Wallet = F::Wallet; diff --git a/crates/provider/src/provider/with_block.rs b/crates/provider/src/provider/with_block.rs index c19b6f2ee8a..9f8caf8a0a1 100644 --- a/crates/provider/src/provider/with_block.rs +++ b/crates/provider/src/provider/with_block.rs @@ -2,7 +2,7 @@ use alloy_eips::BlockId; use alloy_json_rpc::{RpcParam, RpcReturn}; use alloy_primitives::B256; use alloy_rpc_client::RpcCall; -use alloy_transport::{Transport, TransportResult}; +use alloy_transport::TransportResult; use std::future::IntoFuture; use crate::ProviderCall; @@ -39,26 +39,24 @@ impl serde::Serialize for ParamsWithBlock { } } -type ProviderCallProducer = - Box ProviderCall, Resp, Output, Map> + Send>; +type ProviderCallProducer = + Box ProviderCall, Resp, Output, Map> + Send>; /// Container for varous types of calls dependent on a block id. -enum WithBlockInner Output> +enum WithBlockInner Output> where - T: Transport + Clone, Params: RpcParam, Resp: RpcReturn, Map: Fn(Resp) -> Output, { /// [RpcCall] which params are getting wrapped into [ParamsWithBlock] once the block id is set. - RpcCall(RpcCall), + RpcCall(RpcCall), /// Closure that produces a [ProviderCall] once the block id is set. - ProviderCall(ProviderCallProducer), + ProviderCall(ProviderCallProducer), } -impl core::fmt::Debug for WithBlockInner +impl core::fmt::Debug for WithBlockInner where - T: Transport + Clone, Params: RpcParam, Resp: RpcReturn, Map: Fn(Resp) -> Output, @@ -78,70 +76,63 @@ where /// By default this will use "latest". #[pin_project::pin_project] #[derive(Debug)] -pub struct RpcWithBlock Output> +pub struct RpcWithBlock Output> where - T: Transport + Clone, Params: RpcParam, Resp: RpcReturn, Map: Fn(Resp) -> Output + Clone, { - inner: WithBlockInner, + inner: WithBlockInner, block_id: BlockId, } -impl RpcWithBlock +impl RpcWithBlock where - T: Transport + Clone, Params: RpcParam, Resp: RpcReturn, Map: Fn(Resp) -> Output + Clone, { /// Create a new [`RpcWithBlock`] from a [`RpcCall`]. - pub fn new_rpc(inner: RpcCall) -> Self { + pub fn new_rpc(inner: RpcCall) -> Self { Self { inner: WithBlockInner::RpcCall(inner), block_id: Default::default() } } /// Create a new [`RpcWithBlock`] from a closure producing a [`ProviderCall`]. pub fn new_provider(get_call: F) -> Self where - F: Fn(BlockId) -> ProviderCall, Resp, Output, Map> - + Send - + 'static, + F: Fn(BlockId) -> ProviderCall, Resp, Output, Map> + Send + 'static, { let get_call = Box::new(get_call); Self { inner: WithBlockInner::ProviderCall(get_call), block_id: Default::default() } } } -impl From> - for RpcWithBlock +impl From> + for RpcWithBlock where - T: Transport + Clone, Params: RpcParam, Resp: RpcReturn, Map: Fn(Resp) -> Output + Clone, { - fn from(inner: RpcCall) -> Self { + fn from(inner: RpcCall) -> Self { Self::new_rpc(inner) } } -impl From for RpcWithBlock +impl From for RpcWithBlock where - T: Transport + Clone, Params: RpcParam, Resp: RpcReturn, Map: Fn(Resp) -> Output + Clone, - F: Fn(BlockId) -> ProviderCall, Resp, Output, Map> + Send + 'static, + F: Fn(BlockId) -> ProviderCall, Resp, Output, Map> + Send + 'static, { fn from(inner: F) -> Self { Self::new_provider(inner) } } -impl RpcWithBlock +impl RpcWithBlock where - T: Transport + Clone, Params: RpcParam, Resp: RpcReturn, Map: Fn(Resp) -> Output + Clone, @@ -195,9 +186,8 @@ where } } -impl IntoFuture for RpcWithBlock +impl IntoFuture for RpcWithBlock where - T: Transport + Clone, Params: RpcParam, Resp: RpcReturn, Output: 'static, @@ -205,7 +195,7 @@ where { type Output = TransportResult; - type IntoFuture = ProviderCall, Resp, Output, Map>; + type IntoFuture = ProviderCall, Resp, Output, Map>; fn into_future(self) -> Self::IntoFuture { match self.inner { diff --git a/crates/rpc-client/README.md b/crates/rpc-client/README.md index f1034ffc06c..7bad0cf87aa 100644 --- a/crates/rpc-client/README.md +++ b/crates/rpc-client/README.md @@ -4,7 +4,7 @@ Low-level Ethereum JSON-RPC client implementation. ## Usage -Usage of this crate typically means instantiating an `RpcClient` over some +Usage of this crate typically means instantiating an `RpcClient` over some `Transport`. The RPC client can then be used to make requests to the RPC server. Requests are captured as `RpcCall` futures, which can then be polled to completion. diff --git a/crates/rpc-client/src/batch.rs b/crates/rpc-client/src/batch.rs index 30109586d21..d0aad50a00e 100644 --- a/crates/rpc-client/src/batch.rs +++ b/crates/rpc-client/src/batch.rs @@ -4,7 +4,9 @@ use alloy_json_rpc::{ RpcReturn, SerializedRequest, }; use alloy_primitives::map::HashMap; -use alloy_transport::{Transport, TransportError, TransportErrorKind, TransportResult}; +use alloy_transport::{ + BoxTransport, TransportError, TransportErrorKind, TransportFut, TransportResult, +}; use futures::FutureExt; use pin_project::pin_project; use serde_json::value::RawValue; @@ -19,6 +21,7 @@ use std::{ }, }; use tokio::sync::oneshot; +use tower::Service; pub(crate) type Channel = oneshot::Sender>>; pub(crate) type ChannelMap = HashMap; @@ -27,9 +30,9 @@ pub(crate) type ChannelMap = HashMap; /// call. #[derive(Debug)] #[must_use = "A BatchRequest does nothing unless sent via `send_batch` and `.await`"] -pub struct BatchRequest<'a, T> { +pub struct BatchRequest<'a> { /// The transport via which the batch will be sent. - transport: ClientRef<'a, T>, + transport: ClientRef<'a>, /// The requests to be sent. requests: RequestPacket, @@ -96,11 +99,10 @@ where } #[pin_project::pin_project(project = CallStateProj)] -#[derive(Debug)] -#[allow(unnameable_types)] -pub enum BatchFuture { +#[allow(unnameable_types, missing_debug_implementations)] +pub enum BatchFuture { Prepared { - transport: Conn, + transport: BoxTransport, requests: RequestPacket, channels: ChannelMap, }, @@ -108,14 +110,14 @@ pub enum BatchFuture { AwaitingResponse { channels: ChannelMap, #[pin] - fut: Conn::Future, + fut: TransportFut<'static>, }, Complete, } -impl<'a, T> BatchRequest<'a, T> { +impl<'a> BatchRequest<'a> { /// Create a new batch request. - pub fn new(transport: &'a RpcClientInner) -> Self { + pub fn new(transport: &'a RpcClientInner) -> Self { Self { transport, requests: RequestPacket::Batch(Vec::with_capacity(10)), @@ -140,12 +142,7 @@ impl<'a, T> BatchRequest<'a, T> { let ser = request.serialize().map_err(TransportError::ser_err)?; Ok(self.push_raw(ser).into()) } -} -impl BatchRequest<'_, Conn> -where - Conn: Transport + Clone, -{ /// Add a call to the batch. /// /// ### Errors @@ -161,7 +158,7 @@ where } /// Send the batch future via its connection. - pub fn send(self) -> BatchFuture { + pub fn send(self) -> BatchFuture { BatchFuture::Prepared { transport: self.transport.transport.clone(), requests: self.requests, @@ -170,22 +167,16 @@ where } } -impl IntoFuture for BatchRequest<'_, T> -where - T: Transport + Clone, -{ - type Output = as Future>::Output; - type IntoFuture = BatchFuture; +impl IntoFuture for BatchRequest<'_> { + type Output = ::Output; + type IntoFuture = BatchFuture; fn into_future(self) -> Self::IntoFuture { self.send() } } -impl BatchFuture -where - T: Transport + Clone, -{ +impl BatchFuture { fn poll_prepared( mut self: Pin<&mut Self>, cx: &mut task::Context<'_>, @@ -269,10 +260,7 @@ where } } -impl Future for BatchFuture -where - T: Transport + Clone, -{ +impl Future for BatchFuture { type Output = TransportResult<()>; fn poll(mut self: Pin<&mut Self>, cx: &mut task::Context<'_>) -> Poll { diff --git a/crates/rpc-client/src/builder.rs b/crates/rpc-client/src/builder.rs index 759affd3608..727be5bed35 100644 --- a/crates/rpc-client/src/builder.rs +++ b/crates/rpc-client/src/builder.rs @@ -1,7 +1,5 @@ -use crate::RpcClient; -use alloy_transport::{ - BoxTransport, BoxTransportConnect, Transport, TransportConnect, TransportResult, -}; +use crate::{BuiltInConnectionString, RpcClient}; +use alloy_transport::{BoxTransport, IntoBoxTransport, TransportConnect, TransportResult}; use tower::{ layer::util::{Identity, Stack}, Layer, ServiceBuilder, @@ -37,11 +35,11 @@ impl ClientBuilder { /// Create a new [`RpcClient`] with the given transport and the configured /// layers. - pub fn transport(self, transport: T, is_local: bool) -> RpcClient + pub fn transport(self, transport: T, is_local: bool) -> RpcClient where L: Layer, - T: Transport, - L::Service: Transport, + T: IntoBoxTransport, + L::Service: IntoBoxTransport, { RpcClient::new(self.builder.service(transport), is_local) } @@ -49,10 +47,10 @@ impl ClientBuilder { /// Convenience function to create a new [`RpcClient`] with a [`reqwest`] /// HTTP transport. #[cfg(feature = "reqwest")] - pub fn http(self, url: url::Url) -> RpcClient + pub fn http(self, url: url::Url) -> RpcClient where L: Layer>, - L::Service: Transport, + L::Service: IntoBoxTransport, { let transport = alloy_transport_http::Http::new(url); let is_local = transport.guess_local(); @@ -62,10 +60,10 @@ impl ClientBuilder { /// Convenience function to create a new [`RpcClient`] with a `hyper` HTTP transport. #[cfg(all(not(target_arch = "wasm32"), feature = "hyper"))] - pub fn hyper_http(self, url: url::Url) -> RpcClient + pub fn hyper_http(self, url: url::Url) -> RpcClient where L: Layer, - L::Service: Transport, + L::Service: IntoBoxTransport, { let transport = alloy_transport_http::HyperTransport::new_hyper(url); let is_local = transport.guess_local(); @@ -76,11 +74,11 @@ impl ClientBuilder { /// Connect a pubsub transport, producing an [`RpcClient`] with the provided /// connection. #[cfg(feature = "pubsub")] - pub async fn pubsub(self, pubsub_connect: C) -> TransportResult> + pub async fn pubsub(self, pubsub_connect: C) -> TransportResult where C: alloy_pubsub::PubSubConnect, L: Layer, - L::Service: Transport, + L::Service: IntoBoxTransport, { let is_local = pubsub_connect.is_local(); let transport = pubsub_connect.into_service().await?; @@ -90,13 +88,10 @@ impl ClientBuilder { /// Connect a WS transport, producing an [`RpcClient`] with the provided /// connection #[cfg(feature = "ws")] - pub async fn ws( - self, - ws_connect: alloy_transport_ws::WsConnect, - ) -> TransportResult> + pub async fn ws(self, ws_connect: alloy_transport_ws::WsConnect) -> TransportResult where L: Layer, - L::Service: Transport, + L::Service: IntoBoxTransport, { self.pubsub(ws_connect).await } @@ -107,22 +102,32 @@ impl ClientBuilder { pub async fn ipc( self, ipc_connect: alloy_transport_ipc::IpcConnect, - ) -> TransportResult> + ) -> TransportResult where alloy_transport_ipc::IpcConnect: alloy_pubsub::PubSubConnect, L: Layer, - L::Service: Transport, + L::Service: IntoBoxTransport, { self.pubsub(ipc_connect).await } - /// Connect a transport, producing an [`RpcClient`] with the provided - /// connection. - pub async fn connect(self, connect: C) -> TransportResult> + /// Connect a transport specified by the given string, producing an [`RpcClient`]. + /// + /// See [`BuiltInConnectionString`] for more information. + pub async fn connect(self, s: &str) -> TransportResult + where + L: Layer, + L::Service: IntoBoxTransport, + { + self.connect_with(s.parse::()?).await + } + + /// Connect a transport, producing an [`RpcClient`]. + pub async fn connect_with(self, connect: C) -> TransportResult where C: TransportConnect, - L: Layer, - L::Service: Transport, + L: Layer, + L::Service: IntoBoxTransport, { let transport = connect.get_transport().await?; Ok(self.transport(transport, connect.is_local())) @@ -130,13 +135,16 @@ impl ClientBuilder { /// Connect a transport, producing an [`RpcClient`] with a [`BoxTransport`] /// connection. - pub async fn connect_boxed(self, connect: C) -> TransportResult> + #[deprecated( + since = "0.9.0", + note = "RpcClient is now always boxed, use `connect_with` instead" + )] + pub async fn connect_boxed(self, connect: C) -> TransportResult where - C: BoxTransportConnect, + C: TransportConnect, L: Layer, - L::Service: Transport, + L::Service: IntoBoxTransport, { - let transport = connect.get_boxed_transport().await?; - Ok(self.transport(transport, connect.is_local())) + self.connect_with(connect).await } } diff --git a/crates/rpc-client/src/builtin.rs b/crates/rpc-client/src/builtin.rs index 3f1f41f9906..0473b2e7caf 100644 --- a/crates/rpc-client/src/builtin.rs +++ b/crates/rpc-client/src/builtin.rs @@ -1,5 +1,5 @@ use alloy_json_rpc::RpcError; -use alloy_transport::{BoxTransport, BoxTransportConnect, TransportError, TransportErrorKind}; +use alloy_transport::{BoxTransport, TransportConnect, TransportError, TransportErrorKind}; use std::str::FromStr; #[cfg(any(feature = "ws", feature = "ipc"))] @@ -20,7 +20,7 @@ pub enum BuiltInConnectionString { Ipc(std::path::PathBuf), } -impl BoxTransportConnect for BuiltInConnectionString { +impl TransportConnect for BuiltInConnectionString { fn is_local(&self) -> bool { match self { #[cfg(any(feature = "reqwest", feature = "hyper"))] @@ -39,10 +39,8 @@ impl BoxTransportConnect for BuiltInConnectionString { } } - fn get_boxed_transport<'a: 'b, 'b>( - &'a self, - ) -> alloy_transport::Pbf<'b, BoxTransport, TransportError> { - Box::pin(self.connect_boxed()) + async fn get_transport(&self) -> Result { + self.connect_boxed().await } } diff --git a/crates/rpc-client/src/call.rs b/crates/rpc-client/src/call.rs index 8c9efc60fab..4efa940a7cb 100644 --- a/crates/rpc-client/src/call.rs +++ b/crates/rpc-client/src/call.rs @@ -2,7 +2,7 @@ use alloy_json_rpc::{ transform_response, try_deserialize_ok, Request, RequestPacket, ResponsePacket, RpcParam, RpcResult, RpcReturn, }; -use alloy_transport::{RpcFut, Transport, TransportError, TransportResult}; +use alloy_transport::{BoxTransport, IntoBoxTransport, RpcFut, TransportError, TransportResult}; use core::panic; use futures::FutureExt; use serde_json::value::RawValue; @@ -18,26 +18,24 @@ use tower::Service; /// The states of the [`RpcCall`] future. #[must_use = "futures do nothing unless you `.await` or poll them"] #[pin_project::pin_project(project = CallStateProj)] -enum CallState +enum CallState where Params: RpcParam, - Conn: Transport + Clone, { Prepared { request: Option>, - connection: Conn, + connection: BoxTransport, }, AwaitingResponse { #[pin] - fut: >::Future, + fut: >::Future, }, Complete, } -impl Clone for CallState +impl Clone for CallState where Params: RpcParam, - Conn: Transport + Clone, { fn clone(&self) -> Self { match self { @@ -49,10 +47,9 @@ where } } -impl fmt::Debug for CallState +impl fmt::Debug for CallState where Params: RpcParam, - Conn: Transport + Clone, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str(match self { @@ -63,9 +60,8 @@ where } } -impl Future for CallState +impl Future for CallState where - Conn: Transport + Clone, Params: RpcParam, { type Output = TransportResult>; @@ -118,7 +114,7 @@ where /// A prepared, but unsent, RPC call. /// /// This is a future that will send the request when polled. It contains a -/// [`Request`], a [`Transport`], and knowledge of its expected response +/// [`Request`], a [`BoxTransport`], and knowledge of its expected response /// type. Upon awaiting, it will send the request and wait for the response. It /// will then deserialize the response into the expected type. /// @@ -136,21 +132,19 @@ where #[must_use = "futures do nothing unless you `.await` or poll them"] #[pin_project::pin_project] #[derive(Clone)] -pub struct RpcCall Output> +pub struct RpcCall Output> where - Conn: Transport + Clone, Params: RpcParam, Map: FnOnce(Resp) -> Output, { #[pin] - state: CallState, + state: CallState, map: Option, _pd: core::marker::PhantomData (Resp, Output)>, } -impl core::fmt::Debug for RpcCall +impl core::fmt::Debug for RpcCall where - Conn: Transport + Clone, Params: RpcParam, Map: FnOnce(Resp) -> Output, { @@ -159,24 +153,25 @@ where } } -impl RpcCall +impl RpcCall where - Conn: Transport + Clone, Params: RpcParam, { #[doc(hidden)] - pub fn new(req: Request, connection: Conn) -> Self { + pub fn new(req: Request, connection: impl IntoBoxTransport) -> Self { Self { - state: CallState::Prepared { request: Some(req), connection }, + state: CallState::Prepared { + request: Some(req), + connection: connection.into_box_transport(), + }, map: Some(std::convert::identity), _pd: PhantomData, } } } -impl RpcCall +impl RpcCall where - Conn: Transport + Clone, Params: RpcParam, Map: FnOnce(Resp) -> Output, { @@ -194,7 +189,7 @@ where pub fn map_resp( self, map: NewMap, - ) -> RpcCall + ) -> RpcCall where NewMap: FnOnce(Resp) -> NewOutput, { @@ -265,7 +260,7 @@ where pub fn map_params( self, map: impl Fn(Params) -> NewParams, - ) -> RpcCall { + ) -> RpcCall { let CallState::Prepared { request, connection } = self.state else { panic!("Cannot get request after request has been sent"); }; @@ -278,9 +273,8 @@ where } } -impl RpcCall +impl RpcCall<&Params, Resp, Output, Map> where - Conn: Transport + Clone, Params: RpcParam + ToOwned, Params::Owned: RpcParam, Map: FnOnce(Resp) -> Output, @@ -290,7 +284,7 @@ where /// # Panics /// /// Panics if called after the request has been polled. - pub fn into_owned_params(self) -> RpcCall { + pub fn into_owned_params(self) -> RpcCall { let CallState::Prepared { request, connection } = self.state else { panic!("Cannot get params after request has been sent"); }; @@ -304,9 +298,8 @@ where } } -impl<'a, Conn, Params, Resp, Output, Map> RpcCall +impl<'a, Params, Resp, Output, Map> RpcCall where - Conn: Transport + Clone, Params: RpcParam + 'a, Resp: RpcReturn, Output: 'static, @@ -318,9 +311,8 @@ where } } -impl Future for RpcCall +impl Future for RpcCall where - Conn: Transport + Clone, Params: RpcParam, Resp: RpcReturn, Output: 'static, diff --git a/crates/rpc-client/src/client.rs b/crates/rpc-client/src/client.rs index 5b58078e939..653875cc3a5 100644 --- a/crates/rpc-client/src/client.rs +++ b/crates/rpc-client/src/client.rs @@ -1,6 +1,6 @@ use crate::{poller::PollerBuilder, BatchRequest, ClientBuilder, RpcCall}; use alloy_json_rpc::{Id, Request, RpcParam, RpcReturn}; -use alloy_transport::{BoxTransport, Transport}; +use alloy_transport::{BoxTransport, IntoBoxTransport}; use alloy_transport_http::Http; use std::{ borrow::Cow, @@ -14,10 +14,10 @@ use std::{ use tower::{layer::util::Identity, ServiceBuilder}; /// An [`RpcClient`] in a [`Weak`] reference. -pub type WeakClient = Weak>; +pub type WeakClient = Weak; /// A borrowed [`RpcClient`]. -pub type ClientRef<'a, T> = &'a RpcClientInner; +pub type ClientRef<'a> = &'a RpcClientInner; /// Parameter type of a JSON-RPC request with no parameters. pub type NoParams = [(); 0]; @@ -29,59 +29,57 @@ pub type NoParams = [(); 0]; /// /// [`ClientBuilder`]: crate::ClientBuilder #[derive(Debug)] -pub struct RpcClient(Arc>); +pub struct RpcClient(Arc); -impl Clone for RpcClient { +impl Clone for RpcClient { fn clone(&self) -> Self { Self(Arc::clone(&self.0)) } } -impl RpcClient { +impl RpcClient { /// Create a new [`ClientBuilder`]. pub const fn builder() -> ClientBuilder { ClientBuilder { builder: ServiceBuilder::new() } } } -#[cfg(feature = "reqwest")] -impl RpcClient> { +impl RpcClient { /// Create a new [`RpcClient`] with an HTTP transport. + #[cfg(feature = "reqwest")] pub fn new_http(url: reqwest::Url) -> Self { let http = Http::new(url); let is_local = http.guess_local(); Self::new(http, is_local) } -} -impl RpcClient { /// Creates a new [`RpcClient`] with the given transport. - pub fn new(t: T, is_local: bool) -> Self { + pub fn new(t: impl IntoBoxTransport, is_local: bool) -> Self { Self(Arc::new(RpcClientInner::new(t, is_local))) } /// Creates a new [`RpcClient`] with the given inner client. - pub fn from_inner(inner: RpcClientInner) -> Self { + pub fn from_inner(inner: RpcClientInner) -> Self { Self(Arc::new(inner)) } /// Get a reference to the client. - pub const fn inner(&self) -> &Arc> { + pub const fn inner(&self) -> &Arc { &self.0 } /// Convert the client into its inner type. - pub fn into_inner(self) -> Arc> { + pub fn into_inner(self) -> Arc { self.0 } /// Get a [`Weak`] reference to the client. - pub fn get_weak(&self) -> WeakClient { + pub fn get_weak(&self) -> WeakClient { Arc::downgrade(&self.0) } /// Borrow the client. - pub fn get_ref(&self) -> ClientRef<'_, T> { + pub fn get_ref(&self) -> ClientRef<'_> { &self.0 } @@ -93,9 +91,7 @@ impl RpcClient { self.inner().set_poll_interval(poll_interval); self } -} -impl RpcClient { /// Build a poller that polls a method with the given parameters. /// /// See [`PollerBuilder`] for examples and more details. @@ -103,41 +99,32 @@ impl RpcClient { &self, method: impl Into>, params: Params, - ) -> PollerBuilder + ) -> PollerBuilder where - T: Clone, Params: RpcParam + 'static, Resp: RpcReturn + Clone, { PollerBuilder::new(self.get_weak(), method, params) } -} -impl RpcClient { /// Boxes the transport. - /// - /// This will create a new client if this instance is not the only reference to the inner - /// client. - pub fn boxed(self) -> RpcClient { - let inner = Arc::try_unwrap(self.0).unwrap_or_else(|inner| { - RpcClientInner::new(inner.transport.clone(), inner.is_local) - .with_id(inner.id.load(Ordering::Relaxed)) - }); - RpcClient::from_inner(inner.boxed()) + #[deprecated(since = "0.9.0", note = "`RpcClient` is now always boxed")] + #[allow(clippy::missing_const_for_fn)] + pub fn boxed(self) -> Self { + self } -} -impl RpcClient> { /// Create a new [`BatchRequest`] builder. #[inline] - pub fn new_batch(&self) -> BatchRequest<'_, Http> { + pub fn new_batch(&self) -> BatchRequest<'_> { BatchRequest::new(&self.0) } } -impl Deref for RpcClient { - type Target = RpcClientInner; +impl Deref for RpcClient { + type Target = RpcClientInner; + #[inline] fn deref(&self) -> &Self::Target { &self.0 } @@ -145,7 +132,7 @@ impl Deref for RpcClient { /// A JSON-RPC client. /// -/// This struct manages a [`Transport`] and a request ID counter. It is used to +/// This struct manages a [`BoxTransport`] and a request ID counter. It is used to /// build [`RpcCall`] and [`BatchRequest`] objects. The client delegates /// transport access to the calls. /// @@ -156,9 +143,9 @@ impl Deref for RpcClient { /// is no guarantee that a prepared [`RpcCall`] will be sent, or that a sent /// call will receive a response. #[derive(Debug)] -pub struct RpcClientInner { +pub struct RpcClientInner { /// The underlying transport. - pub(crate) transport: T, + pub(crate) transport: BoxTransport, /// `true` if the transport is local. pub(crate) is_local: bool, /// The next request ID to use. @@ -167,15 +154,15 @@ pub struct RpcClientInner { pub(crate) poll_interval: AtomicU64, } -impl RpcClientInner { +impl RpcClientInner { /// Create a new [`RpcClient`] with the given transport. /// /// Note: Sets the poll interval to 250ms for local transports and 7s for remote transports by /// default. #[inline] - pub const fn new(t: T, is_local: bool) -> Self { + pub fn new(t: impl IntoBoxTransport, is_local: bool) -> Self { Self { - transport: t, + transport: t.into_box_transport(), is_local, id: AtomicU64::new(0), poll_interval: if is_local { AtomicU64::new(250) } else { AtomicU64::new(7000) }, @@ -201,33 +188,40 @@ impl RpcClientInner { /// Returns a reference to the underlying transport. #[inline] - pub const fn transport(&self) -> &T { + pub const fn transport(&self) -> &BoxTransport { &self.transport } /// Returns a mutable reference to the underlying transport. #[inline] - pub fn transport_mut(&mut self) -> &mut T { + pub fn transport_mut(&mut self) -> &mut BoxTransport { &mut self.transport } /// Consumes the client and returns the underlying transport. #[inline] - pub fn into_transport(self) -> T { + pub fn into_transport(self) -> BoxTransport { self.transport } /// Returns a reference to the pubsub frontend if the transport supports it. #[cfg(feature = "pubsub")] - pub fn pubsub_frontend(&self) -> Option<&alloy_pubsub::PubSubFrontend> - where - T: std::any::Any, - { - let t = self.transport() as &dyn std::any::Any; - t.downcast_ref::().or_else(|| { - t.downcast_ref::() - .and_then(|t| t.as_any().downcast_ref::()) - }) + #[inline] + #[track_caller] + pub fn pubsub_frontend(&self) -> Option<&alloy_pubsub::PubSubFrontend> { + self.transport.as_any().downcast_ref::() + } + + /// Returns a reference to the pubsub frontend if the transport supports it. + /// + /// # Panics + /// + /// Panics if the transport does not support pubsub. + #[cfg(feature = "pubsub")] + #[inline] + #[track_caller] + pub fn expect_pubsub_frontend(&self) -> &alloy_pubsub::PubSubFrontend { + self.pubsub_frontend().expect("called pubsub_frontend on a non-pubsub transport") } /// Build a `JsonRpcRequest` with the given method and params. @@ -272,9 +266,7 @@ impl RpcClientInner { pub fn next_id(&self) -> Id { self.increment_id().into() } -} -impl RpcClientInner { /// Prepares an [`RpcCall`]. /// /// This function reserves an ID for the request, however the request is not sent. @@ -290,7 +282,7 @@ impl RpcClientInner { &self, method: impl Into>, params: Params, - ) -> RpcCall { + ) -> RpcCall { let request = self.make_request(method, params); RpcCall::new(request, self.transport.clone()) } @@ -301,41 +293,40 @@ impl RpcClientInner { pub fn request_noparams( &self, method: impl Into>, - ) -> RpcCall { + ) -> RpcCall { self.request(method, []) } /// Type erase the service in the transport, allowing it to be used in a /// generic context. - /// - /// ## Note: - /// - /// This is for abstracting over `RpcClient` for multiple `T` by - /// erasing each type. E.g. if you have `RpcClient` and - /// `RpcClient` you can put both into a `Vec>`. - pub fn boxed(self) -> RpcClientInner { - RpcClientInner { - transport: self.transport.boxed(), - is_local: self.is_local, - id: self.id, - poll_interval: self.poll_interval, - } + #[deprecated(since = "0.9.0", note = "`RpcClientInner` is now always boxed")] + #[allow(clippy::missing_const_for_fn)] + pub fn boxed(self) -> Self { + self } } #[cfg(feature = "pubsub")] mod pubsub_impl { use super::*; - use alloy_pubsub::{PubSubConnect, PubSubFrontend, RawSubscription, Subscription}; + use alloy_pubsub::{PubSubConnect, RawSubscription, Subscription}; use alloy_transport::TransportResult; - impl RpcClientInner { + impl RpcClientInner { /// Get a [`RawSubscription`] for the given subscription ID. + /// + /// # Panics + /// + /// Panics if the transport does not support pubsub. pub async fn get_raw_subscription(&self, id: alloy_primitives::B256) -> RawSubscription { - self.transport.get_subscription(id).await.unwrap() + self.expect_pubsub_frontend().get_subscription(id).await.unwrap() } /// Get a [`Subscription`] for the given subscription ID. + /// + /// # Panics + /// + /// Panics if the transport does not support pubsub. pub async fn get_subscription( &self, id: alloy_primitives::B256, @@ -344,12 +335,9 @@ mod pubsub_impl { } } - impl RpcClient { + impl RpcClient { /// Connect to a transport via a [`PubSubConnect`] implementor. - pub async fn connect_pubsub(connect: C) -> TransportResult - where - C: PubSubConnect, - { + pub async fn connect_pubsub(connect: C) -> TransportResult { ClientBuilder::default().pubsub(connect).await } @@ -359,13 +347,23 @@ mod pubsub_impl { /// behavior. /// /// [`tokio::sync::broadcast`]: https://docs.rs/tokio/latest/tokio/sync/broadcast/index.html + /// + /// # Panics + /// + /// Panics if the transport does not support pubsub. + #[track_caller] pub fn channel_size(&self) -> usize { - self.transport.channel_size() + self.expect_pubsub_frontend().channel_size() } /// Set the channel size. + /// + /// # Panics + /// + /// Panics if the transport does not support pubsub. + #[track_caller] pub fn set_channel_size(&self, size: usize) { - self.transport.set_channel_size(size) + self.expect_pubsub_frontend().set_channel_size(size) } } } diff --git a/crates/rpc-client/src/lib.rs b/crates/rpc-client/src/lib.rs index ed98fab1702..4adb0babfe6 100644 --- a/crates/rpc-client/src/lib.rs +++ b/crates/rpc-client/src/lib.rs @@ -35,4 +35,4 @@ pub use alloy_transport_ipc::IpcConnect; /// A client using a [`reqwest`] HTTP transport. #[cfg(feature = "reqwest")] -pub type ReqwestClient = RpcClient; +pub type ReqwestClient = RpcClient; diff --git a/crates/rpc-client/src/poller.rs b/crates/rpc-client/src/poller.rs index 06cb9cdc595..cd9c40cc818 100644 --- a/crates/rpc-client/src/poller.rs +++ b/crates/rpc-client/src/poller.rs @@ -1,6 +1,6 @@ use crate::WeakClient; use alloy_json_rpc::{RpcError, RpcParam, RpcReturn}; -use alloy_transport::{utils::Spawnable, Transport}; +use alloy_transport::utils::Spawnable; use futures::{Stream, StreamExt}; use serde::Serialize; use serde_json::value::RawValue; @@ -45,13 +45,13 @@ const MAX_RETRIES: usize = 3; /// Poll `eth_blockNumber` every 5 seconds: /// /// ```no_run -/// # async fn example(client: alloy_rpc_client::RpcClient) -> Result<(), Box> { +/// # async fn example(client: alloy_rpc_client::RpcClient) -> Result<(), Box> { /// use alloy_primitives::U64; /// use alloy_rpc_client::PollerBuilder; /// use futures_util::StreamExt; /// -/// let poller: PollerBuilder<_, (), U64> = client -/// .prepare_static_poller("eth_blockNumber", ()) +/// let poller: PollerBuilder = client +/// .prepare_static_poller("eth_blockNumber", []) /// .with_poll_interval(std::time::Duration::from_secs(5)); /// let mut stream = poller.into_stream(); /// while let Some(block_number) = stream.next().await { @@ -63,9 +63,9 @@ const MAX_RETRIES: usize = 3; // TODO: make this be able to be spawned on the current thread instead of forcing a task. #[derive(Debug)] #[must_use = "this builder does nothing unless you call `spawn` or `into_stream`"] -pub struct PollerBuilder { +pub struct PollerBuilder { /// The client to poll with. - client: WeakClient, + client: WeakClient, /// Request Method method: Cow<'static, str>, @@ -79,18 +79,13 @@ pub struct PollerBuilder { _pd: PhantomData Resp>, } -impl PollerBuilder +impl PollerBuilder where - Conn: Transport + Clone, Params: RpcParam + 'static, Resp: RpcReturn + Clone, { /// Create a new poller task. - pub fn new( - client: WeakClient, - method: impl Into>, - 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.poll_interval()); Self { diff --git a/crates/rpc-types-admin/src/admin.rs b/crates/rpc-types-admin/src/admin.rs index 05403cd0900..1935eb747d1 100644 --- a/crates/rpc-types-admin/src/admin.rs +++ b/crates/rpc-types-admin/src/admin.rs @@ -75,7 +75,7 @@ pub struct EthProtocolInfo { /// * #[deprecated( since = "0.8.2", - note = "The difficulty field of admin_nodeInfo is being removed from the response, see https://github.com/ethereum/go-ethereum/pull/30744" + note = "`difficulty` is being removed from `admin_nodeInfo`, see https://github.com/ethereum/go-ethereum/pull/30744" )] pub difficulty: Option, /// The Keccak hash of the host's genesis block. diff --git a/crates/rpc-types-eth/src/erc4337.rs b/crates/rpc-types-eth/src/erc4337.rs index 16087cc4f8e..61b0b9c4eca 100644 --- a/crates/rpc-types-eth/src/erc4337.rs +++ b/crates/rpc-types-eth/src/erc4337.rs @@ -7,10 +7,7 @@ use alloy_primitives::{ }; /// Alias for backwards compat -#[deprecated( - since = "0.8.4", - note = "Please use `TransactionConditional` instead of `ConditionalOptions`." -)] +#[deprecated(since = "0.8.4", note = "use `TransactionConditional` instead")] pub type ConditionalOptions = TransactionConditional; /// Options for conditional raw transaction submissions. diff --git a/crates/transport-http/src/hyper_transport.rs b/crates/transport-http/src/hyper_transport.rs index 30de8402f39..1343aea6b7f 100644 --- a/crates/transport-http/src/hyper_transport.rs +++ b/crates/transport-http/src/hyper_transport.rs @@ -1,7 +1,8 @@ +use crate::{Http, HttpConnect}; use alloy_json_rpc::{RequestPacket, ResponsePacket}; use alloy_transport::{ - utils::guess_local_url, TransportConnect, TransportError, TransportErrorKind, TransportFut, - TransportResult, + utils::guess_local_url, BoxTransport, TransportConnect, TransportError, TransportErrorKind, + TransportFut, TransportResult, }; use http_body_util::{BodyExt, Full}; use hyper::{ @@ -13,8 +14,6 @@ use std::{future::Future, marker::PhantomData, pin::Pin, task}; use tower::Service; use tracing::{debug, debug_span, trace, Instrument}; -use crate::{Http, HttpConnect}; - type Hyper = hyper_util::client::legacy::Client< hyper_util::client::legacy::connect::HttpConnector, http_body_util::Full<::hyper::body::Bytes>, @@ -124,20 +123,12 @@ where } impl TransportConnect for HttpConnect { - type Transport = HyperTransport; - fn is_local(&self) -> bool { guess_local_url(self.url.as_str()) } - fn get_transport<'a: 'b, 'b>( - &'a self, - ) -> alloy_transport::Pbf<'b, Self::Transport, TransportError> { - Box::pin(async move { - let hyper_t = HyperClient::new(); - - Ok(Http::with_client(hyper_t, self.url.clone())) - }) + async fn get_transport(&self) -> Result { + Ok(BoxTransport::new(Http::with_client(HyperClient::new(), self.url.clone()))) } } diff --git a/crates/transport-http/src/reqwest_transport.rs b/crates/transport-http/src/reqwest_transport.rs index 331fa9ebf72..5871ba87dea 100644 --- a/crates/transport-http/src/reqwest_transport.rs +++ b/crates/transport-http/src/reqwest_transport.rs @@ -1,8 +1,8 @@ use crate::{Http, HttpConnect}; use alloy_json_rpc::{RequestPacket, ResponsePacket}; use alloy_transport::{ - utils::guess_local_url, TransportConnect, TransportError, TransportErrorKind, TransportFut, - TransportResult, + utils::guess_local_url, BoxTransport, TransportConnect, TransportError, TransportErrorKind, + TransportFut, TransportResult, }; use std::task; use tower::Service; @@ -19,16 +19,12 @@ pub type ReqwestTransport = Http; pub type ReqwestConnect = HttpConnect; impl TransportConnect for ReqwestConnect { - type Transport = ReqwestTransport; - fn is_local(&self) -> bool { guess_local_url(self.url.as_str()) } - fn get_transport<'a: 'b, 'b>( - &'a self, - ) -> alloy_transport::Pbf<'b, Self::Transport, TransportError> { - Box::pin(async move { Ok(Http::with_client(Client::new(), self.url.clone())) }) + async fn get_transport(&self) -> Result { + Ok(BoxTransport::new(Http::with_client(Client::new(), self.url.clone()))) } } diff --git a/crates/transport/Cargo.toml b/crates/transport/Cargo.toml index e508f034edf..5e024e73d4e 100644 --- a/crates/transport/Cargo.toml +++ b/crates/transport/Cargo.toml @@ -22,7 +22,6 @@ workspace = true alloy-json-rpc.workspace = true base64.workspace = true -futures-util.workspace = true futures-utils-wasm.workspace = true serde_json = { workspace = true, features = ["raw_value"] } serde.workspace = true diff --git a/crates/transport/src/boxed.rs b/crates/transport/src/boxed.rs index bd3c1286d27..ef5f9c6e10f 100644 --- a/crates/transport/src/boxed.rs +++ b/crates/transport/src/boxed.rs @@ -1,8 +1,37 @@ use crate::{Transport, TransportError, TransportFut}; use alloy_json_rpc::{RequestPacket, ResponsePacket}; -use std::fmt; +use std::{any::TypeId, fmt}; use tower::Service; +#[allow(unnameable_types)] +mod private { + pub trait Sealed {} + impl Sealed for T {} +} + +/// Trait for converting a transport into a boxed transport. +/// +/// This trait is sealed and implemented for all types that implement +/// [`Transport`] + [`Clone`]. +pub trait IntoBoxTransport: Transport + Clone + private::Sealed { + /// Boxes the transport. + fn into_box_transport(self) -> BoxTransport; +} + +impl IntoBoxTransport for T { + fn into_box_transport(self) -> BoxTransport { + // "specialization" to re-use `BoxTransport`. + if TypeId::of::() == TypeId::of::() { + // This is not `transmute` because it doesn't allow size mismatch at compile time. + // `transmute_copy` is a work-around for `transmute_unchecked` not being stable. + // SAFETY: `self` is `BoxTransport`. This is a no-op. + let this = std::mem::ManuallyDrop::new(self); + return unsafe { std::mem::transmute_copy(&this) }; + } + BoxTransport { inner: Box::new(self) } + } +} + /// A boxed, Clone-able [`Transport`] trait object. /// /// This type allows RPC clients to use a type-erased transport. It is @@ -10,23 +39,21 @@ use tower::Service; /// allows for complex behavior abstracting across several different clients /// with different transport types. /// -/// Most higher-level types will be generic over `T: Transport = BoxTransport`. -/// This allows parameterization with a concrete type, while hiding this -/// complexity from the library consumer. -/// -/// [`RpcClient`]: crate::client::RpcClient -#[repr(transparent)] +/// All higher-level types, such as `RpcClient`, use this type internally +/// rather than a generic [`Transport`] parameter. pub struct BoxTransport { - inner: Box, + inner: Box, } impl BoxTransport { /// Instantiate a new box transport from a suitable transport. - pub fn new(inner: T) -> Self { - Self { inner: Box::new(inner) } + #[inline] + pub fn new(transport: T) -> Self { + transport.into_box_transport() } /// Returns a reference to the inner transport. + #[inline] pub fn as_any(&self) -> &dyn std::any::Any { self.inner.as_any() } @@ -54,10 +81,12 @@ impl CloneTransport for T where T: Transport + Clone + Send + Sync, { + #[inline] fn clone_box(&self) -> Box { Box::new(self.clone()) } + #[inline] fn as_any(&self) -> &dyn std::any::Any { self } @@ -70,6 +99,7 @@ impl Service for BoxTransport { type Future = TransportFut<'static>; + #[inline] fn poll_ready( &mut self, cx: &mut std::task::Context<'_>, @@ -77,6 +107,7 @@ impl Service for BoxTransport { self.inner.poll_ready(cx) } + #[inline] fn call(&mut self, req: RequestPacket) -> Self::Future { self.inner.call(req) } @@ -86,11 +117,61 @@ impl Service for BoxTransport { mod test { use super::*; + #[derive(Clone)] + struct DummyTransport(T); + impl Service for DummyTransport { + type Response = ResponsePacket; + type Error = TransportError; + type Future = TransportFut<'static>; + + fn poll_ready( + &mut self, + _cx: &mut std::task::Context<'_>, + ) -> std::task::Poll> { + unimplemented!() + } + + fn call(&mut self, _req: RequestPacket) -> Self::Future { + unimplemented!() + } + } + // checks trait + send + sync + 'static - fn __compile_check() { - fn inner(_: Option) {} - fn inner_2(_: Option) {} - inner::(None); - inner::(None); + const fn _compile_check() { + const fn inner() + where + T: Transport + CloneTransport + Send + Sync + Clone + IntoBoxTransport + 'static, + { + } + inner::(); + } + + #[test] + fn no_reboxing() { + let id = TypeId::of::>(); + no_reboxing_(DummyTransport(()), id); + no_reboxing_(BoxTransport::new(DummyTransport(())), id); + + let wrap = String::from("hello"); + let id = TypeId::of::>(); + no_reboxing_(DummyTransport(wrap.clone()), id); + no_reboxing_(BoxTransport::new(DummyTransport(wrap)), id); + } + + fn no_reboxing_(t: T, id: TypeId) { + eprintln!("{}", std::any::type_name::()); + + let t1 = BoxTransport::new(t); + let t1p = std::ptr::addr_of!(*t1.inner); + let t1id = t1.as_any().type_id(); + + // This shouldn't wrap `t1` in another box (`BoxTransport>`). + let t2 = BoxTransport::new(t1); + let t2p = std::ptr::addr_of!(*t2.inner); + let t2id = t2.as_any().type_id(); + + assert_eq!(t1id, id); + assert_eq!(t1id, t2id); + assert!(std::ptr::eq(t1p, t2p)); } } diff --git a/crates/transport/src/connect.rs b/crates/transport/src/connect.rs index 2750754226f..a4f7829dfe0 100644 --- a/crates/transport/src/connect.rs +++ b/crates/transport/src/connect.rs @@ -1,5 +1,5 @@ -use crate::{BoxTransport, Pbf, Transport, TransportError}; -use futures_util::TryFutureExt; +use crate::{BoxTransport, TransportError}; +use futures_utils_wasm::impl_future; /// Connection details for a transport. /// @@ -11,46 +11,12 @@ use futures_util::TryFutureExt; /// Users may want to implement transport-connect for the following reasons: /// - You want to customize a `reqwest::Client` before using it. /// - You need to provide special authentication information to a remote provider. -/// - You have implemented a custom [`Transport`]. +/// - You have implemented a custom [`Transport`](crate::Transport). /// - You require a specific websocket reconnection strategy. pub trait TransportConnect: Sized + Send + Sync + 'static { - /// The transport type that is returned by `connect`. - type Transport: Transport + Clone; - /// Returns `true` if the transport connects to a local resource. fn is_local(&self) -> bool; /// Connect to the transport, returning a `Transport` instance. - fn get_transport<'a: 'b, 'b>(&'a self) -> Pbf<'b, Self::Transport, TransportError>; + fn get_transport(&self) -> impl_future!(>); } - -/// Connection details for a transport that can be boxed. -/// -/// This trait is implemented for [`TransportConnect`] implementors that -/// produce a boxable transport. It can be used to create a boxed transport -/// without knowing the exact type of the transport. -/// -/// This trait is separate from `TransportConnect`` to hide the associated type -/// in when this trait is a trait object. It is intended to allow creation of -/// several unlike transports or clients at once. E.g. -/// in something like `Vec<&dyn BoxTransportConnect>. -pub trait BoxTransportConnect { - /// Returns `true` if the transport is a local transport. - fn is_local(&self) -> bool; - - /// Connect to a transport, and box it. - fn get_boxed_transport<'a: 'b, 'b>(&'a self) -> Pbf<'b, BoxTransport, TransportError>; -} - -impl BoxTransportConnect for T { - fn is_local(&self) -> bool { - TransportConnect::is_local(self) - } - - fn get_boxed_transport<'a: 'b, 'b>(&'a self) -> Pbf<'b, BoxTransport, TransportError> { - Box::pin(self.get_transport().map_ok(Transport::boxed)) - } -} - -#[cfg(test)] -fn _object_safe(_: Box) {} diff --git a/crates/transport/src/lib.rs b/crates/transport/src/lib.rs index f892049ea76..df78cd09a7e 100644 --- a/crates/transport/src/lib.rs +++ b/crates/transport/src/lib.rs @@ -7,10 +7,10 @@ #![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] mod boxed; -pub use boxed::BoxTransport; +pub use boxed::{BoxTransport, IntoBoxTransport}; mod connect; -pub use connect::{BoxTransportConnect, TransportConnect}; +pub use connect::TransportConnect; mod common; pub use common::Authorization; diff --git a/crates/transport/src/trait.rs b/crates/transport/src/trait.rs index d5d6e1a7e64..5cb16f3a234 100644 --- a/crates/transport/src/trait.rs +++ b/crates/transport/src/trait.rs @@ -1,4 +1,4 @@ -use crate::{BoxTransport, TransportError, TransportFut}; +use crate::{BoxTransport, IntoBoxTransport, TransportError, TransportFut}; use alloy_json_rpc::{RequestPacket, ResponsePacket}; use tower::Service; @@ -46,7 +46,7 @@ pub trait Transport: /// Convert this transport into a boxed trait object. fn boxed(self) -> BoxTransport where - Self: Sized + Clone, + Self: IntoBoxTransport, { BoxTransport::new(self) } @@ -54,7 +54,7 @@ pub trait Transport: /// Make a boxed trait object by cloning this transport. fn as_boxed(&self) -> BoxTransport where - Self: Sized + Clone, + Self: IntoBoxTransport, { self.clone().boxed() }