diff --git a/crates/provider/src/provider/call.rs b/crates/provider/src/provider/call.rs index fd4e83ecc13..65ef1853bad 100644 --- a/crates/provider/src/provider/call.rs +++ b/crates/provider/src/provider/call.rs @@ -5,11 +5,21 @@ use alloy_rpc_client::{RpcCall, WeakClient}; use alloy_rpc_types::state::StateOverride; use alloy_transport::{Transport, TransportErrorKind, TransportResult}; use futures::FutureExt; -use std::{borrow::Cow, future::Future, task::Poll}; - -/// States for the [`EthCallFut`] future. +use std::{ + borrow::Cow, + future::Future, + task::Poll::{self, Ready}, +}; + +type RunningFut<'req, 'state, T, N> = RpcCall< + T, + (&'req ::TransactionRequest, BlockId, Option>), + Bytes, +>; + +/// The [`EthCallFut`] future is the future type for an `eth_call` RPC request. #[derive(Debug, Clone)] -enum States<'req, 'state, T, N> +pub enum EthCallFut<'req, 'state, T, N> where T: Transport + Clone, N: Network, @@ -20,17 +30,8 @@ where overrides: Option<&'state StateOverride>, block: Option, }, - Running(RpcCall), Bytes>), -} - -/// Future for [`EthCall`]. Simple wrapper around [`RpcCall`]. -#[derive(Debug, Clone)] -pub struct EthCallFut<'req, 'state, T, N> -where - T: Transport + Clone, - N: Network, -{ - state: States<'req, 'state, T, N>, + Running(RunningFut<'req, 'state, T, N>), + Polling, } impl<'req, 'state, T, N> EthCallFut<'req, 'state, T, N> @@ -38,39 +39,39 @@ where T: Transport + Clone, N: Network, { - fn poll_preparing( - mut self: std::pin::Pin<&mut Self>, - cx: &mut std::task::Context<'_>, - ) -> Poll> { - let fut = { - let States::Preparing { client, data, overrides, block } = &self.as_ref().state else { - unreachable!("bad state") - }; - - let client = match client.upgrade().ok_or_else(TransportErrorKind::backend_gone) { - Ok(client) => client, - Err(e) => return std::task::Poll::Ready(Err(e)), - }; - - let overrides = match overrides { - Some(overrides) => Cow::Borrowed(*overrides), - None => Cow::Owned(StateOverride::default()), - }; - client.request("eth_call", (*data, block.unwrap_or_default(), overrides)) - }; + /// Returns `true` if the future is in the preparing state. + const fn is_preparing(&self) -> bool { + matches!(self, Self::Preparing { .. }) + } - self.state = States::Running(fut); - self.poll_running(cx) + /// Returns `true` if the future is in the running state. + const fn is_running(&self) -> bool { + matches!(self, Self::Running(..)) } - fn poll_running( - self: std::pin::Pin<&mut Self>, - cx: &mut std::task::Context<'_>, - ) -> Poll> { - let Self { state: States::Running(call) } = self.get_mut() else { + fn poll_preparing(&mut self, cx: &mut std::task::Context<'_>) -> Poll> { + let Self::Preparing { client, data, overrides, block } = + std::mem::replace(self, Self::Polling) + else { unreachable!("bad state") }; + let client = match client.upgrade().ok_or_else(TransportErrorKind::backend_gone) { + Ok(client) => client, + Err(e) => return Ready(Err(e)), + }; + + let overrides = overrides.map(Cow::Borrowed); + + let fut = client.request("eth_call", (data, block.unwrap_or_default(), overrides)); + + *self = Self::Running(fut); + self.poll_running(cx) + } + + fn poll_running(&mut self, cx: &mut std::task::Context<'_>) -> Poll> { + let Self::Running(ref mut call) = self else { unreachable!("bad state") }; + call.poll_unpin(cx) } } @@ -86,10 +87,13 @@ where self: std::pin::Pin<&mut Self>, cx: &mut std::task::Context<'_>, ) -> std::task::Poll { - if matches!(self.state, States::Preparing { .. }) { - self.poll_preparing(cx) + let this = self.get_mut(); + if this.is_preparing() { + this.poll_preparing(cx) + } else if this.is_running() { + this.poll_running(cx) } else { - self.poll_running(cx) + panic!("unexpected state") } } } @@ -153,13 +157,11 @@ where type IntoFuture = EthCallFut<'req, 'state, T, N>; fn into_future(self) -> Self::IntoFuture { - let state = States::Preparing { + EthCallFut::Preparing { client: self.client, data: self.data, overrides: self.overrides, block: self.block, - }; - - EthCallFut { state } + } } }