From 33cb14da8ff7c1fcb58e575453b2ed36b1ef657e Mon Sep 17 00:00:00 2001 From: DaniPopes <57450786+DaniPopes@users.noreply.github.com> Date: Tue, 31 Dec 2024 16:27:03 +0100 Subject: [PATCH 1/5] chore(deps): alloy 0.10 --- Cargo.toml | 12 +- examples/advanced/Cargo.toml | 10 +- examples/advanced/examples/reth_db_layer.rs | 24 -- .../advanced/examples/reth_db_provider.rs | 227 ------------------ 4 files changed, 15 insertions(+), 258 deletions(-) delete mode 100644 examples/advanced/examples/reth_db_layer.rs delete mode 100644 examples/advanced/examples/reth_db_provider.rs diff --git a/Cargo.toml b/Cargo.toml index f8699f2..a0e3335 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -128,5 +128,13 @@ serde = "1.0" serde_json = "1.0" [patch.crates-io] -# alloy = { git = "https://github.com/alloy-rs/alloy", rev = "65dfbe" } -# foundry-fork-db = { git = "https://github.com/foundry-rs/foundry-fork-db", rev = "d113d6e" } +alloy = { git = "https://github.com/alloy-rs/alloy", branch = "dani/rm-T-transport" } +alloy-consensus = { git = "https://github.com/alloy-rs/alloy", branch = "dani/rm-T-transport" } +alloy-provider = { git = "https://github.com/alloy-rs/alloy", branch = "dani/rm-T-transport" } +alloy-rpc-client = { git = "https://github.com/alloy-rs/alloy", branch = "dani/rm-T-transport" } +alloy-rpc-types = { git = "https://github.com/alloy-rs/alloy", branch = "dani/rm-T-transport" } +alloy-serde = { git = "https://github.com/alloy-rs/alloy", branch = "dani/rm-T-transport" } +alloy-transport = { git = "https://github.com/alloy-rs/alloy", branch = "dani/rm-T-transport" } +alloy-transport-http = { git = "https://github.com/alloy-rs/alloy", branch = "dani/rm-T-transport" } + +foundry-fork-db = { git = "https://github.com/foundry-rs/foundry-fork-db", branch = "dani/alloy-0.10" } diff --git a/examples/advanced/Cargo.toml b/examples/advanced/Cargo.toml index 7563a1d..cd76e73 100644 --- a/examples/advanced/Cargo.toml +++ b/examples/advanced/Cargo.toml @@ -19,11 +19,11 @@ revm-primitives.workspace = true revm.workspace = true # reth -reth-db = { git = "https://github.com/paradigmxyz/reth", package = "reth-db", rev = "c0a8a7b" } -reth-provider = { git = "https://github.com/paradigmxyz/reth", package = "reth-provider", rev = "c0a8a7b" } -reth-node-types = { git = "https://github.com/paradigmxyz/reth", package = "reth-node-types", rev = "c0a8a7b" } -reth-chainspec = { git = "https://github.com/paradigmxyz/reth", package = "reth-chainspec", rev = "c0a8a7b" } -reth-node-ethereum = { git = "https://github.com/paradigmxyz/reth", package = "reth-node-ethereum", rev = "c0a8a7b" } +# reth-db = { git = "https://github.com/paradigmxyz/reth", package = "reth-db", rev = "c0a8a7b" } +# reth-provider = { git = "https://github.com/paradigmxyz/reth", package = "reth-provider", rev = "c0a8a7b" } +# reth-node-types = { git = "https://github.com/paradigmxyz/reth", package = "reth-node-types", rev = "c0a8a7b" } +# reth-chainspec = { git = "https://github.com/paradigmxyz/reth", package = "reth-chainspec", rev = "c0a8a7b" } +# reth-node-ethereum = { git = "https://github.com/paradigmxyz/reth", package = "reth-node-ethereum", rev = "c0a8a7b" } eyre.workspace = true tokio = { workspace = true, features = ["macros", "rt-multi-thread"] } diff --git a/examples/advanced/examples/reth_db_layer.rs b/examples/advanced/examples/reth_db_layer.rs deleted file mode 100644 index 9945d26..0000000 --- a/examples/advanced/examples/reth_db_layer.rs +++ /dev/null @@ -1,24 +0,0 @@ -//! `RethDbLayer` implementation to be used with `RethDbProvider` to wrap the Provider trait over -//! reth-db. - -#![allow(dead_code)] -use std::path::PathBuf; - -/// We use the tower-like layering functionality that has been baked into the alloy-provider to -/// intercept the requests and redirect to the `RethDbProvider`. -pub(crate) struct RethDbLayer { - db_path: PathBuf, -} - -/// Initialize the `RethDBLayer` with the path to the reth datadir. -impl RethDbLayer { - pub(crate) const fn new(db_path: PathBuf) -> Self { - Self { db_path } - } - - pub(crate) const fn db_path(&self) -> &PathBuf { - &self.db_path - } -} - -const fn main() {} diff --git a/examples/advanced/examples/reth_db_provider.rs b/examples/advanced/examples/reth_db_provider.rs deleted file mode 100644 index 2b315cc..0000000 --- a/examples/advanced/examples/reth_db_provider.rs +++ /dev/null @@ -1,227 +0,0 @@ -//! In this example, we demonstrate how we wrap the `Provider` trait over reth-db by -//! leveraging `ProviderCall`. -//! -//! `ProviderCall` enables the alloy-provider to fetch results of a rpc request from arbitrary -//! sources. These arbitray sources could be a RPC call over the network, a local database, or even -//! a synchronous function call. -//! -//! `ProviderCall` is the final future in the flow of an rpc request and is used by the -//! `RpcWithBlock` and `EthCall` types under the hood to give flexibility to the user to use -//! their own implementation of the `Provider` trait and fetch results from any source. -//! -//! Learn more about `ProviderCall` [here](https://github.com/alloy-rs/alloy/pull/788). - -use std::{marker::PhantomData, path::PathBuf, sync::Arc}; - -use alloy::{ - eips::{BlockId, BlockNumberOrTag}, - node_bindings::{utils::run_with_tempdir, Reth}, - primitives::{address, Address, U64}, - providers::{ - Provider, ProviderBuilder, ProviderCall, ProviderLayer, RootProvider, RpcWithBlock, - }, - rpc::client::NoParams, - transports::{Transport, TransportErrorKind}, -}; -use eyre::Result; - -use reth_chainspec::ChainSpecBuilder; -use reth_db::{open_db_read_only, DatabaseEnv}; -use reth_node_ethereum::EthereumNode; -use reth_node_types::NodeTypesWithDBAdapter; -use reth_provider::{ - providers::StaticFileProvider, BlockNumReader, DatabaseProviderFactory, ProviderError, - ProviderFactory, StateProvider, TryIntoHistoricalStateProvider, -}; -mod reth_db_layer; -use reth_db_layer::RethDbLayer; - -#[tokio::main] -async fn main() -> Result<()> { - run_with_tempdir("provider-call-reth-db", |data_dir| async move { - // Initializing reth with a tmp data directory. - // We use a tmp directory for the purposes of this example. - // This would actually use an existing reth datadir specified by `--datadir` when starting - // your reth node. - let reth = Reth::new() - .dev() - .disable_discovery() - .block_time("1s") - .data_dir(data_dir.clone()) - .spawn(); - - let db_path = data_dir.join("db"); - - // Initialize the provider with the reth-db layer. The reth-db layer intercepts the rpc - // requests and returns the results from the reth-db database. - // Any RPC method that is not implemented in the RethDbProvider gracefully falls back to the - // RPC provider specified in the `on_http` method. - let provider = - ProviderBuilder::new().layer(RethDbLayer::new(db_path)).on_http(reth.endpoint_url()); - - // Initialize the RPC provider to compare the time taken to fetch the results. - let rpc_provider = ProviderBuilder::new().on_http(reth.endpoint_url()); - - println!("--------get_block_number---------"); - - let start_t = std::time::Instant::now(); - let latest_block_db = provider.get_block_number().await.unwrap(); - println!("via reth-db: {:?}", start_t.elapsed()); - - let start_t = std::time::Instant::now(); - let latest_block_rpc = rpc_provider.get_block_number().await.unwrap(); - println!("via rpc: {:?}\n", start_t.elapsed()); - - assert_eq!(latest_block_db, latest_block_rpc); - - println!("------get_transaction_count------"); - - let alice = address!("14dC79964da2C08b23698B3D3cc7Ca32193d9955"); - - let start_t = std::time::Instant::now(); - let nonce_db = - provider.get_transaction_count(alice).block_id(BlockId::latest()).await.unwrap(); - println!("via reth-db: {:?}", start_t.elapsed()); - - let start_t = std::time::Instant::now(); - let nonce_rpc = - rpc_provider.get_transaction_count(alice).block_id(BlockId::latest()).await.unwrap(); - println!("via rpc: {:?}\n", start_t.elapsed()); - - assert_eq!(nonce_db, nonce_rpc); - }) - .await; - - Ok(()) -} - -/// Implement the `ProviderLayer` trait for the `RethDBLayer` struct. -impl ProviderLayer for RethDbLayer -where - P: Provider, - T: Transport + Clone, -{ - type Provider = RethDbProvider; - - fn layer(&self, inner: P) -> Self::Provider { - RethDbProvider::new(inner, self.db_path().clone()) - } -} - -/// A provider that overrides the vanilla `Provider` trait to get results from the reth-db. -/// -/// It holds the `reth_provider::ProviderFactory` that enables read-only access to the database -/// tables and static files. -#[derive(Clone, Debug)] -pub struct RethDbProvider { - inner: P, - db_path: PathBuf, - provider_factory: DbAccessor, - _pd: PhantomData, -} - -impl RethDbProvider { - /// Create a new `RethDbProvider` instance. - pub fn new(inner: P, db_path: PathBuf) -> Self { - let db = open_db_read_only(&db_path, Default::default()).unwrap(); - let chain_spec = ChainSpecBuilder::mainnet().build(); - let static_file_provider = - StaticFileProvider::read_only(db_path.join("static_files"), false).unwrap(); - - let provider_factory = - ProviderFactory::new(db.into(), chain_spec.into(), static_file_provider); - - let db_accessor: DbAccessor< - ProviderFactory>>, - > = DbAccessor::new(provider_factory); - Self { inner, db_path, provider_factory: db_accessor, _pd: PhantomData } - } - - const fn factory(&self) -> &DbAccessor { - &self.provider_factory - } - - /// Get the DB Path - pub fn db_path(&self) -> PathBuf { - self.db_path.clone() - } -} - -/// Implement the `Provider` trait for the `RethDbProvider` struct. -/// -/// This is where we override specific RPC methods to fetch from the reth-db. -impl Provider for RethDbProvider -where - P: Provider, - T: Transport + Clone, -{ - fn root(&self) -> &RootProvider { - self.inner.root() - } - - /// Override the `get_block_number` method to fetch the latest block number from the reth-db. - fn get_block_number(&self) -> ProviderCall { - let provider = self.factory().provider().map_err(TransportErrorKind::custom).unwrap(); - - let best = provider.best_block_number().map_err(TransportErrorKind::custom); - - ProviderCall::ready(best) - } - - /// Override the `get_transaction_count` method to fetch the transaction count of an address. - /// - /// `RpcWithBlock` uses `ProviderCall` under the hood. - fn get_transaction_count(&self, address: Address) -> RpcWithBlock { - let this = self.factory().clone(); - RpcWithBlock::new_provider(move |block_id| { - let provider = this.provider_at(block_id).map_err(TransportErrorKind::custom).unwrap(); - - let maybe_acc = - provider.basic_account(&address).map_err(TransportErrorKind::custom).unwrap(); - - let nonce = maybe_acc.map(|acc| acc.nonce).unwrap_or_default(); - - ProviderCall::ready(Ok(nonce)) - }) - } -} - -/// A helper type to get the appropriate DB provider. -#[derive(Debug, Clone)] -struct DbAccessor>>> -where - DB: DatabaseProviderFactory, -{ - inner: DB, -} - -impl DbAccessor -where - DB: DatabaseProviderFactory, -{ - const fn new(inner: DB) -> Self { - Self { inner } - } - - fn provider(&self) -> Result { - self.inner.database_provider_ro() - } - - fn provider_at(&self, block_id: BlockId) -> Result, ProviderError> { - let provider = self.inner.database_provider_ro()?; - - let block_number = match block_id { - BlockId::Hash(hash) => { - if let Some(num) = provider.block_number(hash.into())? { - num - } else { - return Err(ProviderError::BlockHashNotFound(hash.into())); - } - } - BlockId::Number(BlockNumberOrTag::Number(num)) => num, - _ => provider.best_block_number()?, - }; - - provider.try_into_history_at_block(block_number) - } -} From 88d6222034b17dddce09b1632109a017d4086cec Mon Sep 17 00:00:00 2001 From: Yash Atreya <44857776+yash-atreya@users.noreply.github.com> Date: Mon, 6 Jan 2025 20:25:31 +0530 Subject: [PATCH 2/5] feat(`providers`): wrapped provider --- .../providers/examples/wrapped_provider.rs | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 examples/providers/examples/wrapped_provider.rs diff --git a/examples/providers/examples/wrapped_provider.rs b/examples/providers/examples/wrapped_provider.rs new file mode 100644 index 0000000..d3494f4 --- /dev/null +++ b/examples/providers/examples/wrapped_provider.rs @@ -0,0 +1,41 @@ +//! Example demonstrating how to wrap a provider in a custom type. + +use alloy::{ + providers::{Provider, ProviderBuilder}, + transports::TransportResult, +}; +use eyre::Result; + +/// Simple free function to get the latest block number. +async fn get_block_number(provider: &P) -> TransportResult { + provider.get_block_number().await +} + +/// Wrapped provider type. +struct MyProvider { + provider: P, +} + +impl MyProvider

{ + /// Create a new instance of `MyProvider`. + fn new(provider: P) -> Self { + Self { provider } + } + + async fn get_block_number(&self) -> TransportResult { + get_block_number(&self.provider).await + } +} + +#[tokio::main] +async fn main() -> Result<()> { + let provider = ProviderBuilder::new().on_anvil(); + + let my_provider = MyProvider::new(provider); + + let latest_block = my_provider.get_block_number().await?; + + println!("Latest block number: {latest_block}"); + + Ok(()) +} From c43e3de9079fd53b67816c05187e81a3ba3fec48 Mon Sep 17 00:00:00 2001 From: Yash Atreya <44857776+yash-atreya@users.noreply.github.com> Date: Tue, 7 Jan 2025 22:37:42 +0530 Subject: [PATCH 3/5] fix --- .../providers/examples/wrapped_provider.rs | 71 +++++++++++++++---- 1 file changed, 59 insertions(+), 12 deletions(-) diff --git a/examples/providers/examples/wrapped_provider.rs b/examples/providers/examples/wrapped_provider.rs index d3494f4..a5d9728 100644 --- a/examples/providers/examples/wrapped_provider.rs +++ b/examples/providers/examples/wrapped_provider.rs @@ -1,41 +1,88 @@ -//! Example demonstrating how to wrap a provider in a custom type. +//! Example demonstrating how to wrap the [`Provider`] in a struct and pass it through free +//! functions. use alloy::{ + network::EthereumWallet, + node_bindings::Anvil, + primitives::Address, providers::{Provider, ProviderBuilder}, + signers::local::PrivateKeySigner, + sol, transports::TransportResult, }; use eyre::Result; +use Counter::CounterInstance; + +/// Creates and returns an implementation of the [`Provider`] trait. +async fn get_provider(url: &str) -> TransportResult { + ProviderBuilder::new().with_recommended_fillers().on_builtin(url).await +} /// Simple free function to get the latest block number. async fn get_block_number(provider: &P) -> TransportResult { provider.get_block_number().await } -/// Wrapped provider type. -struct MyProvider { +/// Deployer that ingests a [`Provider`] and [`EthereumWallet`] and deploys [`Counter`] +struct Deployer { provider: P, + wallet: EthereumWallet, } -impl MyProvider

{ +impl Deployer

{ /// Create a new instance of `MyProvider`. - fn new(provider: P) -> Self { - Self { provider } + fn new(provider: P, private_key: PrivateKeySigner) -> Self { + let wallet = EthereumWallet::new(private_key); + Self { provider, wallet } } - async fn get_block_number(&self) -> TransportResult { - get_block_number(&self.provider).await + /// Deploys [`Counter`] using the given [`EthereumWallet`] and returns the address it was + /// deployed at. + async fn deploy(&self) -> Result

{ + CounterInstance::deploy_builder(&self.provider) + .from(self.wallet.default_signer().address()) + .deploy() + .await + .map_err(Into::into) } } #[tokio::main] async fn main() -> Result<()> { - let provider = ProviderBuilder::new().on_anvil(); - - let my_provider = MyProvider::new(provider); + let anvil = Anvil::new().spawn(); - let latest_block = my_provider.get_block_number().await?; + let provider = get_provider(&anvil.endpoint()).await?; + let latest_block = get_block_number(&provider).await?; println!("Latest block number: {latest_block}"); + let signer_pk = "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80".parse()?; + let counter_address = Deployer::new(&provider, signer_pk).deploy().await?; + + println!("Deployed `Counter` at {counter_address}"); + + let counter = CounterInstance::new(counter_address, provider); + let num = counter.number().call().await?.number.to::(); + + println!("Current Number {num}"); + Ok(()) } + +// Codegen from embedded Solidity code and precompiled bytecode. +sol! { + #[allow(missing_docs)] + // solc v0.8.26; solc Counter.sol --via-ir --optimize --bin + #[sol(rpc, bytecode="6080806040523460135760df908160198239f35b600080fdfe6080806040526004361015601257600080fd5b60003560e01c9081633fb5c1cb1460925781638381f58a146079575063d09de08a14603c57600080fd5b3460745760003660031901126074576000546000198114605e57600101600055005b634e487b7160e01b600052601160045260246000fd5b600080fd5b3460745760003660031901126074576020906000548152f35b34607457602036600319011260745760043560005500fea2646970667358221220e978270883b7baed10810c4079c941512e93a7ba1cd1108c781d4bc738d9090564736f6c634300081a0033")] + contract Counter { + uint256 public number; + + function setNumber(uint256 newNumber) public { + number = newNumber; + } + + function increment() public { + number++; + } + } +} From e4fada2245ac88f05bbcd78f54a66e5e6ade8876 Mon Sep 17 00:00:00 2001 From: Yash Atreya <44857776+yash-atreya@users.noreply.github.com> Date: Tue, 7 Jan 2025 22:49:51 +0530 Subject: [PATCH 4/5] return instance --- .../providers/examples/wrapped_provider.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/examples/providers/examples/wrapped_provider.rs b/examples/providers/examples/wrapped_provider.rs index a5d9728..1cc3f92 100644 --- a/examples/providers/examples/wrapped_provider.rs +++ b/examples/providers/examples/wrapped_provider.rs @@ -4,11 +4,10 @@ use alloy::{ network::EthereumWallet, node_bindings::Anvil, - primitives::Address, providers::{Provider, ProviderBuilder}, signers::local::PrivateKeySigner, sol, - transports::TransportResult, + transports::{BoxTransport, TransportResult}, }; use eyre::Result; use Counter::CounterInstance; @@ -38,12 +37,13 @@ impl Deployer

{ /// Deploys [`Counter`] using the given [`EthereumWallet`] and returns the address it was /// deployed at. - async fn deploy(&self) -> Result

{ - CounterInstance::deploy_builder(&self.provider) + async fn deploy(&self) -> Result> { + let addr = CounterInstance::deploy_builder(&self.provider) .from(self.wallet.default_signer().address()) .deploy() - .await - .map_err(Into::into) + .await?; + + Ok(CounterInstance::new(addr, &self.provider)) } } @@ -57,11 +57,11 @@ async fn main() -> Result<()> { println!("Latest block number: {latest_block}"); let signer_pk = "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80".parse()?; - let counter_address = Deployer::new(&provider, signer_pk).deploy().await?; + let deployer = Deployer::new(&provider, signer_pk); + let counter = deployer.deploy().await?; - println!("Deployed `Counter` at {counter_address}"); + println!("Deployed `Counter` at {}", counter.address()); - let counter = CounterInstance::new(counter_address, provider); let num = counter.number().call().await?.number.to::(); println!("Current Number {num}"); From d9afe82ecbf323159be18e7aa60489d291e67390 Mon Sep 17 00:00:00 2001 From: Yash Atreya <44857776+yash-atreya@users.noreply.github.com> Date: Tue, 7 Jan 2025 22:50:34 +0530 Subject: [PATCH 5/5] nit --- examples/providers/examples/wrapped_provider.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/examples/providers/examples/wrapped_provider.rs b/examples/providers/examples/wrapped_provider.rs index 1cc3f92..512458c 100644 --- a/examples/providers/examples/wrapped_provider.rs +++ b/examples/providers/examples/wrapped_provider.rs @@ -29,14 +29,13 @@ struct Deployer { } impl Deployer

{ - /// Create a new instance of `MyProvider`. + /// Create a new instance of [`Deployer`]. fn new(provider: P, private_key: PrivateKeySigner) -> Self { let wallet = EthereumWallet::new(private_key); Self { provider, wallet } } - /// Deploys [`Counter`] using the given [`EthereumWallet`] and returns the address it was - /// deployed at. + /// Deploys [`Counter`] using the given [`EthereumWallet`] and returns [`CounterInstance`] async fn deploy(&self) -> Result> { let addr = CounterInstance::deploy_builder(&self.provider) .from(self.wallet.default_signer().address())