From ac0f4e0cf2656f8b5640db6f1803ae695baae90d Mon Sep 17 00:00:00 2001 From: Omar Abdulla Date: Wed, 17 Sep 2025 19:54:50 +0300 Subject: [PATCH] Introduce a geth platform --- crates/common/src/types/identifiers.rs | 22 ++--- crates/compiler/src/revive_resolc.rs | 1 + crates/compiler/src/solc.rs | 1 + crates/core/src/lib.rs | 108 +++++++++++++++++++++++-- crates/node/src/geth.rs | 79 +++++++++--------- crates/node/src/kitchensink.rs | 94 ++++++++++----------- crates/node/src/lib.rs | 13 --- crates/node/src/pool.rs | 15 +--- 8 files changed, 199 insertions(+), 134 deletions(-) diff --git a/crates/common/src/types/identifiers.rs b/crates/common/src/types/identifiers.rs index f52a6f1..a43e3e0 100644 --- a/crates/common/src/types/identifiers.rs +++ b/crates/common/src/types/identifiers.rs @@ -23,16 +23,16 @@ use strum::{AsRefStr, Display, EnumString, IntoStaticStr}; #[serde(rename = "kebab-case")] #[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, + /// The Go-ethereum reference full node EVM implementation with the solc compiler. + GethEvmSolc, + /// The kitchensink node with the PolkaVM backend with the resolc compiler. + KitchensinkPolkavmResolc, + /// The kitchensink node with the REVM backend with the solc compiler. + KitchensinkREVMSolc, + /// The revive dev node with the PolkaVM backend with the resolc compiler. + ReviveDevNodePolkavmResolc, + /// The revive dev node with the REVM backend with the solc compiler. + ReviveDevNodeREVMSolc, } /// An enum of the platform identifiers of all of the platforms supported by this framework. @@ -115,5 +115,5 @@ pub enum VmIdentifier { /// The ethereum virtual machine. Evm, /// Polkadot's PolaVM Risc-v based virtual machine. - PolkaVm, + Polkavm, } diff --git a/crates/compiler/src/revive_resolc.rs b/crates/compiler/src/revive_resolc.rs index 0f87ec5..03074d3 100644 --- a/crates/compiler/src/revive_resolc.rs +++ b/crates/compiler/src/revive_resolc.rs @@ -63,6 +63,7 @@ impl DynSolidityCompiler for Resolc { } } +// TODO: Remove impl SolidityCompiler for Resolc { async fn new( context: impl AsRef diff --git a/crates/compiler/src/solc.rs b/crates/compiler/src/solc.rs index da5b2f0..764d671 100644 --- a/crates/compiler/src/solc.rs +++ b/crates/compiler/src/solc.rs @@ -64,6 +64,7 @@ impl DynSolidityCompiler for Solc { } } +// TODO: Remove impl SolidityCompiler for Solc { async fn new( context: impl AsRef diff --git a/crates/core/src/lib.rs b/crates/core/src/lib.rs index e303867..4e222fb 100644 --- a/crates/core/src/lib.rs +++ b/crates/core/src/lib.rs @@ -3,12 +3,27 @@ //! This crate defines the testing configuration and //! provides a helper utility to execute tests. +use std::{ + pin::Pin, + thread::{self, JoinHandle}, +}; + +use alloy::genesis::Genesis; +use anyhow::Context as _; use revive_dt_common::types::*; -use revive_dt_compiler::{DynSolidityCompiler, SolidityCompiler, revive_resolc, solc}; +use revive_dt_compiler::{ + DynSolidityCompiler, SolidityCompiler, revive_resolc, + solc::{self, Solc}, +}; use revive_dt_config::*; use revive_dt_format::traits::ResolverApi; -use revive_dt_node::{Node, geth, kitchensink::KitchensinkNode}; +use revive_dt_node::{ + Node, + geth::{self, GethNode}, + kitchensink::KitchensinkNode, +}; use revive_dt_node_interaction::EthereumNode; +use tracing::info; pub mod driver; @@ -48,6 +63,7 @@ impl Platform for Kitchensink { } /// A trait that describes the interface for the platforms that are supported by the tool. +#[allow(clippy::type_complexity)] pub trait DynPlatform { /// Returns the identifier of this platform. This is a combination of the node and the compiler /// used. @@ -87,14 +103,92 @@ pub trait DynPlatform { + Sync + Clone + 'static, - ) -> Box; + ) -> anyhow::Result>>>; /// Creates a new compiler for the provided platform - fn new_compiler( + fn new_compiler<'a>( &self, context: impl AsRef + AsRef - + AsRef, - version: impl Into>, - ) -> Box; + + AsRef + + 'a, + version: impl Into> + 'a, + ) -> Pin>> + 'a>>; +} + +pub struct GethEvmPlatform; + +impl DynPlatform for GethEvmPlatform { + fn platform_identifier(&self) -> PlatformIdentifier { + PlatformIdentifier::GethEvmSolc + } + + fn node_identifier(&self) -> NodeIdentifier { + NodeIdentifier::Geth + } + + fn vm_identifier(&self) -> VmIdentifier { + VmIdentifier::Evm + } + + fn compiler_identifier(&self) -> CompilerIdentifier { + CompilerIdentifier::Solc + } + + fn new_node( + &self, + context: impl AsRef + + AsRef + + AsRef + + AsRef + + AsRef + + AsRef + + AsRef + + AsRef + + Send + + Sync + + Clone + + 'static, + ) -> anyhow::Result>>> { + let genesis_configuration = AsRef::::as_ref(&context); + let genesis = genesis_configuration.genesis()?.clone(); + Ok(thread::spawn(move || { + let node = GethNode::new(context); + let node = spawn_node::(node, genesis)?; + Ok(Box::new(node) as Box<_>) + })) + } + + fn new_compiler<'a>( + &self, + context: impl AsRef + + AsRef + + AsRef + + 'a, + version: impl Into> + 'a, + ) -> Pin>> + 'a>> { + Box::pin(async move { + let compiler = Solc::new(context, version).await; + compiler.map(|compiler| Box::new(compiler) as Box) + }) + } +} + +fn spawn_node( + mut node: T, + genesis: Genesis, +) -> anyhow::Result { + info!( + id = node.id(), + connection_string = node.connection_string(), + "Spawning node" + ); + node.spawn(genesis) + .context("Failed to spawn node process")?; + info!( + id = node.id(), + connection_string = node.connection_string(), + "Spawned node" + ); + Ok(node) } diff --git a/crates/node/src/geth.rs b/crates/node/src/geth.rs index 3b73fdc..ed9ca7b 100644 --- a/crates/node/src/geth.rs +++ b/crates/node/src/geth.rs @@ -93,6 +93,43 @@ impl GethNode { const RECEIPT_POLLING_DURATION: Duration = Duration::from_secs(5 * 60); const TRACE_POLLING_DURATION: Duration = Duration::from_secs(60); + pub fn new( + context: impl AsRef + + AsRef + + AsRef + + Clone, + ) -> Self { + let working_directory_configuration = + AsRef::::as_ref(&context); + let wallet_configuration = AsRef::::as_ref(&context); + let geth_configuration = AsRef::::as_ref(&context); + + let geth_directory = working_directory_configuration + .as_path() + .join(Self::BASE_DIRECTORY); + let id = NODE_COUNT.fetch_add(1, Ordering::SeqCst); + let base_directory = geth_directory.join(id.to_string()); + + let wallet = wallet_configuration.wallet(); + + Self { + connection_string: base_directory.join(Self::IPC_FILE).display().to_string(), + data_directory: base_directory.join(Self::DATA_DIRECTORY), + logs_directory: base_directory.join(Self::LOGS_DIRECTORY), + base_directory, + geth: geth_configuration.path.clone(), + id, + handle: None, + start_timeout: geth_configuration.start_timeout_ms, + wallet: wallet.clone(), + chain_id_filler: Default::default(), + nonce_manager: Default::default(), + // We know that we only need to be storing 2 files so we can specify that when creating + // the vector. It's the stdout and stderr of the geth node. + logs_file_to_flush: Vec::with_capacity(2), + } + } + /// Create the node directory and call `geth init` to configure the genesis. #[instrument(level = "info", skip_all, fields(geth_node_id = self.id))] fn init(&mut self, mut genesis: Genesis) -> anyhow::Result<&mut Self> { @@ -751,48 +788,6 @@ impl ResolverApi for GethNode { } impl Node for GethNode { - fn new( - context: impl AsRef - + AsRef - + AsRef - + AsRef - + AsRef - + AsRef - + AsRef - + AsRef - + Clone, - ) -> Self { - let working_directory_configuration = - AsRef::::as_ref(&context); - let wallet_configuration = AsRef::::as_ref(&context); - let geth_configuration = AsRef::::as_ref(&context); - - let geth_directory = working_directory_configuration - .as_path() - .join(Self::BASE_DIRECTORY); - let id = NODE_COUNT.fetch_add(1, Ordering::SeqCst); - let base_directory = geth_directory.join(id.to_string()); - - let wallet = wallet_configuration.wallet(); - - Self { - connection_string: base_directory.join(Self::IPC_FILE).display().to_string(), - data_directory: base_directory.join(Self::DATA_DIRECTORY), - logs_directory: base_directory.join(Self::LOGS_DIRECTORY), - base_directory, - geth: geth_configuration.path.clone(), - id, - handle: None, - start_timeout: geth_configuration.start_timeout_ms, - wallet: wallet.clone(), - chain_id_filler: Default::default(), - nonce_manager: Default::default(), - // We know that we only need to be storing 2 files so we can specify that when creating - // the vector. It's the stdout and stderr of the geth node. - logs_file_to_flush: Vec::with_capacity(2), - } - } - #[instrument(level = "info", skip_all, fields(geth_node_id = self.id))] fn id(&self) -> usize { self.id as _ diff --git a/crates/node/src/kitchensink.rs b/crates/node/src/kitchensink.rs index c6f9d1e..f6fe27e 100644 --- a/crates/node/src/kitchensink.rs +++ b/crates/node/src/kitchensink.rs @@ -93,6 +93,53 @@ impl KitchensinkNode { const PROXY_STDOUT_LOG_FILE_NAME: &str = "proxy_stdout.log"; const PROXY_STDERR_LOG_FILE_NAME: &str = "proxy_stderr.log"; + pub fn new( + context: impl AsRef + + AsRef + + AsRef + + AsRef + + AsRef + + AsRef + + AsRef + + AsRef + + Clone, + ) -> Self { + let kitchensink_configuration = AsRef::::as_ref(&context); + let dev_node_configuration = AsRef::::as_ref(&context); + let eth_rpc_configuration = AsRef::::as_ref(&context); + let working_directory_configuration = + AsRef::::as_ref(&context); + let wallet_configuration = AsRef::::as_ref(&context); + + let kitchensink_directory = working_directory_configuration + .as_path() + .join(Self::BASE_DIRECTORY); + let id = NODE_COUNT.fetch_add(1, Ordering::SeqCst); + let base_directory = kitchensink_directory.join(id.to_string()); + let logs_directory = base_directory.join(Self::LOGS_DIRECTORY); + + let wallet = wallet_configuration.wallet(); + + Self { + id, + substrate_binary: kitchensink_configuration.path.clone(), + dev_node_binary: dev_node_configuration.path.clone(), + eth_proxy_binary: eth_rpc_configuration.path.clone(), + rpc_url: String::new(), + base_directory, + logs_directory, + process_substrate: None, + process_proxy: None, + wallet: wallet.clone(), + chain_id_filler: Default::default(), + nonce_manager: Default::default(), + use_kitchensink_not_dev_node: kitchensink_configuration.use_kitchensink, + // We know that we only need to be storing 4 files so we can specify that when creating + // the vector. It's the stdout and stderr of the substrate-node and the eth-rpc. + logs_file_to_flush: Vec::with_capacity(4), + } + } + fn init(&mut self, mut genesis: Genesis) -> anyhow::Result<&mut Self> { let _ = clear_directory(&self.base_directory); let _ = clear_directory(&self.logs_directory); @@ -784,53 +831,6 @@ impl ResolverApi for KitchensinkNode { } impl Node for KitchensinkNode { - fn new( - context: impl AsRef - + AsRef - + AsRef - + AsRef - + AsRef - + AsRef - + AsRef - + AsRef - + Clone, - ) -> Self { - let kitchensink_configuration = AsRef::::as_ref(&context); - let dev_node_configuration = AsRef::::as_ref(&context); - let eth_rpc_configuration = AsRef::::as_ref(&context); - let working_directory_configuration = - AsRef::::as_ref(&context); - let wallet_configuration = AsRef::::as_ref(&context); - - let kitchensink_directory = working_directory_configuration - .as_path() - .join(Self::BASE_DIRECTORY); - let id = NODE_COUNT.fetch_add(1, Ordering::SeqCst); - let base_directory = kitchensink_directory.join(id.to_string()); - let logs_directory = base_directory.join(Self::LOGS_DIRECTORY); - - let wallet = wallet_configuration.wallet(); - - Self { - id, - substrate_binary: kitchensink_configuration.path.clone(), - dev_node_binary: dev_node_configuration.path.clone(), - eth_proxy_binary: eth_rpc_configuration.path.clone(), - rpc_url: String::new(), - base_directory, - logs_directory, - process_substrate: None, - process_proxy: None, - wallet: wallet.clone(), - chain_id_filler: Default::default(), - nonce_manager: Default::default(), - use_kitchensink_not_dev_node: kitchensink_configuration.use_kitchensink, - // We know that we only need to be storing 4 files so we can specify that when creating - // the vector. It's the stdout and stderr of the substrate-node and the eth-rpc. - logs_file_to_flush: Vec::with_capacity(4), - } - } - fn id(&self) -> usize { self.id as _ } diff --git a/crates/node/src/lib.rs b/crates/node/src/lib.rs index 3ee7b4f..c729e40 100644 --- a/crates/node/src/lib.rs +++ b/crates/node/src/lib.rs @@ -13,19 +13,6 @@ pub mod pool; /// An abstract interface for testing nodes. pub trait Node: EthereumNode { - /// Create a new uninitialized instance. - fn new( - context: impl AsRef - + AsRef - + AsRef - + AsRef - + AsRef - + AsRef - + AsRef - + AsRef - + Clone, - ) -> Self; - /// Returns the identifier of the node. fn id(&self) -> usize; diff --git a/crates/node/src/pool.rs b/crates/node/src/pool.rs index f6d9dcb..e3b93d4 100644 --- a/crates/node/src/pool.rs +++ b/crates/node/src/pool.rs @@ -93,18 +93,5 @@ fn spawn_node( + 'static, genesis: Genesis, ) -> anyhow::Result { - let mut node = T::new(context); - info!( - id = node.id(), - connection_string = node.connection_string(), - "Spawning node" - ); - node.spawn(genesis) - .context("Failed to spawn node process")?; - info!( - id = node.id(), - connection_string = node.connection_string(), - "Spawned node" - ); - Ok(node) + todo!("Remove"); }