Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: correctly serialize eth_call params #778

Merged
merged 1 commit into from
May 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions crates/contract/src/eth_call.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ mod private {

/// An [`alloy_provider::EthCall`] with an abi decoder.
#[must_use = "EthCall must be awaited to execute the call"]
#[derive(Debug, Clone)]
#[derive(Clone, Debug)]
pub struct EthCall<'req, 'state, 'coder, D, T, N>
where
T: Transport + Clone,
Expand Down Expand Up @@ -120,7 +120,7 @@ where
/// Future for the [`EthCall`] type. This future wraps an RPC call with an abi
/// decoder.
#[must_use = "futures do nothing unless you `.await` or poll them"]
#[derive(Debug, Clone)]
#[derive(Clone, Debug)]
pub struct EthCallFut<'req, 'state, 'coder, D, T, N>
where
T: Transport + Clone,
Expand Down
6 changes: 4 additions & 2 deletions crates/provider/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,21 +33,23 @@ async-stream = "0.3"
async-trait.workspace = true
auto_impl.workspace = true
dashmap = "5.5"
futures-utils-wasm.workspace = true
futures.workspace = true
lru = "0.12"
pin-project.workspace = true
reqwest = { workspace = true, optional = true }
serde_json.workspace = true
serde.workspace = true
tokio = { workspace = true, features = ["sync", "macros"] }
tracing.workspace = true
url = { workspace = true, optional = true }
futures-utils-wasm.workspace = true
pin-project.workspace = true

[dev-dependencies]
alloy-consensus = { workspace = true, features = ["std"] }
alloy-node-bindings.workspace = true
alloy-rpc-client = { workspace = true, features = ["reqwest"] }
alloy-rlp.workspace = true
alloy-sol-types.workspace = true
alloy-signer.workspace = true
alloy-signer-wallet.workspace = true
alloy-transport-http = { workspace = true, features = ["reqwest"] }
Expand Down
60 changes: 40 additions & 20 deletions crates/provider/src/provider/call.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,41 @@ 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::{self, Ready},
};

type RunningFut<'req, 'state, T, N> = RpcCall<
T,
(&'req <N as Network>::TransactionRequest, BlockId, Option<Cow<'state, StateOverride>>),
Bytes,
>;
use serde::ser::SerializeSeq;
use std::{future::Future, task::Poll};

type RunningFut<'req, 'state, T, N> = RpcCall<T, EthCallParams<'req, 'state, N>, Bytes>;

#[derive(Clone, Debug)]
struct EthCallParams<'req, 'state, N: Network> {
data: &'req N::TransactionRequest,
block: BlockId,
overrides: Option<&'state StateOverride>,
}

impl<N: Network> serde::Serialize for EthCallParams<'_, '_, N> {
fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
let len = if self.overrides.is_some() { 3 } else { 2 };
let mut seq = serializer.serialize_seq(Some(len))?;
seq.serialize_element(&self.data)?;
seq.serialize_element(&self.block)?;
if let Some(overrides) = self.overrides {
seq.serialize_element(overrides)?;
}
seq.end()
}
}

/// The [`EthCallFut`] future is the future type for an `eth_call` RPC request.
#[derive(Debug, Clone)]
pub enum EthCallFut<'req, 'state, T, N>
#[derive(Clone, Debug)]
#[doc(hidden)] // Not public API.
pub struct EthCallFut<'req, 'state, T, N>(EthCallFutInner<'req, 'state, T, N>)
where
T: Transport + Clone,
N: Network;

#[derive(Clone, Debug)]
enum EthCallFutInner<'req, 'state, T, N: Network>
where
T: Transport + Clone,
N: Network,
Expand All @@ -34,7 +54,7 @@ where
Polling,
}

impl<'req, 'state, T, N> EthCallFut<'req, 'state, T, N>
impl<'req, 'state, T, N> EthCallFutInner<'req, 'state, T, N>
where
T: Transport + Clone,
N: Network,
Expand All @@ -58,12 +78,12 @@ where

let client = match client.upgrade().ok_or_else(TransportErrorKind::backend_gone) {
Ok(client) => client,
Err(e) => return Ready(Err(e)),
Err(e) => return Poll::Ready(Err(e)),
};

let overrides = overrides.map(Cow::Borrowed);
let params = EthCallParams { data, block: block.unwrap_or_default(), overrides };

let fut = client.request("eth_call", (data, block.unwrap_or_default(), overrides));
let fut = client.request("eth_call", params);

*self = Self::Running(fut);
self.poll_running(cx)
Expand All @@ -87,7 +107,7 @@ where
self: std::pin::Pin<&mut Self>,
cx: &mut std::task::Context<'_>,
) -> std::task::Poll<Self::Output> {
let this = self.get_mut();
let this = &mut self.get_mut().0;
if this.is_preparing() {
this.poll_preparing(cx)
} else if this.is_running() {
Expand Down Expand Up @@ -155,11 +175,11 @@ where
type IntoFuture = EthCallFut<'req, 'state, T, N>;

fn into_future(self) -> Self::IntoFuture {
EthCallFut::Preparing {
EthCallFut(EthCallFutInner::Preparing {
client: self.client,
data: self.data,
overrides: self.overrides,
block: self.block,
}
})
}
}
19 changes: 19 additions & 0 deletions crates/provider/src/provider/trait.rs
Original file line number Diff line number Diff line change
Expand Up @@ -922,9 +922,11 @@ impl<T: Transport + Clone, N: Network> Provider<T, N> for RootProvider<T, N> {
mod tests {
use super::*;
use crate::{ProviderBuilder, WalletProvider};
use alloy_network::TransactionBuilder;
use alloy_node_bindings::Anvil;
use alloy_primitives::{address, b256, bytes};
use alloy_rpc_types::request::TransactionRequest;
use alloy_sol_types::SolValue;

fn init_tracing() {
let _ = tracing_subscriber::fmt::try_init();
Expand Down Expand Up @@ -1338,4 +1340,21 @@ mod tests {
let count = provider.get_uncle_count(0.into()).await.unwrap();
assert_eq!(count, 0);
}

#[tokio::test]
#[cfg(any(
feature = "reqwest-default-tls",
feature = "reqwest-rustls-tls",
feature = "reqwest-native-tls",
))]
async fn call_mainnet() {
init_tracing();
let url = "https://eth-mainnet.alchemyapi.io/v2/jGiK5vwDfC3F4r0bqukm-W2GqgdrxdSr";
let provider = ProviderBuilder::new().on_http(url.parse().unwrap());
let req = TransactionRequest::default()
.with_to(address!("c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2")) // WETH
.with_input(bytes!("06fdde03")); // `name()`
let result = provider.call(&req).await.unwrap();
assert_eq!(String::abi_decode(&result, true).unwrap(), "Wrapped Ether");
}
}
Loading