From 9fc74aeea0ec97747a25e04fffc14c681916b203 Mon Sep 17 00:00:00 2001 From: Omar Abdulla Date: Wed, 17 Sep 2025 05:47:13 +0300 Subject: [PATCH] Groundwork for dyn traits --- Cargo.lock | 1 + crates/config/src/lib.rs | 31 +++ crates/core/src/lib.rs | 12 +- crates/format/src/input.rs | 63 +++-- crates/format/src/traits.rs | 37 ++- crates/node-interaction/Cargo.toml | 2 + crates/node-interaction/src/lib.rs | 4 + crates/node/src/geth.rs | 342 +++++++++++++++++++------ crates/node/src/kitchensink.rs | 385 +++++++++++++++++++++-------- 9 files changed, 665 insertions(+), 212 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e7e9684..70a373a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4584,6 +4584,7 @@ version = "0.1.0" dependencies = [ "alloy", "anyhow", + "revive-dt-format", ] [[package]] diff --git a/crates/config/src/lib.rs b/crates/config/src/lib.rs index 8141dfa..21bb27e 100644 --- a/crates/config/src/lib.rs +++ b/crates/config/src/lib.rs @@ -564,3 +564,34 @@ pub enum TestingPlatform { /// The kitchensink runtime provides the PolkaVM (PVM) based node implementation. Kitchensink, } + +/// An enum of the platform identifiers of all of the platforms supported by this framework. +#[derive( + Clone, + Copy, + Debug, + PartialEq, + Eq, + PartialOrd, + Ord, + Hash, + Serialize, + ValueEnum, + EnumString, + Display, + AsRefStr, + IntoStaticStr, +)] +#[strum(serialize_all = "kebab-case")] +pub enum PlatformIdentifier { + /// The Go-ethereum reference full node EVM implementation. + GethEvm, + /// The kitchensink node with the PolkaVM backend. + KitchensinkPolkaVM, + /// The kitchensink node with the REVM backend. + KitchensinkREVM, + /// The revive dev node with the PolkaVM backend. + ReviveDevNodePolkaVM, + /// The revive dev node with the REVM backend. + ReviveDevNodeREVM, +} diff --git a/crates/core/src/lib.rs b/crates/core/src/lib.rs index b729b42..b2a0db9 100644 --- a/crates/core/src/lib.rs +++ b/crates/core/src/lib.rs @@ -4,7 +4,7 @@ //! provides a helper utility to execute tests. use revive_dt_compiler::{SolidityCompiler, revive_resolc, solc}; -use revive_dt_config::TestingPlatform; +use revive_dt_config::{PlatformIdentifier, TestingPlatform}; use revive_dt_format::traits::ResolverApi; use revive_dt_node::{Node, geth, kitchensink::KitchensinkNode}; use revive_dt_node_interaction::EthereumNode; @@ -45,3 +45,13 @@ impl Platform for Kitchensink { &TestingPlatform::Kitchensink } } + +/// A trait that describes the interface for the platforms that are supported by the tool. +pub trait DynPlatform { + /// Returns the identifier of this platform. + fn platform_identifier(&self) -> PlatformIdentifier; + + /// Creates a new node for the platform by spawning a new thread, creating the node object, + /// initializing it, spawning it, and waiting for it to start up. + fn new_node(&self) -> Box; +} diff --git a/crates/format/src/input.rs b/crates/format/src/input.rs index d57f18e..66abc42 100644 --- a/crates/format/src/input.rs +++ b/crates/format/src/input.rs @@ -695,7 +695,7 @@ impl> CalldataToken { context .transaction_hash() .context("No transaction hash provided to get the transaction gas price") - .map(|tx_hash| resolver.transaction_gas_price(tx_hash))? + .map(|tx_hash| resolver.transaction_gas_price(*tx_hash))? .await .map(U256::from) } else if item == Self::GAS_LIMIT_VARIABLE { @@ -799,7 +799,7 @@ mod tests { use alloy::{eips::BlockNumberOrTag, json_abi::JsonAbi}; use alloy_primitives::{BlockHash, BlockNumber, BlockTimestamp, ChainId, TxHash, address}; use alloy_sol_types::SolValue; - use std::collections::HashMap; + use std::{collections::HashMap, pin::Pin}; use super::*; use crate::metadata::ContractIdent; @@ -807,40 +807,63 @@ mod tests { struct MockResolver; impl ResolverApi for MockResolver { - async fn chain_id(&self) -> anyhow::Result { - Ok(0x123) + fn chain_id(&self) -> Pin> + '_>> { + Box::pin(async move { Ok(0x123) }) } - async fn block_gas_limit(&self, _: BlockNumberOrTag) -> anyhow::Result { - Ok(0x1234) + fn block_gas_limit( + &self, + _: BlockNumberOrTag, + ) -> Pin> + '_>> { + Box::pin(async move { Ok(0x1234) }) } - async fn block_coinbase(&self, _: BlockNumberOrTag) -> anyhow::Result
{ - Ok(Address::ZERO) + fn block_coinbase( + &self, + _: BlockNumberOrTag, + ) -> Pin> + '_>> { + Box::pin(async move { Ok(Address::ZERO) }) } - async fn block_difficulty(&self, _: BlockNumberOrTag) -> anyhow::Result { - Ok(U256::from(0x12345u128)) + fn block_difficulty( + &self, + _: BlockNumberOrTag, + ) -> Pin> + '_>> { + Box::pin(async move { Ok(U256::from(0x12345u128)) }) } - async fn block_base_fee(&self, _: BlockNumberOrTag) -> anyhow::Result { - Ok(0x100) + fn block_base_fee( + &self, + _: BlockNumberOrTag, + ) -> Pin> + '_>> { + Box::pin(async move { Ok(0x100) }) } - async fn block_hash(&self, _: BlockNumberOrTag) -> anyhow::Result { - Ok([0xEE; 32].into()) + fn block_hash( + &self, + _: BlockNumberOrTag, + ) -> Pin> + '_>> { + Box::pin(async move { Ok([0xEE; 32].into()) }) } - async fn block_timestamp(&self, _: BlockNumberOrTag) -> anyhow::Result { - Ok(0x123456) + fn block_timestamp( + &self, + _: BlockNumberOrTag, + ) -> Pin> + '_>> { + Box::pin(async move { Ok(0x123456) }) } - async fn last_block_number(&self) -> anyhow::Result { - Ok(0x1234567) + fn last_block_number( + &self, + ) -> Pin> + '_>> { + Box::pin(async move { Ok(0x1234567) }) } - async fn transaction_gas_price(&self, _: &TxHash) -> anyhow::Result { - Ok(0x200) + fn transaction_gas_price( + &self, + _: TxHash, + ) -> Pin> + '_>> { + Box::pin(async move { Ok(0x200) }) } } diff --git a/crates/format/src/traits.rs b/crates/format/src/traits.rs index 1ad6cc3..11395fd 100644 --- a/crates/format/src/traits.rs +++ b/crates/format/src/traits.rs @@ -1,4 +1,5 @@ use std::collections::HashMap; +use std::pin::Pin; use alloy::eips::BlockNumberOrTag; use alloy::json_abi::JsonAbi; @@ -12,36 +13,54 @@ use crate::metadata::{ContractIdent, ContractInstance}; /// crate implements to go from string calldata and into the bytes calldata. pub trait ResolverApi { /// Returns the ID of the chain that the node is on. - fn chain_id(&self) -> impl Future>; + fn chain_id(&self) -> Pin> + '_>>; /// Returns the gas price for the specified transaction. - fn transaction_gas_price(&self, tx_hash: &TxHash) -> impl Future>; + fn transaction_gas_price( + &self, + tx_hash: TxHash, + ) -> Pin> + '_>>; // TODO: This is currently a u128 due to Kitchensink needing more than 64 bits for its gas limit // when we implement the changes to the gas we need to adjust this to be a u64. /// Returns the gas limit of the specified block. - fn block_gas_limit(&self, number: BlockNumberOrTag) -> impl Future>; + fn block_gas_limit( + &self, + number: BlockNumberOrTag, + ) -> Pin> + '_>>; /// Returns the coinbase of the specified block. - fn block_coinbase(&self, number: BlockNumberOrTag) -> impl Future>; + fn block_coinbase( + &self, + number: BlockNumberOrTag, + ) -> Pin> + '_>>; /// Returns the difficulty of the specified block. - fn block_difficulty(&self, number: BlockNumberOrTag) -> impl Future>; + fn block_difficulty( + &self, + number: BlockNumberOrTag, + ) -> Pin> + '_>>; /// Returns the base fee of the specified block. - fn block_base_fee(&self, number: BlockNumberOrTag) -> impl Future>; + fn block_base_fee( + &self, + number: BlockNumberOrTag, + ) -> Pin> + '_>>; /// Returns the hash of the specified block. - fn block_hash(&self, number: BlockNumberOrTag) -> impl Future>; + fn block_hash( + &self, + number: BlockNumberOrTag, + ) -> Pin> + '_>>; /// Returns the timestamp of the specified block, fn block_timestamp( &self, number: BlockNumberOrTag, - ) -> impl Future>; + ) -> Pin> + '_>>; /// Returns the number of the last block. - fn last_block_number(&self) -> impl Future>; + fn last_block_number(&self) -> Pin> + '_>>; } #[derive(Clone, Copy, Debug, Default)] diff --git a/crates/node-interaction/Cargo.toml b/crates/node-interaction/Cargo.toml index c5c002e..5865690 100644 --- a/crates/node-interaction/Cargo.toml +++ b/crates/node-interaction/Cargo.toml @@ -9,6 +9,8 @@ repository.workspace = true rust-version.workspace = true [dependencies] +revive-dt-format = { workspace = true } + alloy = { workspace = true } anyhow = { workspace = true } diff --git a/crates/node-interaction/src/lib.rs b/crates/node-interaction/src/lib.rs index a6e3b38..d44cebb 100644 --- a/crates/node-interaction/src/lib.rs +++ b/crates/node-interaction/src/lib.rs @@ -4,6 +4,7 @@ use alloy::primitives::{Address, StorageKey, U256}; use alloy::rpc::types::trace::geth::{DiffMode, GethDebugTracingOptions, GethTrace}; use alloy::rpc::types::{EIP1186AccountProofResponse, TransactionReceipt, TransactionRequest}; use anyhow::Result; +use revive_dt_format::traits::ResolverApi; /// An interface for all interactions with Ethereum compatible nodes. pub trait EthereumNode { @@ -32,4 +33,7 @@ pub trait EthereumNode { address: Address, keys: Vec, ) -> impl Future>; + + /// Returns the resolver that is to use with this ethereum node. + fn resolver(&self) -> impl Future>>; } diff --git a/crates/node/src/geth.rs b/crates/node/src/geth.rs index 13c32de..5b0e423 100644 --- a/crates/node/src/geth.rs +++ b/crates/node/src/geth.rs @@ -5,6 +5,7 @@ use std::{ io::{BufRead, BufReader, Read, Write}, ops::ControlFlow, path::PathBuf, + pin::Pin, process::{Child, Command, Stdio}, sync::{ Arc, @@ -438,115 +439,294 @@ impl EthereumNode for GethNode { .await .map_err(Into::into) } + + #[instrument(level = "info", skip_all, fields(geth_node_id = self.id))] + fn resolver(&self) -> impl Future>> { + Box::pin(async move { + let id = self.id; + let provider = self.provider().await?; + Ok(Box::new(GethNodeResolver { id, provider }) as Box) + }) + } } +pub struct GethNodeResolver, P: Provider> { + id: u32, + provider: FillProvider, +} + +impl, P: Provider> ResolverApi for GethNodeResolver { + #[instrument(level = "info", skip_all, fields(geth_node_id = self.id))] + fn chain_id( + &self, + ) -> Pin> + '_>> { + Box::pin(async move { self.provider.get_chain_id().await.map_err(Into::into) }) + } + + #[instrument(level = "info", skip_all, fields(geth_node_id = self.id))] + fn transaction_gas_price( + &self, + tx_hash: TxHash, + ) -> Pin> + '_>> { + Box::pin(async move { + self.provider + .get_transaction_receipt(tx_hash) + .await? + .context("Failed to get the transaction receipt") + .map(|receipt| receipt.effective_gas_price) + }) + } + + #[instrument(level = "info", skip_all, fields(geth_node_id = self.id))] + fn block_gas_limit( + &self, + number: BlockNumberOrTag, + ) -> Pin> + '_>> { + Box::pin(async move { + self.provider + .get_block_by_number(number) + .await + .context("Failed to get the geth block")? + .context("Failed to get the Geth block, perhaps there are no blocks?") + .map(|block| block.header.gas_limit as _) + }) + } + + #[instrument(level = "info", skip_all, fields(geth_node_id = self.id))] + fn block_coinbase( + &self, + number: BlockNumberOrTag, + ) -> Pin> + '_>> { + Box::pin(async move { + self.provider + .get_block_by_number(number) + .await + .context("Failed to get the geth block")? + .context("Failed to get the Geth block, perhaps there are no blocks?") + .map(|block| block.header.beneficiary) + }) + } + + #[instrument(level = "info", skip_all, fields(geth_node_id = self.id))] + fn block_difficulty( + &self, + number: BlockNumberOrTag, + ) -> Pin> + '_>> { + Box::pin(async move { + self.provider + .get_block_by_number(number) + .await + .context("Failed to get the geth block")? + .context("Failed to get the Geth block, perhaps there are no blocks?") + .map(|block| U256::from_be_bytes(block.header.mix_hash.0)) + }) + } + + #[instrument(level = "info", skip_all, fields(geth_node_id = self.id))] + fn block_base_fee( + &self, + number: BlockNumberOrTag, + ) -> Pin> + '_>> { + Box::pin(async move { + self.provider + .get_block_by_number(number) + .await + .context("Failed to get the geth block")? + .context("Failed to get the Geth block, perhaps there are no blocks?") + .and_then(|block| { + block + .header + .base_fee_per_gas + .context("Failed to get the base fee per gas") + }) + }) + } + + #[instrument(level = "info", skip_all, fields(geth_node_id = self.id))] + fn block_hash( + &self, + number: BlockNumberOrTag, + ) -> Pin> + '_>> { + Box::pin(async move { + self.provider + .get_block_by_number(number) + .await + .context("Failed to get the geth block")? + .context("Failed to get the Geth block, perhaps there are no blocks?") + .map(|block| block.header.hash) + }) + } + + #[instrument(level = "info", skip_all, fields(geth_node_id = self.id))] + fn block_timestamp( + &self, + number: BlockNumberOrTag, + ) -> Pin> + '_>> { + Box::pin(async move { + self.provider + .get_block_by_number(number) + .await + .context("Failed to get the geth block")? + .context("Failed to get the Geth block, perhaps there are no blocks?") + .map(|block| block.header.timestamp) + }) + } + + #[instrument(level = "info", skip_all, fields(geth_node_id = self.id))] + fn last_block_number(&self) -> Pin> + '_>> { + Box::pin(async move { self.provider.get_block_number().await.map_err(Into::into) }) + } +} + +// TODO: Remove impl ResolverApi for GethNode { #[instrument(level = "info", skip_all, fields(geth_node_id = self.id))] - async fn chain_id(&self) -> anyhow::Result { - self.provider() - .await - .context("Failed to get the Geth provider")? - .get_chain_id() - .await - .map_err(Into::into) + fn chain_id( + &self, + ) -> Pin> + '_>> { + Box::pin(async move { + self.provider() + .await + .context("Failed to get the Geth provider")? + .get_chain_id() + .await + .map_err(Into::into) + }) } #[instrument(level = "info", skip_all, fields(geth_node_id = self.id))] - async fn transaction_gas_price(&self, tx_hash: &TxHash) -> anyhow::Result { - self.provider() - .await - .context("Failed to get the Geth provider")? - .get_transaction_receipt(*tx_hash) - .await? - .context("Failed to get the transaction receipt") - .map(|receipt| receipt.effective_gas_price) + fn transaction_gas_price( + &self, + tx_hash: TxHash, + ) -> Pin> + '_>> { + Box::pin(async move { + self.provider() + .await + .context("Failed to get the Geth provider")? + .get_transaction_receipt(tx_hash) + .await? + .context("Failed to get the transaction receipt") + .map(|receipt| receipt.effective_gas_price) + }) } #[instrument(level = "info", skip_all, fields(geth_node_id = self.id))] - async fn block_gas_limit(&self, number: BlockNumberOrTag) -> anyhow::Result { - self.provider() - .await - .context("Failed to get the Geth provider")? - .get_block_by_number(number) - .await - .context("Failed to get the geth block")? - .context("Failed to get the Geth block, perhaps there are no blocks?") - .map(|block| block.header.gas_limit as _) + fn block_gas_limit( + &self, + number: BlockNumberOrTag, + ) -> Pin> + '_>> { + Box::pin(async move { + self.provider() + .await + .context("Failed to get the Geth provider")? + .get_block_by_number(number) + .await + .context("Failed to get the geth block")? + .context("Failed to get the Geth block, perhaps there are no blocks?") + .map(|block| block.header.gas_limit as _) + }) } #[instrument(level = "info", skip_all, fields(geth_node_id = self.id))] - async fn block_coinbase(&self, number: BlockNumberOrTag) -> anyhow::Result
{ - self.provider() - .await - .context("Failed to get the Geth provider")? - .get_block_by_number(number) - .await - .context("Failed to get the geth block")? - .context("Failed to get the Geth block, perhaps there are no blocks?") - .map(|block| block.header.beneficiary) + fn block_coinbase( + &self, + number: BlockNumberOrTag, + ) -> Pin> + '_>> { + Box::pin(async move { + self.provider() + .await + .context("Failed to get the Geth provider")? + .get_block_by_number(number) + .await + .context("Failed to get the geth block")? + .context("Failed to get the Geth block, perhaps there are no blocks?") + .map(|block| block.header.beneficiary) + }) } #[instrument(level = "info", skip_all, fields(geth_node_id = self.id))] - async fn block_difficulty(&self, number: BlockNumberOrTag) -> anyhow::Result { - self.provider() - .await - .context("Failed to get the Geth provider")? - .get_block_by_number(number) - .await - .context("Failed to get the geth block")? - .context("Failed to get the Geth block, perhaps there are no blocks?") - .map(|block| U256::from_be_bytes(block.header.mix_hash.0)) + fn block_difficulty( + &self, + number: BlockNumberOrTag, + ) -> Pin> + '_>> { + Box::pin(async move { + self.provider() + .await + .context("Failed to get the Geth provider")? + .get_block_by_number(number) + .await + .context("Failed to get the geth block")? + .context("Failed to get the Geth block, perhaps there are no blocks?") + .map(|block| U256::from_be_bytes(block.header.mix_hash.0)) + }) } #[instrument(level = "info", skip_all, fields(geth_node_id = self.id))] - async fn block_base_fee(&self, number: BlockNumberOrTag) -> anyhow::Result { - self.provider() - .await - .context("Failed to get the Geth provider")? - .get_block_by_number(number) - .await - .context("Failed to get the geth block")? - .context("Failed to get the Geth block, perhaps there are no blocks?") - .and_then(|block| { - block - .header - .base_fee_per_gas - .context("Failed to get the base fee per gas") - }) + fn block_base_fee( + &self, + number: BlockNumberOrTag, + ) -> Pin> + '_>> { + Box::pin(async move { + self.provider() + .await + .context("Failed to get the Geth provider")? + .get_block_by_number(number) + .await + .context("Failed to get the geth block")? + .context("Failed to get the Geth block, perhaps there are no blocks?") + .and_then(|block| { + block + .header + .base_fee_per_gas + .context("Failed to get the base fee per gas") + }) + }) } #[instrument(level = "info", skip_all, fields(geth_node_id = self.id))] - async fn block_hash(&self, number: BlockNumberOrTag) -> anyhow::Result { - self.provider() - .await - .context("Failed to get the Geth provider")? - .get_block_by_number(number) - .await - .context("Failed to get the geth block")? - .context("Failed to get the Geth block, perhaps there are no blocks?") - .map(|block| block.header.hash) + fn block_hash( + &self, + number: BlockNumberOrTag, + ) -> Pin> + '_>> { + Box::pin(async move { + self.provider() + .await + .context("Failed to get the Geth provider")? + .get_block_by_number(number) + .await + .context("Failed to get the geth block")? + .context("Failed to get the Geth block, perhaps there are no blocks?") + .map(|block| block.header.hash) + }) } #[instrument(level = "info", skip_all, fields(geth_node_id = self.id))] - async fn block_timestamp(&self, number: BlockNumberOrTag) -> anyhow::Result { - self.provider() - .await - .context("Failed to get the Geth provider")? - .get_block_by_number(number) - .await - .context("Failed to get the geth block")? - .context("Failed to get the Geth block, perhaps there are no blocks?") - .map(|block| block.header.timestamp) + fn block_timestamp( + &self, + number: BlockNumberOrTag, + ) -> Pin> + '_>> { + Box::pin(async move { + self.provider() + .await + .context("Failed to get the Geth provider")? + .get_block_by_number(number) + .await + .context("Failed to get the geth block")? + .context("Failed to get the Geth block, perhaps there are no blocks?") + .map(|block| block.header.timestamp) + }) } #[instrument(level = "info", skip_all, fields(geth_node_id = self.id))] - async fn last_block_number(&self) -> anyhow::Result { - self.provider() - .await - .context("Failed to get the Geth provider")? - .get_block_number() - .await - .map_err(Into::into) + fn last_block_number(&self) -> Pin> + '_>> { + Box::pin(async move { + self.provider() + .await + .context("Failed to get the Geth provider")? + .get_block_number() + .await + .map_err(Into::into) + }) } } diff --git a/crates/node/src/kitchensink.rs b/crates/node/src/kitchensink.rs index 751e583..ccc7e90 100644 --- a/crates/node/src/kitchensink.rs +++ b/crates/node/src/kitchensink.rs @@ -2,6 +2,7 @@ use std::{ fs::{File, OpenOptions, create_dir_all, remove_dir_all}, io::{BufRead, Write}, path::{Path, PathBuf}, + pin::Pin, process::{Child, Command, Stdio}, sync::{ Arc, @@ -44,6 +45,7 @@ use sp_runtime::AccountId32; use revive_dt_config::*; use revive_dt_node_interaction::EthereumNode; +use tracing::instrument; use crate::{Node, common::FallbackGasFiller, constants::INITIAL_BALANCE}; @@ -387,14 +389,14 @@ impl KitchensinkNode { &self, ) -> anyhow::Result< FillProvider< - impl TxFiller, - impl Provider, - KitchenSinkNetwork, + impl TxFiller, + impl Provider, + KitchensinkNetwork, >, > { ProviderBuilder::new() .disable_recommended_fillers() - .network::() + .network::() .filler(FallbackGasFiller::new( 25_000_000, 1_000_000_000, @@ -479,106 +481,287 @@ impl EthereumNode for KitchensinkNode { .await .map_err(Into::into) } + + fn resolver(&self) -> impl Future>> { + Box::pin(async move { + let id = self.id; + let provider = self.provider().await?; + Ok(Box::new(KitchensinkNodeResolver { id, provider }) as Box) + }) + } } +pub struct KitchensinkNodeResolver, P: Provider> +{ + id: u32, + provider: FillProvider, +} + +impl, P: Provider> ResolverApi + for KitchensinkNodeResolver +{ + #[instrument(level = "info", skip_all, fields(kitchensink_node_id = self.id))] + fn chain_id( + &self, + ) -> Pin> + '_>> { + Box::pin(async move { self.provider.get_chain_id().await.map_err(Into::into) }) + } + + #[instrument(level = "info", skip_all, fields(kitchensink_node_id = self.id))] + fn transaction_gas_price( + &self, + tx_hash: TxHash, + ) -> Pin> + '_>> { + Box::pin(async move { + self.provider + .get_transaction_receipt(tx_hash) + .await? + .context("Failed to get the transaction receipt") + .map(|receipt| receipt.effective_gas_price) + }) + } + + #[instrument(level = "info", skip_all, fields(kitchensink_node_id = self.id))] + fn block_gas_limit( + &self, + number: BlockNumberOrTag, + ) -> Pin> + '_>> { + Box::pin(async move { + self.provider + .get_block_by_number(number) + .await + .context("Failed to get the kitchensink block")? + .context("Failed to get the Kitchensink block, perhaps the chain has no blocks?") + .map(|block| block.header.gas_limit as _) + }) + } + + #[instrument(level = "info", skip_all, fields(kitchensink_node_id = self.id))] + fn block_coinbase( + &self, + number: BlockNumberOrTag, + ) -> Pin> + '_>> { + Box::pin(async move { + self.provider + .get_block_by_number(number) + .await + .context("Failed to get the kitchensink block")? + .context("Failed to get the Kitchensink block, perhaps the chain has no blocks?") + .map(|block| block.header.beneficiary) + }) + } + + #[instrument(level = "info", skip_all, fields(kitchensink_node_id = self.id))] + fn block_difficulty( + &self, + number: BlockNumberOrTag, + ) -> Pin> + '_>> { + Box::pin(async move { + self.provider + .get_block_by_number(number) + .await + .context("Failed to get the kitchensink block")? + .context("Failed to get the Kitchensink block, perhaps the chain has no blocks?") + .map(|block| U256::from_be_bytes(block.header.mix_hash.0)) + }) + } + + #[instrument(level = "info", skip_all, fields(kitchensink_node_id = self.id))] + fn block_base_fee( + &self, + number: BlockNumberOrTag, + ) -> Pin> + '_>> { + Box::pin(async move { + self.provider + .get_block_by_number(number) + .await + .context("Failed to get the kitchensink block")? + .context("Failed to get the Kitchensink block, perhaps the chain has no blocks?") + .and_then(|block| { + block + .header + .base_fee_per_gas + .context("Failed to get the base fee per gas") + }) + }) + } + + #[instrument(level = "info", skip_all, fields(kitchensink_node_id = self.id))] + fn block_hash( + &self, + number: BlockNumberOrTag, + ) -> Pin> + '_>> { + Box::pin(async move { + self.provider + .get_block_by_number(number) + .await + .context("Failed to get the kitchensink block")? + .context("Failed to get the Kitchensink block, perhaps the chain has no blocks?") + .map(|block| block.header.hash) + }) + } + + #[instrument(level = "info", skip_all, fields(kitchensink_node_id = self.id))] + fn block_timestamp( + &self, + number: BlockNumberOrTag, + ) -> Pin> + '_>> { + Box::pin(async move { + self.provider + .get_block_by_number(number) + .await + .context("Failed to get the kitchensink block")? + .context("Failed to get the Kitchensink block, perhaps the chain has no blocks?") + .map(|block| block.header.timestamp) + }) + } + + #[instrument(level = "info", skip_all, fields(kitchensink_node_id = self.id))] + fn last_block_number(&self) -> Pin> + '_>> { + Box::pin(async move { self.provider.get_block_number().await.map_err(Into::into) }) + } +} + +// TODO: Remove impl ResolverApi for KitchensinkNode { - async fn chain_id(&self) -> anyhow::Result { - self.provider() - .await - .context("Failed to get the Kitchensink provider")? - .get_chain_id() - .await - .map_err(Into::into) + fn chain_id( + &self, + ) -> Pin> + '_>> { + Box::pin(async move { + self.provider() + .await + .context("Failed to get the Kitchensink provider")? + .get_chain_id() + .await + .map_err(Into::into) + }) } - async fn transaction_gas_price(&self, tx_hash: &TxHash) -> anyhow::Result { - self.provider() - .await - .context("Failed to get the Kitchensink provider")? - .get_transaction_receipt(*tx_hash) - .await? - .context("Failed to get the transaction receipt") - .map(|receipt| receipt.effective_gas_price) + fn transaction_gas_price( + &self, + tx_hash: TxHash, + ) -> Pin> + '_>> { + Box::pin(async move { + self.provider() + .await + .context("Failed to get the Kitchensink provider")? + .get_transaction_receipt(tx_hash) + .await? + .context("Failed to get the transaction receipt") + .map(|receipt| receipt.effective_gas_price) + }) } - async fn block_gas_limit(&self, number: BlockNumberOrTag) -> anyhow::Result { - self.provider() - .await - .context("Failed to get the Kitchensink provider")? - .get_block_by_number(number) - .await - .context("Failed to get the kitchensink block")? - .context("Failed to get the Kitchensink block, perhaps the chain has no blocks?") - .map(|block| block.header.gas_limit as _) + fn block_gas_limit( + &self, + number: BlockNumberOrTag, + ) -> Pin> + '_>> { + Box::pin(async move { + self.provider() + .await + .context("Failed to get the Kitchensink provider")? + .get_block_by_number(number) + .await + .context("Failed to get the kitchensink block")? + .context("Failed to get the Kitchensink block, perhaps the chain has no blocks?") + .map(|block| block.header.gas_limit as _) + }) } - async fn block_coinbase(&self, number: BlockNumberOrTag) -> anyhow::Result
{ - self.provider() - .await - .context("Failed to get the Kitchensink provider")? - .get_block_by_number(number) - .await - .context("Failed to get the kitchensink block")? - .context("Failed to get the Kitchensink block, perhaps the chain has no blocks?") - .map(|block| block.header.beneficiary) + fn block_coinbase( + &self, + number: BlockNumberOrTag, + ) -> Pin> + '_>> { + Box::pin(async move { + self.provider() + .await + .context("Failed to get the Kitchensink provider")? + .get_block_by_number(number) + .await + .context("Failed to get the kitchensink block")? + .context("Failed to get the Kitchensink block, perhaps the chain has no blocks?") + .map(|block| block.header.beneficiary) + }) } - async fn block_difficulty(&self, number: BlockNumberOrTag) -> anyhow::Result { - self.provider() - .await - .context("Failed to get the Kitchensink provider")? - .get_block_by_number(number) - .await - .context("Failed to get the kitchensink block")? - .context("Failed to get the Kitchensink block, perhaps the chain has no blocks?") - .map(|block| U256::from_be_bytes(block.header.mix_hash.0)) + fn block_difficulty( + &self, + number: BlockNumberOrTag, + ) -> Pin> + '_>> { + Box::pin(async move { + self.provider() + .await + .context("Failed to get the Kitchensink provider")? + .get_block_by_number(number) + .await + .context("Failed to get the kitchensink block")? + .context("Failed to get the Kitchensink block, perhaps the chain has no blocks?") + .map(|block| U256::from_be_bytes(block.header.mix_hash.0)) + }) } - async fn block_base_fee(&self, number: BlockNumberOrTag) -> anyhow::Result { - self.provider() - .await - .context("Failed to get the Kitchensink provider")? - .get_block_by_number(number) - .await - .context("Failed to get the kitchensink block")? - .context("Failed to get the Kitchensink block, perhaps the chain has no blocks?") - .and_then(|block| { - block - .header - .base_fee_per_gas - .context("Failed to get the base fee per gas") - }) + fn block_base_fee( + &self, + number: BlockNumberOrTag, + ) -> Pin> + '_>> { + Box::pin(async move { + self.provider() + .await + .context("Failed to get the Kitchensink provider")? + .get_block_by_number(number) + .await + .context("Failed to get the kitchensink block")? + .context("Failed to get the Kitchensink block, perhaps the chain has no blocks?") + .and_then(|block| { + block + .header + .base_fee_per_gas + .context("Failed to get the base fee per gas") + }) + }) } - async fn block_hash(&self, number: BlockNumberOrTag) -> anyhow::Result { - self.provider() - .await - .context("Failed to get the Kitchensink provider")? - .get_block_by_number(number) - .await - .context("Failed to get the kitchensink block")? - .context("Failed to get the Kitchensink block, perhaps the chain has no blocks?") - .map(|block| block.header.hash) + fn block_hash( + &self, + number: BlockNumberOrTag, + ) -> Pin> + '_>> { + Box::pin(async move { + self.provider() + .await + .context("Failed to get the Kitchensink provider")? + .get_block_by_number(number) + .await + .context("Failed to get the kitchensink block")? + .context("Failed to get the Kitchensink block, perhaps the chain has no blocks?") + .map(|block| block.header.hash) + }) } - async fn block_timestamp(&self, number: BlockNumberOrTag) -> anyhow::Result { - self.provider() - .await - .context("Failed to get the Kitchensink provider")? - .get_block_by_number(number) - .await - .context("Failed to get the kitchensink block")? - .context("Failed to get the Kitchensink block, perhaps the chain has no blocks?") - .map(|block| block.header.timestamp) + fn block_timestamp( + &self, + number: BlockNumberOrTag, + ) -> Pin> + '_>> { + Box::pin(async move { + self.provider() + .await + .context("Failed to get the Kitchensink provider")? + .get_block_by_number(number) + .await + .context("Failed to get the kitchensink block")? + .context("Failed to get the Kitchensink block, perhaps the chain has no blocks?") + .map(|block| block.header.timestamp) + }) } - async fn last_block_number(&self) -> anyhow::Result { - self.provider() - .await - .context("Failed to get the Kitchensink provider")? - .get_block_number() - .await - .map_err(Into::into) + fn last_block_number(&self) -> Pin> + '_>> { + Box::pin(async move { + self.provider() + .await + .context("Failed to get the Kitchensink provider")? + .get_block_number() + .await + .map_err(Into::into) + }) } } @@ -701,9 +884,9 @@ impl Drop for KitchensinkNode { } #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] -struct KitchenSinkNetwork; +pub struct KitchensinkNetwork; -impl Network for KitchenSinkNetwork { +impl Network for KitchensinkNetwork { type TxType = ::TxType; type TxEnvelope = ::TxEnvelope; @@ -712,7 +895,7 @@ impl Network for KitchenSinkNetwork { type ReceiptEnvelope = ::ReceiptEnvelope; - type Header = KitchenSinkHeader; + type Header = KitchensinkHeader; type TransactionRequest = ::TransactionRequest; @@ -720,12 +903,12 @@ impl Network for KitchenSinkNetwork { type ReceiptResponse = ::ReceiptResponse; - type HeaderResponse = Header; + type HeaderResponse = Header; - type BlockResponse = Block, Header>; + type BlockResponse = Block, Header>; } -impl TransactionBuilder for ::TransactionRequest { +impl TransactionBuilder for ::TransactionRequest { fn chain_id(&self) -> Option { <::TransactionRequest as TransactionBuilder>::chain_id(self) } @@ -857,7 +1040,7 @@ impl TransactionBuilder for ::Transacti fn complete_type( &self, - ty: ::TxType, + ty: ::TxType, ) -> Result<(), Vec<&'static str>> { <::TransactionRequest as TransactionBuilder>::complete_type( self, ty, @@ -874,13 +1057,13 @@ impl TransactionBuilder for ::Transacti <::TransactionRequest as TransactionBuilder>::can_build(self) } - fn output_tx_type(&self) -> ::TxType { + fn output_tx_type(&self) -> ::TxType { <::TransactionRequest as TransactionBuilder>::output_tx_type( self, ) } - fn output_tx_type_checked(&self) -> Option<::TxType> { + fn output_tx_type_checked(&self) -> Option<::TxType> { <::TransactionRequest as TransactionBuilder>::output_tx_type_checked( self, ) @@ -894,7 +1077,7 @@ impl TransactionBuilder for ::Transacti fn build_unsigned( self, - ) -> alloy::network::BuildResult<::UnsignedTx, KitchenSinkNetwork> + ) -> alloy::network::BuildResult<::UnsignedTx, KitchensinkNetwork> { let result = <::TransactionRequest as TransactionBuilder>::build_unsigned( self, @@ -902,7 +1085,7 @@ impl TransactionBuilder for ::Transacti match result { Ok(unsigned_tx) => Ok(unsigned_tx), Err(UnbuiltTransactionError { request, error }) => { - Err(UnbuiltTransactionError:: { + Err(UnbuiltTransactionError:: { request, error: match error { TransactionBuilderError::InvalidTransactionRequest(tx_type, items) => { @@ -923,12 +1106,12 @@ impl TransactionBuilder for ::Transacti } } - async fn build>( + async fn build>( self, wallet: &W, ) -> Result< - ::TxEnvelope, - TransactionBuilderError, + ::TxEnvelope, + TransactionBuilderError, > { Ok(wallet.sign_request(self).await?) } @@ -936,7 +1119,7 @@ impl TransactionBuilder for ::Transacti #[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] #[serde(rename_all = "camelCase")] -pub struct KitchenSinkHeader { +pub struct KitchensinkHeader { /// The Keccak 256-bit hash of the parent /// block’s header, in its entirety; formally Hp. pub parent_hash: B256, @@ -1039,7 +1222,7 @@ pub struct KitchenSinkHeader { pub requests_hash: Option, } -impl BlockHeader for KitchenSinkHeader { +impl BlockHeader for KitchensinkHeader { fn parent_hash(&self) -> B256 { self.parent_hash }