From d7bc4f1fab5eae7d244da7207b0babcfc10b76de Mon Sep 17 00:00:00 2001 From: Omar Abdulla Date: Mon, 21 Jul 2025 19:42:44 +0300 Subject: [PATCH] Cleanup implementation --- crates/core/src/driver/mod.rs | 95 ++++-------------------------- crates/core/src/main.rs | 88 +++++++++++++++++++++++---- crates/format/src/input.rs | 5 +- crates/format/src/metadata.rs | 5 +- crates/node-interaction/src/lib.rs | 10 +--- crates/node/src/geth.rs | 65 +++++++++----------- crates/node/src/kitchensink.rs | 78 ++++++++++-------------- crates/node/src/lib.rs | 6 +- crates/node/src/pool.rs | 23 ++++++-- 9 files changed, 177 insertions(+), 198 deletions(-) diff --git a/crates/core/src/driver/mod.rs b/crates/core/src/driver/mod.rs index 55c59d1..c0626ce 100644 --- a/crates/core/src/driver/mod.rs +++ b/crates/core/src/driver/mod.rs @@ -22,10 +22,8 @@ use indexmap::IndexMap; use revive_dt_compiler::{Compiler, SolidityCompiler}; use revive_dt_config::Arguments; use revive_dt_format::case::CaseIdx; -use revive_dt_format::input::{Calldata, Expected, ExpectedOutput, Method, default_caller}; -use revive_dt_format::metadata::{ - AddressReplacementMap, ContractInstance, ContractPathAndIdentifier, -}; +use revive_dt_format::input::{Calldata, Expected, ExpectedOutput, Method}; +use revive_dt_format::metadata::{ContractInstance, ContractPathAndIdentifier}; use revive_dt_format::{input::Input, metadata::Metadata, mode::SolcMode}; use revive_dt_node_interaction::EthereumNode; use revive_dt_report::reporter::{CompilationTask, Report, Span}; @@ -147,17 +145,11 @@ where case_idx: CaseIdx, input: &Input, node: &T::Blockchain, - address_replacement: &AddressReplacementMap, ) -> anyhow::Result<(TransactionReceipt, GethTrace, DiffMode)> { let deployment_receipts = - self.handle_contract_deployment(metadata, case_idx, input, node, address_replacement)?; - let execution_receipt = self.handle_input_execution( - case_idx, - input, - deployment_receipts, - node, - address_replacement, - )?; + self.handle_contract_deployment(metadata, case_idx, input, node)?; + let execution_receipt = + self.handle_input_execution(case_idx, input, deployment_receipts, node)?; self.handle_input_expectations(case_idx, input, &execution_receipt, node)?; self.handle_input_diff(case_idx, execution_receipt, node) } @@ -169,7 +161,6 @@ where case_idx: CaseIdx, input: &Input, node: &T::Blockchain, - address_replacement: &AddressReplacementMap, ) -> anyhow::Result> { let span = tracing::debug_span!( "Handling contract deployment", @@ -261,16 +252,7 @@ where TransactionBuilder::::with_deploy_code(tx, code) }; - let receipt = match node.execute_transaction( - tx, - Some( - address_replacement - .as_ref() - .values() - .map(|(sk, _)| sk) - .map(Clone::clone), - ), - ) { + let receipt = match node.execute_transaction(tx) { Ok(receipt) => receipt, Err(error) => { tracing::error!( @@ -334,7 +316,6 @@ where input: &Input, mut deployment_receipts: HashMap, node: &T::Blockchain, - address_replacement: &AddressReplacementMap, ) -> anyhow::Result { match input.method { // This input was already executed when `handle_input` was called. We just need to @@ -358,16 +339,7 @@ where tracing::trace!("Executing transaction for input: {input:?}"); - match node.execute_transaction( - tx, - Some( - address_replacement - .as_ref() - .values() - .map(|(sk, _)| sk) - .map(Clone::clone), - ), - ) { + match node.execute_transaction(tx) { Ok(receipt) => Ok(receipt), Err(err) => { tracing::error!( @@ -599,7 +571,7 @@ where } pub struct Driver<'a, Leader: Platform, Follower: Platform> { - metadata: &'a mut Metadata, + metadata: &'a Metadata, config: &'a Arguments, leader_node: &'a Leader::Blockchain, follower_node: &'a Follower::Blockchain, @@ -611,7 +583,7 @@ where F: Platform, { pub fn new( - metadata: &'a mut Metadata, + metadata: &'a Metadata, config: &'a Arguments, leader_node: &'a L::Blockchain, follower_node: &'a F::Blockchain, @@ -722,44 +694,6 @@ where // For cases if one of the inputs fail then we move on to the next case and we do NOT // bail out of the whole thing. - let replacement_maps = self - .metadata - .cases - .iter_mut() - .enumerate() - .map(|(case_id, case)| (CaseIdx::new(case_id), case)) - .fold(HashMap::new(), |mut map, (case_idx, case)| { - let mut replacement_map = AddressReplacementMap::default(); - case.inputs - .iter() - .filter_map(|input| { - if input.caller == default_caller() { - None - } else { - Some(input.caller) - } - }) - .for_each(|caller| { - replacement_map.get(caller); - }); - if let Err(error) = case.handle_address_replacement(&mut replacement_map) { - tracing::error!( - target = ?Target::Leader, - ?error, - "Case address replacement failed" - ); - execution_result.add_failed_case( - Target::Leader, - mode.clone(), - case.name.as_deref().unwrap_or("no case name").to_owned(), - case_idx, - 0, - anyhow::Error::msg(format!("{error}")), - ); - } - map.insert(case_idx, replacement_map); - map - }); 'case_loop: for (case_idx, case) in self.metadata.cases.iter().enumerate() { let tracing_span = tracing::info_span!( @@ -770,7 +704,6 @@ where let _guard = tracing_span.enter(); let case_idx = CaseIdx::new_from(case_idx); - let replacement_map = replacement_maps.get(&case_idx).cloned().unwrap_or_default(); // For inputs if one of the inputs fail we move on to the next case (we do not move // on to the next input as it doesn't make sense. It depends on the previous one). @@ -782,13 +715,8 @@ where tracing::info_span!("Executing input", contract_name = ?input.instance) .in_scope(|| { let (leader_receipt, _, leader_diff) = match leader_state - .handle_input( - self.metadata, - case_idx, - &input, - self.leader_node, - &replacement_map, - ) { + .handle_input(self.metadata, case_idx, &input, self.leader_node) + { Ok(result) => result, Err(error) => { tracing::error!( @@ -817,7 +745,6 @@ where case_idx, &input, self.follower_node, - &replacement_map, ) { Ok(result) => result, Err(error) => { diff --git a/crates/core/src/main.rs b/crates/core/src/main.rs index e61281b..c161620 100644 --- a/crates/core/src/main.rs +++ b/crates/core/src/main.rs @@ -1,5 +1,13 @@ -use std::{collections::HashMap, sync::LazyLock}; +use std::{ + collections::{HashMap, HashSet}, + sync::LazyLock, +}; +use alloy::{ + network::TxSigner, + primitives::FixedBytes, + signers::{Signature, local::PrivateKeySigner}, +}; use clap::Parser; use rayon::{ThreadPoolBuilder, prelude::*}; @@ -8,7 +16,11 @@ use revive_dt_core::{ Geth, Kitchensink, Platform, driver::{Driver, State}, }; -use revive_dt_format::{corpus::Corpus, metadata::MetadataFile}; +use revive_dt_format::{ + corpus::Corpus, + input::default_caller, + metadata::{AddressReplacementMap, MetadataFile}, +}; use revive_dt_node::pool::NodePool; use revive_dt_report::reporter::{Report, Span}; use temp_dir::TempDir; @@ -20,12 +32,48 @@ static TEMP_DIR: LazyLock = LazyLock::new(|| TempDir::new().unwrap()); fn main() -> anyhow::Result<()> { let args = init_cli()?; - for (corpus, mut tests) in collect_corpora(&args)? { + let mut corpora = collect_corpora(&args)?; + let mut replacement_private_keys = HashSet::>::new(); + for case in corpora + .values_mut() + .flat_map(|metadata| metadata.iter_mut()) + .flat_map(|metadata| metadata.content.cases.iter_mut()) + { + let mut replacement_map = AddressReplacementMap::new(); + for address in case.inputs.iter().filter_map(|input| { + if input.caller != default_caller() { + Some(input.caller) + } else { + None + } + }) { + replacement_map.get(address); + } + case.handle_address_replacement(&mut replacement_map)?; + replacement_private_keys.extend( + replacement_map + .into_inner() + .into_values() + .map(|(sk, _)| sk) + .map(|sk| sk.to_bytes()), + ); + } + + for (corpus, tests) in collect_corpora(&args)? { let span = Span::new(corpus, args.clone())?; match &args.compile_only { Some(platform) => compile_corpus(&args, &tests, platform, span), - None => execute_corpus(&args, &mut tests, span)?, + None => execute_corpus( + &args, + &tests, + replacement_private_keys + .clone() + .into_iter() + .map(|bytes| PrivateKeySigner::from_bytes(&bytes).expect("Can't fail")) + .collect::>(), + span, + )?, } Report::save()?; @@ -83,17 +131,26 @@ fn collect_corpora(args: &Arguments) -> anyhow::Result(args: &Arguments, tests: &mut [MetadataFile], span: Span) -> anyhow::Result<()> +fn run_driver( + args: &Arguments, + tests: &[MetadataFile], + additional_signers: impl IntoIterator + Send + Sync + 'static> + + Clone + + Send + + Sync + + 'static, + span: Span, +) -> anyhow::Result<()> where L: Platform, F: Platform, L::Blockchain: revive_dt_node::Node + Send + Sync + 'static, F::Blockchain: revive_dt_node::Node + Send + Sync + 'static, { - let leader_nodes = NodePool::::new(args)?; - let follower_nodes = NodePool::::new(args)?; + let leader_nodes = NodePool::::new(args, additional_signers.clone())?; + let follower_nodes = NodePool::::new(args, additional_signers)?; - tests.par_iter_mut().for_each( + tests.par_iter().for_each( |MetadataFile { content: metadata, path: metadata_file_path, @@ -141,13 +198,22 @@ where Ok(()) } -fn execute_corpus(args: &Arguments, tests: &mut [MetadataFile], span: Span) -> anyhow::Result<()> { +fn execute_corpus( + args: &Arguments, + tests: &[MetadataFile], + additional_signers: impl IntoIterator + Send + Sync + 'static> + + Clone + + Send + + Sync + + 'static, + span: Span, +) -> anyhow::Result<()> { match (&args.leader, &args.follower) { (TestingPlatform::Geth, TestingPlatform::Kitchensink) => { - run_driver::(args, tests, span)? + run_driver::(args, tests, additional_signers, span)? } (TestingPlatform::Geth, TestingPlatform::Geth) => { - run_driver::(args, tests, span)? + run_driver::(args, tests, additional_signers, span)? } _ => unimplemented!(), } diff --git a/crates/format/src/input.rs b/crates/format/src/input.rs index a0965f3..1faae0b 100644 --- a/crates/format/src/input.rs +++ b/crates/format/src/input.rs @@ -448,8 +448,8 @@ pub fn resolve_argument( mod tests { use super::*; - use alloy::{json_abi::JsonAbi, network::TxSigner}; - use alloy_primitives::{Signature, address}; + use alloy::json_abi::JsonAbi; + use alloy_primitives::address; use alloy_sol_types::SolValue; use std::collections::HashMap; @@ -459,7 +459,6 @@ mod tests { fn execute_transaction( &self, _: TransactionRequest, - _: Option + Send + Sync + 'static>>, ) -> anyhow::Result { unimplemented!() } diff --git a/crates/format/src/metadata.rs b/crates/format/src/metadata.rs index 980d6d3..c8c9756 100644 --- a/crates/format/src/metadata.rs +++ b/crates/format/src/metadata.rs @@ -7,8 +7,8 @@ use std::{ str::FromStr, }; -use alloy::{network::TxSigner, signers::local::PrivateKeySigner}; -use alloy_primitives::{Address, Signature}; +use alloy::signers::local::PrivateKeySigner; +use alloy_primitives::Address; use revive_dt_node_interaction::EthereumNode; use serde::{Deserialize, Serialize}; @@ -389,7 +389,6 @@ impl EthereumNode for UnimplementedEthereumNode { fn execute_transaction( &self, _: alloy::rpc::types::TransactionRequest, - _: Option + Send + Sync + 'static>>, ) -> anyhow::Result { anyhow::bail!("Unimplemented") } diff --git a/crates/node-interaction/src/lib.rs b/crates/node-interaction/src/lib.rs index 470c67c..8ac488c 100644 --- a/crates/node-interaction/src/lib.rs +++ b/crates/node-interaction/src/lib.rs @@ -1,11 +1,9 @@ //! This crate implements all node interactions. use alloy::eips::BlockNumberOrTag; -use alloy::network::TxSigner; use alloy::primitives::{Address, BlockHash, BlockNumber, BlockTimestamp, ChainId, U256}; use alloy::rpc::types::trace::geth::{DiffMode, GethDebugTracingOptions, GethTrace}; use alloy::rpc::types::{TransactionReceipt, TransactionRequest}; -use alloy::signers::Signature; use anyhow::Result; mod blocking_executor; @@ -14,13 +12,7 @@ pub use blocking_executor::*; /// An interface for all interactions with Ethereum compatible nodes. pub trait EthereumNode { /// Execute the [TransactionRequest] and return a [TransactionReceipt]. - fn execute_transaction( - &self, - transaction: TransactionRequest, - additional_signers: Option< - impl IntoIterator + Send + Sync + 'static>, - >, - ) -> Result; + fn execute_transaction(&self, transaction: TransactionRequest) -> Result; /// Trace the transaction in the [TransactionReceipt] and return a [GethTrace]. fn trace_transaction( diff --git a/crates/node/src/geth.rs b/crates/node/src/geth.rs index 84b100b..2077ef0 100644 --- a/crates/node/src/geth.rs +++ b/crates/node/src/geth.rs @@ -22,7 +22,7 @@ use alloy::{ TransactionReceipt, TransactionRequest, trace::geth::{DiffMode, GethDebugTracingOptions, PreStateConfig, PreStateFrame}, }, - signers::{Signature, local::PrivateKeySigner}, + signers::Signature, }; use revive_dt_config::Arguments; use revive_dt_node_interaction::{BlockingExecutor, EthereumNode}; @@ -196,19 +196,13 @@ impl Instance { fn provider( &self, - additional_signers: Option< - impl IntoIterator + Send + Sync + 'static>, - >, ) -> impl Future< Output = anyhow::Result< FillProvider, impl Provider, Ethereum>, >, > + 'static { let connection_string = self.connection_string(); - let mut wallet = self.wallet.clone(); - for signer in additional_signers.into_iter().flatten() { - wallet.register_signer(signer); - } + let wallet = self.wallet.clone(); // Note: We would like all providers to make use of the same nonce manager so that we have // monotonically increasing nonces that are cached. The cached nonce manager uses Arc's in @@ -228,16 +222,6 @@ impl Instance { .map_err(Into::into) }) } - - fn provider_no_additional_signers( - &self, - ) -> impl Future< - Output = anyhow::Result< - FillProvider, impl Provider, Ethereum>, - >, - > + 'static { - self.provider(None::>) - } } impl EthereumNode for Instance { @@ -245,11 +229,8 @@ impl EthereumNode for Instance { fn execute_transaction( &self, transaction: TransactionRequest, - additional_signers: Option< - impl IntoIterator + Send + Sync + 'static>, - >, ) -> anyhow::Result { - let provider = self.provider(additional_signers); + let provider = self.provider(); BlockingExecutor::execute(async move { let outer_span = tracing::debug_span!("Submitting transaction", ?transaction); let _outer_guard = outer_span.enter(); @@ -336,7 +317,7 @@ impl EthereumNode for Instance { trace_options: GethDebugTracingOptions, ) -> anyhow::Result { let tx_hash = transaction.transaction_hash; - let provider = self.provider_no_additional_signers(); + let provider = self.provider(); BlockingExecutor::execute(async move { Ok(provider .await? @@ -363,7 +344,7 @@ impl EthereumNode for Instance { #[tracing::instrument(skip_all, fields(geth_node_id = self.id))] fn chain_id(&self) -> anyhow::Result { - let provider = self.provider_no_additional_signers(); + let provider = self.provider(); BlockingExecutor::execute(async move { provider.await?.get_chain_id().await.map_err(Into::into) })? @@ -371,7 +352,7 @@ impl EthereumNode for Instance { #[tracing::instrument(skip_all, fields(geth_node_id = self.id))] fn block_gas_limit(&self, number: BlockNumberOrTag) -> anyhow::Result { - let provider = self.provider_no_additional_signers(); + let provider = self.provider(); BlockingExecutor::execute(async move { provider .await? @@ -384,7 +365,7 @@ impl EthereumNode for Instance { #[tracing::instrument(skip_all, fields(geth_node_id = self.id))] fn block_coinbase(&self, number: BlockNumberOrTag) -> anyhow::Result
{ - let provider = self.provider_no_additional_signers(); + let provider = self.provider(); BlockingExecutor::execute(async move { provider .await? @@ -397,7 +378,7 @@ impl EthereumNode for Instance { #[tracing::instrument(skip_all, fields(geth_node_id = self.id))] fn block_difficulty(&self, number: BlockNumberOrTag) -> anyhow::Result { - let provider = self.provider_no_additional_signers(); + let provider = self.provider(); BlockingExecutor::execute(async move { provider .await? @@ -410,7 +391,7 @@ impl EthereumNode for Instance { #[tracing::instrument(skip_all, fields(geth_node_id = self.id))] fn block_hash(&self, number: BlockNumberOrTag) -> anyhow::Result { - let provider = self.provider_no_additional_signers(); + let provider = self.provider(); BlockingExecutor::execute(async move { provider .await? @@ -423,7 +404,7 @@ impl EthereumNode for Instance { #[tracing::instrument(skip_all, fields(geth_node_id = self.id))] fn block_timestamp(&self, number: BlockNumberOrTag) -> anyhow::Result { - let provider = self.provider_no_additional_signers(); + let provider = self.provider(); BlockingExecutor::execute(async move { provider .await? @@ -436,7 +417,7 @@ impl EthereumNode for Instance { #[tracing::instrument(skip_all, fields(geth_node_id = self.id))] fn last_block_number(&self) -> anyhow::Result { - let provider = self.provider_no_additional_signers(); + let provider = self.provider(); BlockingExecutor::execute(async move { provider.await?.get_block_number().await.map_err(Into::into) })? @@ -444,11 +425,19 @@ impl EthereumNode for Instance { } impl Node for Instance { - fn new(config: &Arguments) -> Self { + fn new( + config: &Arguments, + additional_signers: impl IntoIterator + Send + Sync + 'static>, + ) -> Self { let geth_directory = config.directory().join(Self::BASE_DIRECTORY); let id = NODE_COUNT.fetch_add(1, Ordering::SeqCst); let base_directory = geth_directory.join(id.to_string()); + let mut wallet = config.wallet(); + for signer in additional_signers { + wallet.register_signer(signer); + } + Self { connection_string: base_directory.join(Self::IPC_FILE).display().to_string(), data_directory: base_directory.join(Self::DATA_DIRECTORY), @@ -459,7 +448,7 @@ impl Node for Instance { handle: None, network_id: config.network_id, start_timeout: config.geth_start_timeout, - wallet: config.wallet(), + wallet, // 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), @@ -524,6 +513,8 @@ impl Drop for Instance { #[cfg(test)] mod tests { use revive_dt_config::Arguments; + + use alloy::signers::local::PrivateKeySigner; use temp_dir::TempDir; use crate::{GENESIS_JSON, Node}; @@ -540,7 +531,7 @@ mod tests { fn new_node() -> (Instance, TempDir) { let (args, temp_dir) = test_config(); - let mut node = Instance::new(&args); + let mut node = Instance::new(&args, Vec::::with_capacity(0)); node.init(GENESIS_JSON.to_owned()) .expect("Failed to initialize the node") .spawn_process() @@ -550,21 +541,23 @@ mod tests { #[test] fn init_works() { - Instance::new(&test_config().0) + Instance::new(&test_config().0, Vec::::with_capacity(0)) .init(GENESIS_JSON.to_string()) .unwrap(); } #[test] fn spawn_works() { - Instance::new(&test_config().0) + Instance::new(&test_config().0, Vec::::with_capacity(0)) .spawn(GENESIS_JSON.to_string()) .unwrap(); } #[test] fn version_works() { - let version = Instance::new(&test_config().0).version().unwrap(); + let version = Instance::new(&test_config().0, Vec::::with_capacity(0)) + .version() + .unwrap(); assert!( version.starts_with("geth version"), "expected version string, got: '{version}'" diff --git a/crates/node/src/kitchensink.rs b/crates/node/src/kitchensink.rs index 2d835aa..43b4ddd 100644 --- a/crates/node/src/kitchensink.rs +++ b/crates/node/src/kitchensink.rs @@ -26,7 +26,7 @@ use alloy::{ eth::{Block, Header, Transaction}, trace::geth::{DiffMode, GethDebugTracingOptions, PreStateConfig, PreStateFrame}, }, - signers::{Signature, local::PrivateKeySigner}, + signers::Signature, }; use serde::{Deserialize, Serialize}; use serde_json::{Value as JsonValue, json}; @@ -336,9 +336,6 @@ impl KitchensinkNode { fn provider( &self, - additional_signers: Option< - impl IntoIterator + Send + Sync + 'static>, - >, ) -> impl Future< Output = anyhow::Result< FillProvider< @@ -349,10 +346,7 @@ impl KitchensinkNode { >, > + 'static { let connection_string = self.connection_string(); - let mut wallet = self.wallet.clone(); - for signer in additional_signers.into_iter().flatten() { - wallet.register_signer(signer); - } + let wallet = self.wallet.clone(); // Note: We would like all providers to make use of the same nonce manager so that we have // monotonically increasing nonces that are cached. The cached nonce manager uses Arc's in @@ -377,20 +371,6 @@ impl KitchensinkNode { .map_err(Into::into) }) } - - fn provider_no_additional_signers( - &self, - ) -> impl Future< - Output = anyhow::Result< - FillProvider< - impl TxFiller, - impl Provider, - KitchenSinkNetwork, - >, - >, - > + 'static { - self.provider(None::>) - } } impl EthereumNode for KitchensinkNode { @@ -398,12 +378,9 @@ impl EthereumNode for KitchensinkNode { fn execute_transaction( &self, transaction: alloy::rpc::types::TransactionRequest, - additional_signers: Option< - impl IntoIterator + Send + Sync + 'static>, - >, ) -> anyhow::Result { tracing::debug!(?transaction, "Submitting transaction"); - let provider = self.provider(additional_signers); + let provider = self.provider(); let receipt = BlockingExecutor::execute(async move { Ok(provider .await? @@ -423,7 +400,7 @@ impl EthereumNode for KitchensinkNode { trace_options: GethDebugTracingOptions, ) -> anyhow::Result { let tx_hash = transaction.transaction_hash; - let provider = self.provider_no_additional_signers(); + let provider = self.provider(); BlockingExecutor::execute(async move { Ok(provider .await? @@ -450,7 +427,7 @@ impl EthereumNode for KitchensinkNode { #[tracing::instrument(skip_all, fields(geth_node_id = self.id))] fn chain_id(&self) -> anyhow::Result { - let provider = self.provider_no_additional_signers(); + let provider = self.provider(); BlockingExecutor::execute(async move { provider.await?.get_chain_id().await.map_err(Into::into) })? @@ -458,7 +435,7 @@ impl EthereumNode for KitchensinkNode { #[tracing::instrument(skip_all, fields(geth_node_id = self.id))] fn block_gas_limit(&self, number: BlockNumberOrTag) -> anyhow::Result { - let provider = self.provider_no_additional_signers(); + let provider = self.provider(); BlockingExecutor::execute(async move { provider .await? @@ -471,7 +448,7 @@ impl EthereumNode for KitchensinkNode { #[tracing::instrument(skip_all, fields(geth_node_id = self.id))] fn block_coinbase(&self, number: BlockNumberOrTag) -> anyhow::Result
{ - let provider = self.provider_no_additional_signers(); + let provider = self.provider(); BlockingExecutor::execute(async move { provider .await? @@ -484,7 +461,7 @@ impl EthereumNode for KitchensinkNode { #[tracing::instrument(skip_all, fields(geth_node_id = self.id))] fn block_difficulty(&self, number: BlockNumberOrTag) -> anyhow::Result { - let provider = self.provider_no_additional_signers(); + let provider = self.provider(); BlockingExecutor::execute(async move { provider .await? @@ -497,7 +474,7 @@ impl EthereumNode for KitchensinkNode { #[tracing::instrument(skip_all, fields(geth_node_id = self.id))] fn block_hash(&self, number: BlockNumberOrTag) -> anyhow::Result { - let provider = self.provider_no_additional_signers(); + let provider = self.provider(); BlockingExecutor::execute(async move { provider .await? @@ -510,7 +487,7 @@ impl EthereumNode for KitchensinkNode { #[tracing::instrument(skip_all, fields(geth_node_id = self.id))] fn block_timestamp(&self, number: BlockNumberOrTag) -> anyhow::Result { - let provider = self.provider_no_additional_signers(); + let provider = self.provider(); BlockingExecutor::execute(async move { provider .await? @@ -523,7 +500,7 @@ impl EthereumNode for KitchensinkNode { #[tracing::instrument(skip_all, fields(geth_node_id = self.id))] fn last_block_number(&self) -> anyhow::Result { - let provider = self.provider_no_additional_signers(); + let provider = self.provider(); BlockingExecutor::execute(async move { provider.await?.get_block_number().await.map_err(Into::into) })? @@ -531,18 +508,26 @@ impl EthereumNode for KitchensinkNode { } impl Node for KitchensinkNode { - fn new(config: &Arguments) -> Self { + fn new( + config: &Arguments, + additional_signers: impl IntoIterator + Send + Sync + 'static>, + ) -> Self { let kitchensink_directory = config.directory().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 mut wallet = config.wallet(); + for signer in additional_signers { + wallet.register_signer(signer); + } + Self { id, substrate_binary: config.kitchensink.clone(), eth_proxy_binary: config.eth_proxy.clone(), rpc_url: String::new(), - wallet: config.wallet(), + wallet, base_directory, logs_directory, process_substrate: None, @@ -1041,7 +1026,7 @@ impl BlockHeader for KitchenSinkHeader { #[cfg(test)] mod tests { - use alloy::rpc::types::TransactionRequest; + use alloy::{rpc::types::TransactionRequest, signers::local::PrivateKeySigner}; use revive_dt_config::Arguments; use std::path::PathBuf; use std::sync::{LazyLock, Mutex}; @@ -1084,7 +1069,7 @@ mod tests { let _guard = NODE_START_MUTEX.lock().unwrap(); let (args, temp_dir) = test_config(); - let mut node = KitchensinkNode::new(&args); + let mut node = KitchensinkNode::new(&args, Vec::::with_capacity(0)); node.init(GENESIS_JSON) .expect("Failed to initialize the node") .spawn_process() @@ -1106,10 +1091,7 @@ mod tests { // Arrange let (node, args, _temp_dir) = new_node(); - let provider = node - .provider_no_additional_signers() - .await - .expect("Failed to create provider"); + let provider = node.provider().await.expect("Failed to create provider"); let account_address = args.wallet().default_signer().address(); let transaction = TransactionRequest::default() @@ -1142,7 +1124,8 @@ mod tests { } "#; - let mut dummy_node = KitchensinkNode::new(&test_config().0); + let mut dummy_node = + KitchensinkNode::new(&test_config().0, Vec::::with_capacity(0)); // Call `init()` dummy_node.init(genesis_content).expect("init failed"); @@ -1186,7 +1169,8 @@ mod tests { } "#; - let node = KitchensinkNode::new(&test_config().0); + let node = + KitchensinkNode::new(&test_config().0, Vec::::with_capacity(0)); let result = node .extract_balance_from_genesis_file(genesis_json) @@ -1259,7 +1243,7 @@ mod tests { fn spawn_works() { let (config, _temp_dir) = test_config(); - let mut node = KitchensinkNode::new(&config); + let mut node = KitchensinkNode::new(&config, Vec::::with_capacity(0)); node.spawn(GENESIS_JSON.to_string()).unwrap(); } @@ -1267,7 +1251,7 @@ mod tests { fn version_works() { let (config, _temp_dir) = test_config(); - let node = KitchensinkNode::new(&config); + let node = KitchensinkNode::new(&config, Vec::::with_capacity(0)); let version = node.version().unwrap(); assert!( @@ -1280,7 +1264,7 @@ mod tests { fn eth_rpc_version_works() { let (config, _temp_dir) = test_config(); - let node = KitchensinkNode::new(&config); + let node = KitchensinkNode::new(&config, Vec::::with_capacity(0)); let version = node.eth_rpc_version().unwrap(); assert!( diff --git a/crates/node/src/lib.rs b/crates/node/src/lib.rs index 44eaf19..380f621 100644 --- a/crates/node/src/lib.rs +++ b/crates/node/src/lib.rs @@ -1,5 +1,6 @@ //! This crate implements the testing nodes. +use alloy::{network::TxSigner, signers::Signature}; use revive_dt_config::Arguments; use revive_dt_node_interaction::EthereumNode; @@ -14,7 +15,10 @@ pub const GENESIS_JSON: &str = include_str!("../../../genesis.json"); /// An abstract interface for testing nodes. pub trait Node: EthereumNode { /// Create a new uninitialized instance. - fn new(config: &Arguments) -> Self; + fn new( + config: &Arguments, + additional_signers: impl IntoIterator + Send + Sync + 'static>, + ) -> Self; /// Spawns a node configured according to the genesis json. /// diff --git a/crates/node/src/pool.rs b/crates/node/src/pool.rs index 10d4d59..363dc29 100644 --- a/crates/node/src/pool.rs +++ b/crates/node/src/pool.rs @@ -6,6 +6,7 @@ use std::{ thread, }; +use alloy::{network::TxSigner, signers::Signature}; use anyhow::Context; use revive_dt_config::Arguments; @@ -23,7 +24,14 @@ where T: Node + Send + 'static, { /// Create a new Pool. This will start as many nodes as there are workers in `config`. - pub fn new(config: &Arguments) -> anyhow::Result { + pub fn new( + config: &Arguments, + additional_signers: impl IntoIterator + Send + Sync + 'static> + + Clone + + Send + + Sync + + 'static, + ) -> anyhow::Result { let nodes = config.workers; let genesis = read_to_string(&config.genesis_file).context(format!( "can not read genesis file: {}", @@ -34,7 +42,10 @@ where for _ in 0..nodes { let config = config.clone(); let genesis = genesis.clone(); - handles.push(thread::spawn(move || spawn_node::(&config, genesis))); + let additional_signers = additional_signers.clone(); + handles.push(thread::spawn(move || { + spawn_node::(&config, additional_signers, genesis) + })); } let mut nodes = Vec::with_capacity(nodes); @@ -60,8 +71,12 @@ where } } -fn spawn_node(args: &Arguments, genesis: String) -> anyhow::Result { - let mut node = T::new(args); +fn spawn_node( + args: &Arguments, + additional_signers: impl IntoIterator + Send + Sync + 'static>, + genesis: String, +) -> anyhow::Result { + let mut node = T::new(args, additional_signers); tracing::info!("starting node: {}", node.connection_string()); node.spawn(genesis)?; Ok(node)