From 4dc11111b6c0352259461deca4e9c483c1dcf9b6 Mon Sep 17 00:00:00 2001 From: James Date: Tue, 21 May 2024 09:24:40 +0200 Subject: [PATCH 1/2] refactor: improve eth_call internals --- crates/provider/src/provider/call.rs | 105 +++++++++++++++------------ 1 file changed, 57 insertions(+), 48 deletions(-) diff --git a/crates/provider/src/provider/call.rs b/crates/provider/src/provider/call.rs index fd4e83ecc13..892e59b7d87 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,40 +39,47 @@ 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 { .. }) + } + + /// Returns `true` if the future is in the running state. + const fn is_running(&self) -> bool { + matches!(self, Self::Running(..)) + } + + 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)), }; - self.state = States::Running(fut); + 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( - self: std::pin::Pin<&mut Self>, - cx: &mut std::task::Context<'_>, - ) -> Poll> { - let Self { state: States::Running(call) } = self.get_mut() else { + fn poll_running(&mut self, cx: &mut std::task::Context<'_>) -> Poll> { + let Self::Running(mut call) = std::mem::replace(self, Self::Polling) else { unreachable!("bad state") }; - call.poll_unpin(cx) + if let Ready(res) = call.poll_unpin(cx) { + Ready(res) + } else { + *self = Self::Running(call); + Poll::Pending + } } } @@ -86,10 +94,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 +164,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 } + } } } From 662525a11e4dd32c8cc4208b695d3f503c5f7ac0 Mon Sep 17 00:00:00 2001 From: James Date: Tue, 21 May 2024 09:30:38 +0200 Subject: [PATCH 2/2] fix: remove unnecessary mem replace --- crates/provider/src/provider/call.rs | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/crates/provider/src/provider/call.rs b/crates/provider/src/provider/call.rs index 892e59b7d87..65ef1853bad 100644 --- a/crates/provider/src/provider/call.rs +++ b/crates/provider/src/provider/call.rs @@ -70,16 +70,9 @@ where } fn poll_running(&mut self, cx: &mut std::task::Context<'_>) -> Poll> { - let Self::Running(mut call) = std::mem::replace(self, Self::Polling) else { - unreachable!("bad state") - }; + let Self::Running(ref mut call) = self else { unreachable!("bad state") }; - if let Ready(res) = call.poll_unpin(cx) { - Ready(res) - } else { - *self = Self::Running(call); - Poll::Pending - } + call.poll_unpin(cx) } }