diff --git a/.gitignore b/.gitignore index acf69f1..5d06954 100644 --- a/.gitignore +++ b/.gitignore @@ -13,4 +13,5 @@ resolc-compiler-tests workdir !/schema.json -!/dev-genesis.json \ No newline at end of file +!/dev-genesis.json +geth-dev/ diff --git a/crates/common/src/cached_fs/mod.rs b/crates/common/src/cached_fs/mod.rs index 17a1fa5..3c28abd 100644 --- a/crates/common/src/cached_fs/mod.rs +++ b/crates/common/src/cached_fs/mod.rs @@ -1,9 +1,11 @@ //! This module implements a cached file system allowing for results to be stored in-memory rather //! rather being queried from the file system again. -use std::fs; -use std::io::{Error, Result}; -use std::path::{Path, PathBuf}; +use std::{ + fs, + io::{Error, Result}, + path::{Path, PathBuf}, +}; use moka::sync::Cache; use once_cell::sync::Lazy; @@ -25,10 +27,7 @@ pub fn read(path: impl AsRef) -> Result> { pub fn read_to_string(path: impl AsRef) -> Result { let content = read(path)?; String::from_utf8(content).map_err(|_| { - Error::new( - std::io::ErrorKind::InvalidData, - "The contents of the file are not valid UTF8", - ) + Error::new(std::io::ErrorKind::InvalidData, "The contents of the file are not valid UTF8") }) } diff --git a/crates/common/src/fs/clear_dir.rs b/crates/common/src/fs/clear_dir.rs index 387c134..2bc4449 100644 --- a/crates/common/src/fs/clear_dir.rs +++ b/crates/common/src/fs/clear_dir.rs @@ -12,10 +12,7 @@ pub fn clear_directory(path: impl AsRef) -> Result<()> { .with_context(|| format!("Failed to read directory: {}", path.as_ref().display()))? { let entry = entry.with_context(|| { - format!( - "Failed to read an entry in directory: {}", - path.as_ref().display() - ) + format!("Failed to read an entry in directory: {}", path.as_ref().display()) })?; let entry_path = entry.path(); diff --git a/crates/common/src/futures/poll.rs b/crates/common/src/futures/poll.rs index 8551cb7..8386591 100644 --- a/crates/common/src/futures/poll.rs +++ b/crates/common/src/futures/poll.rs @@ -1,5 +1,4 @@ -use std::ops::ControlFlow; -use std::time::Duration; +use std::{ops::ControlFlow, time::Duration}; use anyhow::{Context as _, Result, anyhow}; @@ -38,10 +37,7 @@ where )); } - match future() - .await - .context("Polled future returned an error during polling loop")? - { + match future().await.context("Polled future returned an error during polling loop")? { ControlFlow::Continue(()) => { let next_wait_duration = match polling_wait_behavior { PollingWaitBehavior::Constant(duration) => duration, diff --git a/crates/common/src/types/mode.rs b/crates/common/src/types/mode.rs index 3e2d3a9..4a9671b 100644 --- a/crates/common/src/types/mode.rs +++ b/crates/common/src/types/mode.rs @@ -1,9 +1,7 @@ use crate::types::VersionOrRequirement; use semver::Version; use serde::{Deserialize, Serialize}; -use std::fmt::Display; -use std::str::FromStr; -use std::sync::LazyLock; +use std::{fmt::Display, str::FromStr, sync::LazyLock}; /// This represents a mode that a given test should be run with, if possible. /// @@ -78,9 +76,7 @@ impl FromStr for ModePipeline { // Don't go via Yul IR "E" => Ok(ModePipeline::ViaEVMAssembly), // Anything else that we see isn't a mode at all - _ => Err(anyhow::anyhow!( - "Unsupported pipeline '{s}': expected 'Y' or 'E'" - )), + _ => Err(anyhow::anyhow!("Unsupported pipeline '{s}': expected 'Y' or 'E'")), } } } diff --git a/crates/common/src/types/private_key_allocator.rs b/crates/common/src/types/private_key_allocator.rs index 5bab1d3..c2495ab 100644 --- a/crates/common/src/types/private_key_allocator.rs +++ b/crates/common/src/types/private_key_allocator.rs @@ -1,5 +1,4 @@ -use alloy::primitives::U256; -use alloy::signers::local::PrivateKeySigner; +use alloy::{primitives::U256, signers::local::PrivateKeySigner}; use anyhow::{Context, Result, bail}; /// This is a sequential private key allocator. When instantiated, it allocated private keys in diff --git a/crates/compiler/src/lib.rs b/crates/compiler/src/lib.rs index 7780eba..e696182 100644 --- a/crates/compiler/src/lib.rs +++ b/crates/compiler/src/lib.rs @@ -10,8 +10,7 @@ use std::{ pin::Pin, }; -use alloy::json_abi::JsonAbi; -use alloy::primitives::Address; +use alloy::{json_abi::JsonAbi, primitives::Address}; use anyhow::{Context as _, Result}; use semver::Version; use serde::{Deserialize, Serialize}; diff --git a/crates/compiler/src/revive_resolc.rs b/crates/compiler/src/revive_resolc.rs index f0025ea..a5a5e57 100644 --- a/crates/compiler/src/revive_resolc.rs +++ b/crates/compiler/src/revive_resolc.rs @@ -141,9 +141,7 @@ impl SolidityCompiler for Resolc { output_selection: Some(SolcStandardJsonInputSettingsSelection::new_required()), via_ir: Some(true), optimizer: SolcStandardJsonInputSettingsOptimizer::new( - optimization - .unwrap_or(ModeOptimizerSetting::M0) - .optimizations_enabled(), + optimization.unwrap_or(ModeOptimizerSetting::M0).optimizations_enabled(), None, &Version::new(0, 0, 0), false, diff --git a/crates/compiler/src/solc.rs b/crates/compiler/src/solc.rs index 9a825ad..cba7e0f 100644 --- a/crates/compiler/src/solc.rs +++ b/crates/compiler/src/solc.rs @@ -21,8 +21,7 @@ use foundry_compilers_artifacts::{ output_selection::{ BytecodeOutputSelection, ContractOutputSelection, EvmOutputSelection, OutputSelection, }, - solc::CompilerOutput as SolcOutput, - solc::*, + solc::{CompilerOutput as SolcOutput, *}, }; use semver::Version; use tokio::{io::AsyncWriteExt, process::Command as AsyncCommand}; @@ -57,9 +56,7 @@ impl Solc { // resolution for us. Therefore, even if the download didn't proceed, this function will // resolve the version requirement into a canonical version of the compiler. It's then up // to us to either use the provided path or not. - let version = version - .into() - .unwrap_or_else(|| solc_configuration.version.clone().into()); + let version = version.into().unwrap_or_else(|| solc_configuration.version.clone().into()); let (version, path) = download_solc(working_directory_configuration.as_path(), version, false) .await @@ -253,10 +250,7 @@ impl SolidityCompiler for Solc { let map = compiler_output .contracts .entry(contract_path.canonicalize().with_context(|| { - format!( - "Failed to canonicalize contract path {}", - contract_path.display() - ) + format!("Failed to canonicalize contract path {}", contract_path.display()) })?) .or_default(); for (contract_name, contract_info) in contracts.into_iter() { diff --git a/crates/compiler/tests/lib.rs b/crates/compiler/tests/lib.rs index 5de4b90..f837882 100644 --- a/crates/compiler/tests/lib.rs +++ b/crates/compiler/tests/lib.rs @@ -9,9 +9,8 @@ use semver::Version; async fn contracts_can_be_compiled_with_solc() { // Arrange let args = TestExecutionContext::default(); - let solc = Solc::new(&args, VersionOrRequirement::Version(Version::new(0, 8, 30))) - .await - .unwrap(); + let solc = + Solc::new(&args, VersionOrRequirement::Version(Version::new(0, 8, 30))).await.unwrap(); // Act let output = Compiler::new() @@ -28,18 +27,12 @@ async fn contracts_can_be_compiled_with_solc() { let main_file_contracts = output .contracts - .get( - &PathBuf::from("./tests/assets/array_one_element/main.sol") - .canonicalize() - .unwrap(), - ) + .get(&PathBuf::from("./tests/assets/array_one_element/main.sol").canonicalize().unwrap()) .unwrap(); let callable_file_contracts = output .contracts .get( - &PathBuf::from("./tests/assets/array_one_element/callable.sol") - .canonicalize() - .unwrap(), + &PathBuf::from("./tests/assets/array_one_element/callable.sol").canonicalize().unwrap(), ) .unwrap(); assert!(main_file_contracts.contains_key("Main")); @@ -50,9 +43,8 @@ async fn contracts_can_be_compiled_with_solc() { async fn contracts_can_be_compiled_with_resolc() { // Arrange let args = TestExecutionContext::default(); - let resolc = Resolc::new(&args, VersionOrRequirement::Version(Version::new(0, 8, 30))) - .await - .unwrap(); + let resolc = + Resolc::new(&args, VersionOrRequirement::Version(Version::new(0, 8, 30))).await.unwrap(); // Act let output = Compiler::new() @@ -69,18 +61,12 @@ async fn contracts_can_be_compiled_with_resolc() { let main_file_contracts = output .contracts - .get( - &PathBuf::from("./tests/assets/array_one_element/main.sol") - .canonicalize() - .unwrap(), - ) + .get(&PathBuf::from("./tests/assets/array_one_element/main.sol").canonicalize().unwrap()) .unwrap(); let callable_file_contracts = output .contracts .get( - &PathBuf::from("./tests/assets/array_one_element/callable.sol") - .canonicalize() - .unwrap(), + &PathBuf::from("./tests/assets/array_one_element/callable.sol").canonicalize().unwrap(), ) .unwrap(); assert!(main_file_contracts.contains_key("Main")); diff --git a/crates/config/src/lib.rs b/crates/config/src/lib.rs index 7e8814b..982a281 100644 --- a/crates/config/src/lib.rs +++ b/crates/config/src/lib.rs @@ -626,11 +626,7 @@ pub struct KurtosisConfiguration { /// /// If this is not specified, then the tool assumes that it should use the kurtosis binary that's /// provided in the user's $PATH. - #[clap( - id = "kurtosis.path", - long = "kurtosis.path", - default_value = "kurtosis" - )] + #[clap(id = "kurtosis.path", long = "kurtosis.path", default_value = "kurtosis")] pub path: PathBuf, } @@ -641,11 +637,7 @@ pub struct KitchensinkConfiguration { /// /// If this is not specified, then the tool assumes that it should use the kitchensink binary /// that's provided in the user's $PATH. - #[clap( - id = "kitchensink.path", - long = "kitchensink.path", - default_value = "substrate-node" - )] + #[clap(id = "kitchensink.path", long = "kitchensink.path", default_value = "substrate-node")] pub path: PathBuf, /// The amount of time to wait upon startup before considering that the node timed out. @@ -785,6 +777,20 @@ impl WalletConfiguration { } } +impl Default for WalletConfiguration { + fn default() -> Self { + let mut config = Self::parse_from::<[&str; 0], &str>([]); + config.additional_keys = 0; + config + // config.default_key = PrivateKeySigner::from_bytes( + // &FixedBytes::from_hex_str( + // "0x4f3edf983ac636a65a842ce7c78d9aa706d3b113bce9c46f30d7d21715b23b1d", + // ) + // .unwrap(), + // ) + } +} + fn serialize_private_key(value: &PrivateKeySigner, serializer: S) -> Result where S: Serializer, @@ -823,10 +829,7 @@ impl ConcurrencyConfiguration { pub fn concurrency_limit(&self) -> Option { match self.ignore_concurrency_limit { true => None, - false => Some( - self.number_concurrent_tasks - .unwrap_or(20 * self.number_of_nodes), - ), + false => Some(self.number_concurrent_tasks.unwrap_or(20 * self.number_of_nodes)), } } } @@ -917,9 +920,7 @@ impl Serialize for WorkingDirectoryConfiguration { } fn parse_duration(s: &str) -> anyhow::Result { - u64::from_str(s) - .map(Duration::from_millis) - .map_err(Into::into) + u64::from_str(s).map(Duration::from_millis).map_err(Into::into) } /// The Solidity compatible node implementation. diff --git a/crates/core/src/differential_benchmarks/driver.rs b/crates/core/src/differential_benchmarks/driver.rs index abdc6fd..05a931b 100644 --- a/crates/core/src/differential_benchmarks/driver.rs +++ b/crates/core/src/differential_benchmarks/driver.rs @@ -206,9 +206,7 @@ where "Deployed library" ); - let library_address = receipt - .contract_address - .expect("Failed to deploy the library"); + let library_address = receipt.contract_address.expect("Failed to deploy the library"); deployed_libraries.get_or_insert_default().insert( library_instance.clone(), @@ -236,10 +234,8 @@ where }) .context("Failed to compile the post-link contracts")?; - self.execution_state = ExecutionState::new( - compiler_output.contracts, - deployed_libraries.unwrap_or_default(), - ); + self.execution_state = + ExecutionState::new(compiler_output.contracts, deployed_libraries.unwrap_or_default()); Ok(()) } @@ -325,11 +321,7 @@ where ) -> Result> { let mut instances_we_must_deploy = IndexMap::::new(); for instance in step.find_all_contract_instances().into_iter() { - if !self - .execution_state - .deployed_contracts - .contains_key(&instance) - { + if !self.execution_state.deployed_contracts.contains_key(&instance) { instances_we_must_deploy.entry(instance).or_insert(false); } } @@ -341,15 +333,11 @@ where let mut receipts = HashMap::new(); for (instance, deploy_with_constructor_arguments) in instances_we_must_deploy.into_iter() { let calldata = deploy_with_constructor_arguments.then_some(&step.calldata); - let value = deploy_with_constructor_arguments - .then_some(step.value) - .flatten(); + let value = deploy_with_constructor_arguments.then_some(step.value).flatten(); let caller = { let context = self.default_resolution_context(); - step.caller - .resolve_address(self.resolver.as_ref(), context) - .await? + step.caller.resolve_address(self.resolver.as_ref(), context).await? }; if let (_, _, Some(receipt)) = self .get_or_deploy_contract_instance(&instance, caller, calldata, value) @@ -424,18 +412,13 @@ where }; // Handling the return data variable assignments. - for (variable_name, output_word) in assignments.return_data.iter().zip( - tracing_result - .output - .as_ref() - .unwrap_or_default() - .to_vec() - .chunks(32), - ) { + for (variable_name, output_word) in assignments + .return_data + .iter() + .zip(tracing_result.output.as_ref().unwrap_or_default().to_vec().chunks(32)) + { let value = U256::from_be_slice(output_word); - self.execution_state - .variables - .insert(variable_name.clone(), value); + self.execution_state.variables.insert(variable_name.clone(), value); tracing::info!( variable_name, variable_value = hex::encode(value.to_be_bytes::<32>()), @@ -508,9 +491,8 @@ where }) .context("Failed to send message on the watcher's tx")?; - let res = futures::future::try_join_all(tasks) - .await - .context("Repetition execution failed")?; + let res = + futures::future::try_join_all(tasks).await.context("Repetition execution failed")?; Ok(res.into_iter().sum()) } @@ -533,9 +515,7 @@ where let account = private_key.address(); let variable = U256::from_be_slice(account.0.as_slice()); - self.execution_state - .variables - .insert(variable_name.to_string(), variable); + self.execution_state.variables.insert(variable_name.to_string(), variable); Ok(1) } @@ -560,10 +540,8 @@ where calldata: Option<&Calldata>, value: Option, ) -> Result<(Address, JsonAbi, Option)> { - if let Some((_, address, abi)) = self - .execution_state - .deployed_contracts - .get(contract_instance) + if let Some((_, address, abi)) = + self.execution_state.deployed_contracts.get(contract_instance) { info!( @@ -606,16 +584,9 @@ where let Some(ContractPathAndIdent { contract_source_path, contract_ident, - }) = self - .test_definition - .metadata - .contract_sources()? - .remove(contract_instance) + }) = self.test_definition.metadata.contract_sources()?.remove(contract_instance) else { - anyhow::bail!( - "Contract source not found for instance {:?}", - contract_instance - ) + anyhow::bail!("Contract source not found for instance {:?}", contract_instance) }; let Some((code, abi)) = self @@ -625,10 +596,7 @@ where .and_then(|source_file_contracts| source_file_contracts.get(contract_ident.as_ref())) .cloned() else { - anyhow::bail!( - "Failed to find information for contract {:?}", - contract_instance - ) + anyhow::bail!("Failed to find information for contract {:?}", contract_instance) }; let mut code = match alloy::hex::decode(&code) { @@ -680,10 +648,9 @@ where .reporter .report_contract_deployed_event(contract_instance.clone(), address)?; - self.execution_state.deployed_contracts.insert( - contract_instance.clone(), - (contract_ident, address, abi.clone()), - ); + self.execution_state + .deployed_contracts + .insert(contract_instance.clone(), (contract_ident, address, abi.clone())); Ok((address, abi, receipt)) } @@ -696,9 +663,7 @@ where match step_address { StepAddress::Address(address) => Ok(*address), StepAddress::ResolvableAddress(resolvable) => { - let Some(instance) = resolvable - .strip_suffix(".address") - .map(ContractInstance::new) + let Some(instance) = resolvable.strip_suffix(".address").map(ContractInstance::new) else { bail!("Not an address variable"); }; @@ -736,15 +701,15 @@ where transaction: TransactionRequest, ) -> anyhow::Result { let node = self.platform_information.node; - let transaction_hash = node - .submit_transaction(transaction) - .await - .context("Failed to submit transaction")?; + let transaction_hash = + node.submit_transaction(transaction).await.context("Failed to submit transaction")?; Span::current().record("transaction_hash", display(transaction_hash)); info!("Submitted transaction"); self.watcher_tx - .send(WatcherEvent::SubmittedTransaction { transaction_hash }) + .send(WatcherEvent::SubmittedTransaction { + transaction_hash, + }) .context("Failed to send the transaction hash to the watcher")?; info!("Starting to poll for transaction receipt"); diff --git a/crates/core/src/differential_benchmarks/entry_point.rs b/crates/core/src/differential_benchmarks/entry_point.rs index 7702d52..1cc854c 100644 --- a/crates/core/src/differential_benchmarks/entry_point.rs +++ b/crates/core/src/differential_benchmarks/entry_point.rs @@ -44,12 +44,8 @@ pub async fn handle_differential_benchmarks( info!(len = metadata_files.len(), "Discovered metadata files"); // Discover the list of platforms that the tests should run on based on the context. - let platforms = context - .platforms - .iter() - .copied() - .map(Into::<&dyn Platform>::into) - .collect::>(); + let platforms = + context.platforms.iter().copied().map(Into::<&dyn Platform>::into).collect::>(); // Starting the nodes of the various platforms specified in the context. Note that we use the // node pool since it contains all of the code needed to spawn nodes from A to Z and therefore @@ -96,13 +92,8 @@ pub async fn handle_differential_benchmarks( // Creating the objects that will be shared between the various runs. The cached compiler is the // only one at the current moment of time that's safe to share between runs. let cached_compiler = CachedCompiler::new( - context - .working_directory - .as_path() - .join("compilation_cache"), - context - .compilation_configuration - .invalidate_compilation_cache, + context.working_directory.as_path().join("compilation_cache"), + context.compilation_configuration.invalidate_compilation_cache, ) .await .map(Arc::new) @@ -161,9 +152,7 @@ pub async fn handle_differential_benchmarks( watcher.run(), driver.execute_all().inspect(|_| { info!("All transactions submitted - driver completed execution"); - watcher_tx - .send(WatcherEvent::AllTransactionsSubmitted) - .unwrap() + watcher_tx.send(WatcherEvent::AllTransactionsSubmitted).unwrap() }), ) .await diff --git a/crates/core/src/differential_benchmarks/watcher.rs b/crates/core/src/differential_benchmarks/watcher.rs index 12ea840..2d0a0aa 100644 --- a/crates/core/src/differential_benchmarks/watcher.rs +++ b/crates/core/src/differential_benchmarks/watcher.rs @@ -80,12 +80,13 @@ impl Watcher { // Subsequent repetition starts are ignored since certain workloads can // contain nested repetitions and therefore there's no use in doing any // action if the repetitions are nested. - WatcherEvent::RepetitionStartEvent { .. } => {} - WatcherEvent::SubmittedTransaction { transaction_hash } => { - watch_for_transaction_hashes - .write() - .await - .insert(transaction_hash); + WatcherEvent::RepetitionStartEvent { + .. + } => {} + WatcherEvent::SubmittedTransaction { + transaction_hash, + } => { + watch_for_transaction_hashes.write().await.insert(transaction_hash); } WatcherEvent::AllTransactionsSubmitted => { *all_transactions_submitted.write().await = true; @@ -151,15 +152,8 @@ impl Watcher { use std::io::Write; let mut stderr = std::io::stderr().lock(); - writeln!( - stderr, - "Watcher information for {}", - self.platform_identifier - )?; - writeln!( - stderr, - "block_number,block_timestamp,mined_gas,block_gas_limit,tx_count" - )?; + writeln!(stderr, "Watcher information for {}", self.platform_identifier)?; + writeln!(stderr, "block_number,block_timestamp,mined_gas,block_gas_limit,tx_count")?; for block in mined_blocks_information { writeln!( stderr, diff --git a/crates/core/src/differential_tests/driver.rs b/crates/core/src/differential_tests/driver.rs index d98c2ad..4f25723 100644 --- a/crates/core/src/differential_tests/driver.rs +++ b/crates/core/src/differential_tests/driver.rs @@ -76,7 +76,9 @@ impl<'a> Driver<'a, StepsIterator> { .into_iter() .collect::>(); - Ok(Self { platform_drivers }) + Ok(Self { + platform_drivers, + }) } async fn create_platform_driver( @@ -112,9 +114,7 @@ impl<'a> Driver<'a, StepsIterator> { pub async fn execute_all(mut self) -> Result { let platform_drivers = std::mem::take(&mut self.platform_drivers); let results = futures::future::try_join_all( - platform_drivers - .into_values() - .map(|driver| driver.execute_all()), + platform_drivers.into_values().map(|driver| driver.execute_all()), ) .await .context("Failed to execute all of the steps on the driver")?; @@ -210,12 +210,8 @@ where ) }) .context("Failed to get the contract instances from the metadata file")?; - for library_instance in test_definition - .metadata - .libraries - .iter() - .flatten() - .flat_map(|(_, map)| map.values()) + for library_instance in + test_definition.metadata.libraries.iter().flatten().flat_map(|(_, map)| map.values()) { let ContractPathAndIdent { contract_source_path: library_source_path, @@ -252,11 +248,8 @@ where TransactionRequest::default().from(deployer_address), code, ); - let receipt = platform_information - .node - .execute_transaction(tx) - .await - .inspect_err(|err| { + let receipt = + platform_information.node.execute_transaction(tx).await.inspect_err(|err| { error!( ?err, %library_instance, @@ -265,9 +258,7 @@ where ) })?; - let library_address = receipt - .contract_address - .expect("Failed to deploy the library"); + let library_address = receipt.contract_address.expect("Failed to deploy the library"); deployed_libraries.get_or_insert_default().insert( library_instance.clone(), @@ -295,10 +286,7 @@ where }) .context("Failed to compile the post-link contracts")?; - Ok(ExecutionState::new( - compiler_output.contracts, - deployed_libraries.unwrap_or_default(), - )) + Ok(ExecutionState::new(compiler_output.contracts, deployed_libraries.unwrap_or_default())) } // endregion:Constructors & Initialization @@ -392,11 +380,7 @@ where ) -> Result> { let mut instances_we_must_deploy = IndexMap::::new(); for instance in step.find_all_contract_instances().into_iter() { - if !self - .execution_state - .deployed_contracts - .contains_key(&instance) - { + if !self.execution_state.deployed_contracts.contains_key(&instance) { instances_we_must_deploy.entry(instance).or_insert(false); } } @@ -408,16 +392,13 @@ where let mut receipts = HashMap::new(); for (instance, deploy_with_constructor_arguments) in instances_we_must_deploy.into_iter() { let calldata = deploy_with_constructor_arguments.then_some(&step.calldata); - let value = deploy_with_constructor_arguments - .then_some(step.value) - .flatten(); + let value = deploy_with_constructor_arguments.then_some(step.value).flatten(); let caller = { let context = self.default_resolution_context(); let resolver = self.platform_information.node.resolver().await?; - step.caller - .resolve_address(resolver.as_ref(), context) - .await? + let resolved = step.caller.resolve_address(resolver.as_ref(), context).await?; + self.platform_information.node.resolve_signer_or_default(resolved) }; if let (_, _, Some(receipt)) = self .get_or_deploy_contract_instance(&instance, caller, calldata, value) @@ -445,7 +426,7 @@ where .context("Failed to find deployment receipt for constructor call"), Method::Fallback | Method::FunctionName(_) => { let resolver = self.platform_information.node.resolver().await?; - let tx = match step + let mut tx = match step .as_transaction(resolver.as_ref(), self.default_resolution_context()) .await { @@ -455,6 +436,11 @@ where } }; + // Resolve the signer to ensure we use an address that has keys + if let Some(from) = tx.from { + tx.from = Some(self.platform_information.node.resolve_signer_or_default(from)); + } + self.platform_information.node.execute_transaction(tx).await } } @@ -503,18 +489,13 @@ where }; // Handling the return data variable assignments. - for (variable_name, output_word) in assignments.return_data.iter().zip( - tracing_result - .output - .as_ref() - .unwrap_or_default() - .to_vec() - .chunks(32), - ) { + for (variable_name, output_word) in assignments + .return_data + .iter() + .zip(tracing_result.output.as_ref().unwrap_or_default().to_vec().chunks(32)) + { let value = U256::from_be_slice(output_word); - self.execution_state - .variables - .insert(variable_name.clone(), value); + self.execution_state.variables.insert(variable_name.clone(), value); tracing::info!( variable_name, variable_value = hex::encode(value.to_be_bytes::<32>()), @@ -546,7 +527,10 @@ where expected: Some(Expected::ExpectedMany(expected)), .. } => expected.clone(), - FunctionCallStep { expected: None, .. } => vec![ExpectedOutput::new().with_success()], + FunctionCallStep { + expected: None, + .. + } => vec![ExpectedOutput::new().with_success()], }; // This is a bit of a special case and we have to support it separately on it's own. If it's @@ -562,8 +546,7 @@ where futures::stream::iter(expectations.into_iter().map(Ok)) .try_for_each_concurrent(None, |expectation| async { - self.handle_function_call_assertion_item(receipt, tracing_result, expectation) - .await + self.handle_function_call_assertion_item(receipt, tracing_result, expectation).await }) .await } @@ -664,11 +647,8 @@ where } // Handling the topics assertion. - for (expected, actual) in expected_event - .topics - .as_slice() - .iter() - .zip(actual_event.topics()) + for (expected, actual) in + expected_event.topics.as_slice().iter().zip(actual_event.topics()) { let expected = Calldata::new_compound([expected]); if !expected @@ -764,11 +744,8 @@ where .resolve_address(resolver.as_ref(), self.default_resolution_context()) .await?; - let storage = self - .platform_information - .node - .latest_state_proof(address, Default::default()) - .await?; + let storage = + self.platform_information.node.latest_state_proof(address, Default::default()).await?; let is_empty = storage.storage_hash == EMPTY_ROOT_HASH; let expected = step.is_storage_empty; @@ -818,9 +795,8 @@ where }) .map(|driver| driver.execute_all()) .collect::>(); - let res = futures::future::try_join_all(tasks) - .await - .context("Repetition execution failed")?; + let res = + futures::future::try_join_all(tasks).await.context("Repetition execution failed")?; Ok(res.first().copied().unwrap_or_default()) } @@ -838,9 +814,7 @@ where let account = private_key.address(); let variable = U256::from_be_slice(account.0.as_slice()); - self.execution_state - .variables - .insert(variable_name.to_string(), variable); + self.execution_state.variables.insert(variable_name.to_string(), variable); Ok(1) } @@ -863,10 +837,8 @@ where calldata: Option<&Calldata>, value: Option, ) -> Result<(Address, JsonAbi, Option)> { - if let Some((_, address, abi)) = self - .execution_state - .deployed_contracts - .get(contract_instance) + if let Some((_, address, abi)) = + self.execution_state.deployed_contracts.get(contract_instance) { info!( @@ -876,6 +848,7 @@ where Ok((*address, abi.clone(), None)) } else { info!("Contract instance requires deployment."); + let (address, abi, receipt) = self .deploy_contract(contract_instance, deployer, calldata, value) .await @@ -907,16 +880,9 @@ where let Some(ContractPathAndIdent { contract_source_path, contract_ident, - }) = self - .test_definition - .metadata - .contract_sources()? - .remove(contract_instance) + }) = self.test_definition.metadata.contract_sources()?.remove(contract_instance) else { - anyhow::bail!( - "Contract source not found for instance {:?}", - contract_instance - ) + anyhow::bail!("Contract source not found for instance {:?}", contract_instance) }; let Some((code, abi)) = self @@ -926,10 +892,7 @@ where .and_then(|source_file_contracts| source_file_contracts.get(contract_ident.as_ref())) .cloned() else { - anyhow::bail!( - "Failed to find information for contract {:?}", - contract_instance - ) + anyhow::bail!("Failed to find information for contract {:?}", contract_instance) }; let mut code = match alloy::hex::decode(&code) { @@ -947,13 +910,13 @@ where if let Some(calldata) = calldata { let resolver = self.platform_information.node.resolver().await?; - let calldata = calldata - .calldata(resolver.as_ref(), self.default_resolution_context()) - .await?; + let calldata = + calldata.calldata(resolver.as_ref(), self.default_resolution_context()).await?; code.extend(calldata); } let tx = { + let deployer = self.platform_information.node.resolve_signer_or_default(deployer); let tx = TransactionRequest::default().from(deployer); let tx = match value { Some(ref value) => tx.value(value.into_inner()), @@ -982,10 +945,9 @@ where .reporter .report_contract_deployed_event(contract_instance.clone(), address)?; - self.execution_state.deployed_contracts.insert( - contract_instance.clone(), - (contract_ident, address, abi.clone()), - ); + self.execution_state + .deployed_contracts + .insert(contract_instance.clone(), (contract_ident, address, abi.clone())); Ok((address, abi, receipt)) } @@ -998,9 +960,7 @@ where match step_address { StepAddress::Address(address) => Ok(*address), StepAddress::ResolvableAddress(resolvable) => { - let Some(instance) = resolvable - .strip_suffix(".address") - .map(ContractInstance::new) + let Some(instance) = resolvable.strip_suffix(".address").map(ContractInstance::new) else { bail!("Not an address variable"); }; diff --git a/crates/core/src/differential_tests/entry_point.rs b/crates/core/src/differential_tests/entry_point.rs index 1215490..99ea61c 100644 --- a/crates/core/src/differential_tests/entry_point.rs +++ b/crates/core/src/differential_tests/entry_point.rs @@ -7,10 +7,10 @@ use std::{ time::{Duration, Instant}, }; +use crate::Platform; use anyhow::Context as _; use futures::{FutureExt, StreamExt}; use revive_dt_common::types::PrivateKeyAllocator; -use crate::Platform; use tokio::sync::{Mutex, RwLock, Semaphore}; use tracing::{Instrument, error, info, info_span, instrument}; @@ -37,12 +37,8 @@ pub async fn handle_differential_tests( info!(len = metadata_files.len(), "Discovered metadata files"); // Discover the list of platforms that the tests should run on based on the context. - let platforms = context - .platforms - .iter() - .copied() - .map(Into::<&dyn Platform>::into) - .collect::>(); + let platforms = + context.platforms.iter().copied().map(Into::<&dyn Platform>::into).collect::>(); // Starting the nodes of the various platforms specified in the context. let platforms_and_nodes = { @@ -85,13 +81,8 @@ pub async fn handle_differential_tests( // Creating everything else required for the driver to run. let cached_compiler = CachedCompiler::new( - context - .working_directory - .as_path() - .join("compilation_cache"), - context - .compilation_configuration - .invalidate_compilation_cache, + context.working_directory.as_path().join("compilation_cache"), + context.compilation_configuration.invalidate_compilation_cache, ) .await .map(Arc::new) @@ -101,11 +92,8 @@ pub async fn handle_differential_tests( ))); // Creating the driver and executing all of the steps. - let semaphore = context - .concurrency_configuration - .concurrency_limit() - .map(Semaphore::new) - .map(Arc::new); + let semaphore = + context.concurrency_configuration.concurrency_limit().map(Semaphore::new).map(Arc::new); let running_task_list = Arc::new(RwLock::new(BTreeSet::::new())); let driver_task = futures::future::join_all(test_definitions.iter().enumerate().map( |(test_id, test_definition)| { @@ -172,20 +160,14 @@ pub async fn handle_differential_tests( )) .inspect(|_| { info!("Finished executing all test cases"); - reporter_clone - .report_completion_event() - .expect("Can't fail") + reporter_clone.report_completion_event().expect("Can't fail") }); let cli_reporting_task = start_cli_reporting_task(reporter); tokio::task::spawn(async move { loop { let remaining_tasks = running_task_list.read().await; - info!( - count = remaining_tasks.len(), - ?remaining_tasks, - "Remaining Tests" - ); + info!(count = remaining_tasks.len(), ?remaining_tasks, "Remaining Tests"); tokio::time::sleep(Duration::from_secs(10)).await } }); @@ -227,7 +209,9 @@ async fn start_cli_reporting_task(reporter: Reporter) { for (case_idx, case_status) in case_status.into_iter() { let _ = write!(buf, "\tCase Index {case_idx:>3}: "); let _ = match case_status { - TestCaseStatus::Succeeded { steps_executed } => { + TestCaseStatus::Succeeded { + steps_executed, + } => { number_of_successes += 1; writeln!( buf, @@ -235,7 +219,9 @@ async fn start_cli_reporting_task(reporter: Reporter) { GREEN, BOLD, BOLD_RESET, steps_executed, COLOR_RESET ) } - TestCaseStatus::Failed { reason } => { + TestCaseStatus::Failed { + reason, + } => { number_of_failures += 1; writeln!( buf, @@ -247,7 +233,10 @@ async fn start_cli_reporting_task(reporter: Reporter) { COLOR_RESET, ) } - TestCaseStatus::Ignored { reason, .. } => writeln!( + TestCaseStatus::Ignored { + reason, + .. + } => writeln!( buf, "{}{}Case Ignored{} - Reason: {}{}", GREY, diff --git a/crates/core/src/helpers/cached_compiler.rs b/crates/core/src/helpers/cached_compiler.rs index 6ca5018..580de7c 100644 --- a/crates/core/src/helpers/cached_compiler.rs +++ b/crates/core/src/helpers/cached_compiler.rs @@ -8,10 +8,10 @@ use std::{ sync::{Arc, LazyLock}, }; +use crate::Platform; use futures::FutureExt; use revive_dt_common::{iterators::FilesWithExtensionIterator, types::CompilerIdentifier}; use revive_dt_compiler::{Compiler, CompilerOutput, Mode, SolidityCompiler}; -use crate::Platform; use revive_dt_format::metadata::{ContractIdent, ContractInstance, Metadata}; use alloy::{hex::ToHexExt, json_abi::JsonAbi, primitives::Address}; @@ -225,9 +225,7 @@ async fn compile_contracts( .flat_map(|value| value.iter()) .map(|(instance, (ident, address, abi))| (instance, ident, address, abi)) .flat_map(|(_, ident, address, _)| { - all_sources_in_dir - .iter() - .map(move |path| (ident, address, path)) + all_sources_in_dir.iter().map(move |path| (ident, address, path)) }) .fold(compiler, |compiler, (ident, address, path)| { compiler.with_library(path, ident.as_str(), *address) @@ -309,19 +307,15 @@ impl ArtifactsCache { pub async fn insert(&self, key: &CacheKey<'_>, value: &CacheValue) -> Result<()> { let key = bson::to_vec(key).context("Failed to serialize cache key (bson)")?; let value = bson::to_vec(value).context("Failed to serialize cache value (bson)")?; - cacache::write(self.path.as_path(), key.encode_hex(), value) - .await - .with_context(|| { - format!("Failed to write cache entry under {}", self.path.display()) - })?; + cacache::write(self.path.as_path(), key.encode_hex(), value).await.with_context(|| { + format!("Failed to write cache entry under {}", self.path.display()) + })?; Ok(()) } pub async fn get(&self, key: &CacheKey<'_>) -> Option { let key = bson::to_vec(key).ok()?; - let value = cacache::read(self.path.as_path(), key.encode_hex()) - .await - .ok()?; + let value = cacache::read(self.path.as_path(), key.encode_hex()).await.ok()?; let value = bson::from_slice::(&value).ok()?; Some(value) } @@ -370,6 +364,8 @@ struct CacheValue { impl CacheValue { pub fn new(compiler_output: CompilerOutput) -> Self { - Self { compiler_output } + Self { + compiler_output, + } } } diff --git a/crates/core/src/helpers/pool.rs b/crates/core/src/helpers/pool.rs index 9e0b111..48fd711 100644 --- a/crates/core/src/helpers/pool.rs +++ b/crates/core/src/helpers/pool.rs @@ -2,9 +2,9 @@ use std::sync::atomic::{AtomicUsize, Ordering}; +use crate::Platform; use anyhow::Context as _; use revive_dt_config::*; -use crate::Platform; use revive_dt_node_interaction::EthereumNode; /// The node pool starts one or more [Node] which then can be accessed @@ -37,10 +37,8 @@ impl NodePool { ); } - let pre_transactions_tasks = nodes - .iter_mut() - .map(|node| node.pre_transactions()) - .collect::>(); + let pre_transactions_tasks = + nodes.iter_mut().map(|node| node.pre_transactions()).collect::>(); futures::future::try_join_all(pre_transactions_tasks) .await .context("Failed to run the pre-transactions task")?; diff --git a/crates/core/src/helpers/test.rs b/crates/core/src/helpers/test.rs index ec16b91..22ae512 100644 --- a/crates/core/src/helpers/test.rs +++ b/crates/core/src/helpers/test.rs @@ -1,28 +1,22 @@ -use std::collections::BTreeMap; -use std::sync::Arc; -use std::{borrow::Cow, path::Path}; +use std::{borrow::Cow, collections::BTreeMap, path::Path, sync::Arc}; use futures::{Stream, StreamExt, stream}; use indexmap::{IndexMap, indexmap}; -use revive_dt_common::iterators::EitherIter; -use revive_dt_common::types::PlatformIdentifier; +use revive_dt_common::{iterators::EitherIter, types::PlatformIdentifier}; use revive_dt_config::Context; use revive_dt_format::mode::ParsedMode; use serde_json::{Value, json}; -use revive_dt_compiler::Mode; -use revive_dt_compiler::SolidityCompiler; +use revive_dt_compiler::{Mode, SolidityCompiler}; use revive_dt_format::{ case::{Case, CaseIdx}, metadata::MetadataFile, }; use revive_dt_node_interaction::EthereumNode; -use revive_dt_report::{ExecutionSpecificReporter, Reporter}; -use revive_dt_report::{TestSpecificReporter, TestSpecifier}; +use revive_dt_report::{ExecutionSpecificReporter, Reporter, TestSpecificReporter, TestSpecifier}; use tracing::{debug, error, info}; -use crate::Platform; -use crate::helpers::NodePool; +use crate::{Platform, helpers::NodePool}; pub async fn create_test_definitions_stream<'a>( // This is only required for creating the compiler objects and is not used anywhere else in the @@ -72,72 +66,68 @@ pub async fn create_test_definitions_stream<'a>( // Inform the reporter of each one of the test cases that were discovered which we expect to // run. .inspect(|(_, _, _, _, reporter)| { - reporter - .report_test_case_discovery_event() - .expect("Can't fail"); + reporter.report_test_case_discovery_event().expect("Can't fail"); }), ) // Creating the Test Definition objects from all of the various objects we have and creating // their required dependencies (e.g., compiler). - .filter_map( - move |(metadata_file, case_idx, case, mode, reporter)| async move { - let mut platforms = BTreeMap::new(); - for (platform, node_pool) in platforms_and_nodes.values() { - let node = node_pool.round_robbin(); - let compiler = platform - .new_compiler(context.clone(), mode.version.clone().map(Into::into)) - .await - .inspect_err(|err| { - error!( - ?err, - platform_identifier = %platform.platform_identifier(), - "Failed to instantiate the compiler" - ) - }) - .ok()?; - - reporter - .report_node_assigned_event( - node.id(), - platform.platform_identifier(), - node.connection_string(), + .filter_map(move |(metadata_file, case_idx, case, mode, reporter)| async move { + let mut platforms = BTreeMap::new(); + for (platform, node_pool) in platforms_and_nodes.values() { + let node = node_pool.round_robbin(); + let compiler = platform + .new_compiler(context.clone(), mode.version.clone().map(Into::into)) + .await + .inspect_err(|err| { + error!( + ?err, + platform_identifier = %platform.platform_identifier(), + "Failed to instantiate the compiler" ) - .expect("Can't fail"); + }) + .ok()?; - let reporter = - reporter.execution_specific_reporter(node.id(), platform.platform_identifier()); - - platforms.insert( + reporter + .report_node_assigned_event( + node.id(), platform.platform_identifier(), - TestPlatformInformation { - platform: *platform, - node, - compiler, - reporter, - }, - ); - } + node.connection_string(), + ) + .expect("Can't fail"); - Some(TestDefinition { - /* Metadata file information */ - metadata: metadata_file, - metadata_file_path: metadata_file.metadata_file_path.as_path(), + let reporter = + reporter.execution_specific_reporter(node.id(), platform.platform_identifier()); - /* Mode Information */ - mode: mode.clone(), + platforms.insert( + platform.platform_identifier(), + TestPlatformInformation { + platform: *platform, + node, + compiler, + reporter, + }, + ); + } - /* Case Information */ - case_idx: CaseIdx::new(case_idx), - case, + Some(TestDefinition { + /* Metadata file information */ + metadata: metadata_file, + metadata_file_path: metadata_file.metadata_file_path.as_path(), - /* Platform and Node Assignment Information */ - platforms, + /* Mode Information */ + mode: mode.clone(), - /* Reporter */ - reporter, - }) - }, - ) + /* Case Information */ + case_idx: CaseIdx::new(case_idx), + case, + + /* Platform and Node Assignment Information */ + platforms, + + /* Reporter */ + reporter, + }) + }) // Filter out the test cases which are incompatible or that can't run in the current setup. .filter_map(move |test| async move { match test.check_compatibility() { @@ -280,10 +270,7 @@ impl<'a> TestDefinition<'a> { if is_allowed { Ok(()) } else { - Err(( - "EVM version is incompatible for the platforms specified", - error_map, - )) + Err(("EVM version is incompatible for the platforms specified", error_map)) } } diff --git a/crates/core/src/lib.rs b/crates/core/src/lib.rs index 7f2e1f6..e0d5dd2 100644 --- a/crates/core/src/lib.rs +++ b/crates/core/src/lib.rs @@ -3,8 +3,8 @@ //! This crate defines the testing configuration and //! provides a helper utility to execute tests. -pub mod helpers; pub mod differential_tests; +pub mod helpers; use std::{ pin::Pin, @@ -17,9 +17,11 @@ use revive_dt_common::types::*; use revive_dt_compiler::{SolidityCompiler, revive_resolc::Resolc, solc::Solc}; use revive_dt_config::*; use revive_dt_node::{ - Node, node_implementations::geth::GethNode, - node_implementations::lighthouse_geth::LighthouseGethNode, - node_implementations::substrate::SubstrateNode, node_implementations::zombienet::ZombieNode, + Node, + node_implementations::{ + geth::GethNode, lighthouse_geth::LighthouseGethNode, substrate::SubstrateNode, + zombienet::ZombieNode, + }, }; use revive_dt_node_interaction::EthereumNode; use tracing::info; @@ -36,11 +38,7 @@ pub trait Platform { /// Returns a full identifier for the platform. fn full_identifier(&self) -> (NodeIdentifier, VmIdentifier, CompilerIdentifier) { - ( - self.node_identifier(), - self.vm_identifier(), - self.compiler_identifier(), - ) + (self.node_identifier(), self.vm_identifier(), self.compiler_identifier()) } /// Returns the identifier of the node used. @@ -182,9 +180,7 @@ impl Platform for KitchensinkPolkavmResolcPlatform { context: Context, ) -> anyhow::Result>>> { let genesis_configuration = AsRef::::as_ref(&context); - let kitchensink_path = AsRef::::as_ref(&context) - .path - .clone(); + let kitchensink_path = AsRef::::as_ref(&context).path.clone(); let genesis = genesis_configuration.genesis()?.clone(); Ok(thread::spawn(move || { let node = SubstrateNode::new( @@ -234,9 +230,7 @@ impl Platform for KitchensinkRevmSolcPlatform { context: Context, ) -> anyhow::Result>>> { let genesis_configuration = AsRef::::as_ref(&context); - let kitchensink_path = AsRef::::as_ref(&context) - .path - .clone(); + let kitchensink_path = AsRef::::as_ref(&context).path.clone(); let genesis = genesis_configuration.genesis()?.clone(); Ok(thread::spawn(move || { let node = SubstrateNode::new( @@ -286,9 +280,8 @@ impl Platform for ReviveDevNodePolkavmResolcPlatform { context: Context, ) -> anyhow::Result>>> { let genesis_configuration = AsRef::::as_ref(&context); - let revive_dev_node_path = AsRef::::as_ref(&context) - .path - .clone(); + let revive_dev_node_path = + AsRef::::as_ref(&context).path.clone(); let genesis = genesis_configuration.genesis()?.clone(); Ok(thread::spawn(move || { let node = SubstrateNode::new( @@ -338,9 +331,8 @@ impl Platform for ReviveDevNodeRevmSolcPlatform { context: Context, ) -> anyhow::Result>>> { let genesis_configuration = AsRef::::as_ref(&context); - let revive_dev_node_path = AsRef::::as_ref(&context) - .path - .clone(); + let revive_dev_node_path = + AsRef::::as_ref(&context).path.clone(); let genesis = genesis_configuration.genesis()?.clone(); Ok(thread::spawn(move || { let node = SubstrateNode::new( @@ -390,9 +382,8 @@ impl Platform for ZombienetPolkavmResolcPlatform { context: Context, ) -> anyhow::Result>>> { let genesis_configuration = AsRef::::as_ref(&context); - let polkadot_parachain_path = AsRef::::as_ref(&context) - .path - .clone(); + let polkadot_parachain_path = + AsRef::::as_ref(&context).path.clone(); let genesis = genesis_configuration.genesis()?.clone(); Ok(thread::spawn(move || { let node = ZombieNode::new(polkadot_parachain_path, context); @@ -438,9 +429,8 @@ impl Platform for ZombienetRevmSolcPlatform { context: Context, ) -> anyhow::Result>>> { let genesis_configuration = AsRef::::as_ref(&context); - let polkadot_parachain_path = AsRef::::as_ref(&context) - .path - .clone(); + let polkadot_parachain_path = + AsRef::::as_ref(&context).path.clone(); let genesis = genesis_configuration.genesis()?.clone(); Ok(thread::spawn(move || { let node = ZombieNode::new(polkadot_parachain_path, context); @@ -519,17 +509,8 @@ 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" - ); + 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/format/src/case.rs b/crates/format/src/case.rs index 7c48279..085d368 100644 --- a/crates/format/src/case.rs +++ b/crates/format/src/case.rs @@ -54,39 +54,33 @@ pub struct Case { impl Case { pub fn steps_iterator(&self) -> impl Iterator { let steps_len = self.steps.len(); - self.steps - .clone() - .into_iter() - .enumerate() - .map(move |(idx, mut step)| { - let Step::FunctionCall(ref mut input) = step else { - return step; - }; + self.steps.clone().into_iter().enumerate().map(move |(idx, mut step)| { + let Step::FunctionCall(ref mut input) = step else { + return step; + }; - if idx + 1 == steps_len { - if input.expected.is_none() { - input.expected = self.expected.clone(); - } - - // TODO: What does it mean for us to have an `expected` field on the case itself - // but the final input also has an expected field that doesn't match the one on - // the case? What are we supposed to do with that final expected field on the - // case? - - step - } else { - step + if idx + 1 == steps_len { + if input.expected.is_none() { + input.expected = self.expected.clone(); } - }) + + // TODO: What does it mean for us to have an `expected` field on the case itself + // but the final input also has an expected field that doesn't match the one on + // the case? What are we supposed to do with that final expected field on the + // case? + + step + } else { + step + } + }) } pub fn steps_iterator_for_benchmarks( &self, default_repeat_count: usize, ) -> Box + '_> { - let contains_repeat = self - .steps_iterator() - .any(|step| matches!(&step, Step::Repeat(..))); + let contains_repeat = self.steps_iterator().any(|step| matches!(&step, Step::Repeat(..))); if contains_repeat { Box::new(self.steps_iterator()) as Box<_> } else { diff --git a/crates/format/src/corpus.rs b/crates/format/src/corpus.rs index 62e81f6..1e8ecc7 100644 --- a/crates/format/src/corpus.rs +++ b/crates/format/src/corpus.rs @@ -13,8 +13,14 @@ use anyhow::Context as _; #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)] #[serde(untagged)] pub enum Corpus { - SinglePath { name: String, path: PathBuf }, - MultiplePaths { name: String, paths: Vec }, + SinglePath { + name: String, + path: PathBuf, + }, + MultiplePaths { + name: String, + paths: Vec, + }, } impl Corpus { @@ -86,46 +92,58 @@ impl Corpus { .collect::>(); tests.sort_by(|a, b| a.metadata_file_path.cmp(&b.metadata_file_path)); tests.dedup_by(|a, b| a.metadata_file_path == b.metadata_file_path); - info!( - len = tests.len(), - corpus_name = self.name(), - "Found tests in Corpus" - ); + info!(len = tests.len(), corpus_name = self.name(), "Found tests in Corpus"); tests } pub fn name(&self) -> &str { match self { - Corpus::SinglePath { name, .. } | Corpus::MultiplePaths { name, .. } => name.as_str(), + Corpus::SinglePath { + name, + .. + } + | Corpus::MultiplePaths { + name, + .. + } => name.as_str(), } } pub fn paths_iter(&self) -> impl Iterator { match self { - Corpus::SinglePath { path, .. } => { - Box::new(std::iter::once(path.as_path())) as Box> - } - Corpus::MultiplePaths { paths, .. } => { - Box::new(paths.iter().map(|path| path.as_path())) as Box> - } + Corpus::SinglePath { + path, + .. + } => Box::new(std::iter::once(path.as_path())) as Box>, + Corpus::MultiplePaths { + paths, + .. + } => Box::new(paths.iter().map(|path| path.as_path())) as Box>, } } pub fn paths_iter_mut(&mut self) -> impl Iterator { match self { - Corpus::SinglePath { path, .. } => { - Box::new(std::iter::once(path)) as Box> - } - Corpus::MultiplePaths { paths, .. } => { - Box::new(paths.iter_mut()) as Box> - } + Corpus::SinglePath { + path, + .. + } => Box::new(std::iter::once(path)) as Box>, + Corpus::MultiplePaths { + paths, + .. + } => Box::new(paths.iter_mut()) as Box>, } } pub fn path_count(&self) -> usize { match self { - Corpus::SinglePath { .. } => 1, - Corpus::MultiplePaths { paths, .. } => paths.len(), + Corpus::SinglePath { + .. + } => 1, + Corpus::MultiplePaths { + paths, + .. + } => paths.len(), } } } diff --git a/crates/format/src/metadata.rs b/crates/format/src/metadata.rs index 7632866..d2d20ee 100644 --- a/crates/format/src/metadata.rs +++ b/crates/format/src/metadata.rs @@ -44,9 +44,7 @@ impl MetadataFile { if self.corpus_file_path.is_file() { &self.corpus_file_path } else { - self.metadata_file_path - .strip_prefix(&self.corpus_file_path) - .unwrap() + self.metadata_file_path.strip_prefix(&self.corpus_file_path).unwrap() } } } @@ -167,10 +165,8 @@ impl Metadata { ) in contracts { let alias = alias.clone(); - let absolute_path = directory - .join(contract_source_path) - .canonicalize() - .map_err(|error| { + let absolute_path = + directory.join(contract_source_path).canonicalize().map_err(|error| { anyhow::anyhow!( "Failed to canonicalize contract source path '{}': {error}", directory.join(contract_source_path).display() @@ -335,12 +331,7 @@ pub struct ContractPathAndIdent { impl Display for ContractPathAndIdent { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!( - f, - "{}:{}", - self.contract_source_path.display(), - self.contract_ident.as_ref() - ) + write!(f, "{}:{}", self.contract_source_path.display(), self.contract_ident.as_ref()) } } @@ -596,10 +587,7 @@ mod test { // Assert let identifier = identifier.expect("Failed to parse"); - assert_eq!( - identifier.contract_source_path.display().to_string(), - "ERC20/ERC20.sol" - ); + assert_eq!(identifier.contract_source_path.display().to_string(), "ERC20/ERC20.sol"); assert_eq!(identifier.contract_ident, "ERC20".to_owned().into()); // Act diff --git a/crates/format/src/mode.rs b/crates/format/src/mode.rs index bf6ae03..82609f9 100644 --- a/crates/format/src/mode.rs +++ b/crates/format/src/mode.rs @@ -1,13 +1,12 @@ use anyhow::Context as _; use regex::Regex; -use revive_dt_common::iterators::EitherIter; -use revive_dt_common::types::{Mode, ModeOptimizerSetting, ModePipeline}; +use revive_dt_common::{ + iterators::EitherIter, + types::{Mode, ModeOptimizerSetting, ModePipeline}, +}; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; -use std::collections::HashSet; -use std::fmt::Display; -use std::str::FromStr; -use std::sync::LazyLock; +use std::{collections::HashSet, fmt::Display, str::FromStr, sync::LazyLock}; /// This represents a mode that has been parsed from test metadata. /// @@ -94,7 +93,11 @@ impl Display for ParsedMode { if let Some(pipeline) = self.pipeline { pipeline.fmt(f)?; if let Some(optimize_flag) = self.optimize_flag { - f.write_str(if optimize_flag { "+" } else { "-" })?; + f.write_str(if optimize_flag { + "+" + } else { + "-" + })?; } has_written = true; } @@ -158,13 +161,11 @@ impl ParsedMode { ); pipeline_iter.flat_map(move |pipeline| { - optimize_settings_iter - .clone() - .map(move |optimize_setting| Mode { - pipeline, - optimize_setting, - version: self.version.clone(), - }) + optimize_settings_iter.clone().map(move |optimize_setting| Mode { + pipeline, + optimize_setting, + version: self.version.clone(), + }) }) } @@ -236,10 +237,7 @@ mod tests { ("Y+", vec!["Y M3"]), ("Y-", vec!["Y M0"]), ("Y <=0.8", vec!["Y M0 <=0.8", "Y M3 <=0.8"]), - ( - "<=0.8", - vec!["Y M0 <=0.8", "Y M3 <=0.8", "E M0 <=0.8", "E M3 <=0.8"], - ), + ("<=0.8", vec!["Y M0 <=0.8", "Y M3 <=0.8", "E M0 <=0.8", "E M3 <=0.8"]), ]; for (actual, expected) in strings { diff --git a/crates/format/src/steps.rs b/crates/format/src/steps.rs index 19ab310..d7b3b59 100644 --- a/crates/format/src/steps.rs +++ b/crates/format/src/steps.rs @@ -1,11 +1,10 @@ use std::{collections::HashMap, fmt::Display, str::FromStr}; -use alloy::primitives::{FixedBytes, utils::parse_units}; use alloy::{ eips::BlockNumberOrTag, json_abi::Function, network::TransactionBuilder, - primitives::{Address, Bytes, U256}, + primitives::{Address, Bytes, FixedBytes, U256, utils::parse_units}, rpc::types::TransactionRequest, }; use anyhow::Context as _; @@ -17,8 +16,10 @@ use serde::{Deserialize, Serialize}; use revive_dt_common::macros::define_wrapper_type; use tracing::{Instrument, info_span, instrument}; -use crate::traits::ResolverApi; -use crate::{metadata::ContractInstance, traits::ResolutionContext}; +use crate::{ + metadata::ContractInstance, + traits::{ResolutionContext, ResolverApi}, +}; /// A test step. /// @@ -77,12 +78,7 @@ impl StepPath { impl Display for StepPath { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - self.0 - .iter() - .map(|idx| idx.to_string()) - .collect::>() - .join(".") - .fmt(f) + self.0.iter().map(|idx| idx.to_string()).collect::>().join(".").fmt(f) } } @@ -90,10 +86,7 @@ impl FromStr for StepPath { type Err = anyhow::Error; fn from_str(s: &str) -> Result { - s.split(".") - .map(StepIdx::from_str) - .collect::>>() - .map(Self) + s.split(".").map(StepIdx::from_str).collect::>>().map(Self) } } @@ -455,9 +448,7 @@ impl StepAddress { impl FunctionCallStep { pub const fn default_caller_address() -> Address { - Address(FixedBytes(alloy::hex!( - "0x90F8bf6A479f320ead074411a4B0e7944Ea8c9C1" - ))) + Address(FixedBytes(alloy::hex!("0x90F8bf6A479f320ead074411a4B0e7944Ea8c9C1"))) } pub const fn default_caller() -> StepAddress { @@ -547,11 +538,9 @@ impl FunctionCallStep { .await .context("Failed to encode input bytes for transaction request")?; let caller = self.caller.resolve_address(resolver, context).await?; - let transaction_request = TransactionRequest::default().from(caller).value( - self.value - .map(|value| value.into_inner()) - .unwrap_or_default(), - ); + let transaction_request = TransactionRequest::default() + .from(caller) + .value(self.value.map(|value| value.into_inner()).unwrap_or_default()); match self.method { Method::Deployer => Ok(transaction_request.with_deploy_code(input_data)), _ => Ok(transaction_request @@ -607,11 +596,7 @@ impl Calldata { pub fn new_compound(items: impl IntoIterator>) -> Self { Self::Compound( - items - .into_iter() - .map(|item| item.as_ref().to_owned()) - .map(CalldataItem::new) - .collect(), + items.into_iter().map(|item| item.as_ref().to_owned()).map(CalldataItem::new).collect(), ) } @@ -633,8 +618,7 @@ impl Calldata { context: ResolutionContext<'_>, ) -> anyhow::Result> { let mut buffer = Vec::::with_capacity(self.size_requirement()); - self.calldata_into_slice(&mut buffer, resolver, context) - .await?; + self.calldata_into_slice(&mut buffer, resolver, context).await?; Ok(buffer) } @@ -725,10 +709,7 @@ impl CalldataItem { ) -> anyhow::Result { let mut stack = Vec::>::new(); - for token in self - .calldata_tokens() - .map(|token| token.resolve(resolver, context)) - { + for token in self.calldata_tokens().map(|token| token.resolve(resolver, context)) { let token = token.await?; let new_token = match token { CalldataToken::Item(_) => token, @@ -769,9 +750,7 @@ impl CalldataItem { // Empty stack means that we got an empty compound calldata which we resolve to zero. [] => Ok(U256::ZERO), [CalldataToken::Item(item)] => Ok(*item), - _ => Err(anyhow::anyhow!( - "Invalid calldata arithmetic operation - Invalid stack" - )), + _ => Err(anyhow::anyhow!("Invalid calldata arithmetic operation - Invalid stack")), } } @@ -915,10 +894,7 @@ impl> CalldataToken { .await .map(U256::from) } else if let Some(variable_name) = item.strip_prefix(Self::VARIABLE_PREFIX) { - context - .variable(variable_name) - .context("Variable lookup failed") - .copied() + context.variable(variable_name).context("Variable lookup failed").copied() } else { U256::from_str_radix(item, 10) .map_err(|error| anyhow::anyhow!("Invalid decimal literal: {}", error)) @@ -959,9 +935,12 @@ impl<'de> Deserialize<'de> for EtherValue { #[cfg(test)] mod tests { - use alloy::primitives::{BlockHash, BlockNumber, BlockTimestamp, ChainId, TxHash, address}; - use alloy::sol_types::SolValue; - use alloy::{eips::BlockNumberOrTag, json_abi::JsonAbi}; + use alloy::{ + eips::BlockNumberOrTag, + json_abi::JsonAbi, + primitives::{BlockHash, BlockNumber, BlockTimestamp, ChainId, TxHash, address}, + sol_types::SolValue, + }; use std::{collections::HashMap, pin::Pin}; use super::*; @@ -1045,13 +1024,7 @@ mod tests { "#; let parsed_abi: JsonAbi = serde_json::from_str(raw_metadata).unwrap(); - let selector = parsed_abi - .function("store") - .unwrap() - .first() - .unwrap() - .selector() - .0; + let selector = parsed_abi.function("store").unwrap().first().unwrap().selector().0; let input = FunctionCallStep { instance: ContractInstance::new("Contract"), @@ -1089,13 +1062,7 @@ mod tests { ]"#; let parsed_abi: JsonAbi = serde_json::from_str(raw_abi).unwrap(); - let selector = parsed_abi - .function("send") - .unwrap() - .first() - .unwrap() - .selector() - .0; + let selector = parsed_abi.function("send").unwrap().first().unwrap().selector().0; let input: FunctionCallStep = FunctionCallStep { instance: "Contract".to_owned().into(), @@ -1117,10 +1084,7 @@ mod tests { type T = (alloy::primitives::Address,); let decoded: T = T::abi_decode(&encoded.0[4..]).unwrap(); - assert_eq!( - decoded.0, - address!("0x1000000000000000000000000000000000000001") - ); + assert_eq!(decoded.0, address!("0x1000000000000000000000000000000000000001")); } #[tokio::test] @@ -1136,13 +1100,7 @@ mod tests { ]"#; let parsed_abi: JsonAbi = serde_json::from_str(raw_abi).unwrap(); - let selector = parsed_abi - .function("send") - .unwrap() - .first() - .unwrap() - .selector() - .0; + let selector = parsed_abi.function("send").unwrap().first().unwrap().selector().0; let input: FunctionCallStep = FunctionCallStep { instance: ContractInstance::new("Contract"), @@ -1164,10 +1122,7 @@ mod tests { type T = (alloy::primitives::Address,); let decoded: T = T::abi_decode(&encoded.0[4..]).unwrap(); - assert_eq!( - decoded.0, - address!("0x1000000000000000000000000000000000000001") - ); + assert_eq!(decoded.0, address!("0x1000000000000000000000000000000000000001")); } async fn resolve_calldata_item( @@ -1204,12 +1159,7 @@ mod tests { let resolved = resolved.expect("Failed to resolve argument"); assert_eq!( resolved, - U256::from( - MockResolver - .block_gas_limit(Default::default()) - .await - .unwrap() - ) + U256::from(MockResolver.block_gas_limit(Default::default()).await.unwrap()) ) } @@ -1226,11 +1176,7 @@ mod tests { assert_eq!( resolved, U256::from_be_slice( - MockResolver - .block_coinbase(Default::default()) - .await - .unwrap() - .as_ref() + MockResolver.block_coinbase(Default::default()).await.unwrap().as_ref() ) ) } @@ -1245,13 +1191,7 @@ mod tests { // Assert let resolved = resolved.expect("Failed to resolve argument"); - assert_eq!( - resolved, - MockResolver - .block_difficulty(Default::default()) - .await - .unwrap() - ) + assert_eq!(resolved, MockResolver.block_difficulty(Default::default()).await.unwrap()) } #[tokio::test] @@ -1266,11 +1206,7 @@ mod tests { let resolved = resolved.expect("Failed to resolve argument"); assert_eq!( resolved, - MockResolver - .block_base_fee(Default::default()) - .await - .map(U256::from) - .unwrap() + MockResolver.block_base_fee(Default::default()).await.map(U256::from).unwrap() ) } @@ -1300,10 +1236,7 @@ mod tests { // Assert let resolved = resolved.expect("Failed to resolve argument"); - assert_eq!( - resolved, - U256::from(MockResolver.last_block_number().await.unwrap()) - ) + assert_eq!(resolved, U256::from(MockResolver.last_block_number().await.unwrap())) } #[tokio::test] @@ -1318,12 +1251,7 @@ mod tests { let resolved = resolved.expect("Failed to resolve argument"); assert_eq!( resolved, - U256::from( - MockResolver - .block_timestamp(Default::default()) - .await - .unwrap() - ) + U256::from(MockResolver.block_timestamp(Default::default()).await.unwrap()) ) } @@ -1401,10 +1329,7 @@ mod tests { // Assert let resolved = resolved.expect("Failed to resolve argument"); - assert_eq!( - resolved, - U256::from(MockResolver.last_block_number().await.unwrap() + 10) - ); + assert_eq!(resolved, U256::from(MockResolver.last_block_number().await.unwrap() + 10)); } #[tokio::test] diff --git a/crates/format/src/traits.rs b/crates/format/src/traits.rs index 5e1006a..94215fe 100644 --- a/crates/format/src/traits.rs +++ b/crates/format/src/traits.rs @@ -1,10 +1,10 @@ -use std::collections::HashMap; -use std::pin::Pin; +use std::{collections::HashMap, pin::Pin}; -use alloy::eips::BlockNumberOrTag; -use alloy::json_abi::JsonAbi; -use alloy::primitives::TxHash; -use alloy::primitives::{Address, BlockHash, BlockNumber, BlockTimestamp, ChainId, U256}; +use alloy::{ + eips::BlockNumberOrTag, + json_abi::JsonAbi, + primitives::{Address, BlockHash, BlockNumber, BlockTimestamp, ChainId, TxHash, U256}, +}; use anyhow::Result; use crate::metadata::{ContractIdent, ContractInstance}; @@ -149,8 +149,7 @@ impl<'a> ResolutionContext<'a> { &self, instance: &ContractInstance, ) -> Option<&(ContractIdent, Address, JsonAbi)> { - self.deployed_contracts - .and_then(|deployed_contracts| deployed_contracts.get(instance)) + self.deployed_contracts.and_then(|deployed_contracts| deployed_contracts.get(instance)) } pub fn deployed_contract_address(&self, instance: &ContractInstance) -> Option<&Address> { @@ -162,8 +161,7 @@ impl<'a> ResolutionContext<'a> { } pub fn variable(&self, name: impl AsRef) -> Option<&U256> { - self.variables - .and_then(|variables| variables.get(name.as_ref())) + self.variables.and_then(|variables| variables.get(name.as_ref())) } pub fn tip_block_number(&self) -> Option<&'a BlockNumber> { diff --git a/crates/ml-test-runner/src/main.rs b/crates/ml-test-runner/src/main.rs index 0265a71..ab40ffe 100644 --- a/crates/ml-test-runner/src/main.rs +++ b/crates/ml-test-runner/src/main.rs @@ -11,7 +11,6 @@ use revive_dt_format::{ corpus::Corpus, metadata::{Metadata, MetadataFile}, }; -use revive_dt_node_interaction::EthereumNode; use std::{ borrow::Cow, collections::{BTreeMap, HashSet}, @@ -130,10 +129,7 @@ async fn run(args: MlTestRunnerArgs) -> anyhow::Result<()> { println!("test {} ... {RED}FAILED{COLOUR_RESET}", file_display); println!(" Error loading metadata: {}", e); failed_files += 1; - failures.push(( - file_display.clone(), - format!("Error loading metadata: {}", e), - )); + failures.push((file_display.clone(), format!("Error loading metadata: {}", e))); if args.bail { break; } @@ -233,10 +229,7 @@ fn discover_test_files(path: &Path) -> anyhow::Result> { files.push(metadata.metadata_file_path); } } - _ => anyhow::bail!( - "Unsupported file extension: {}. Expected .sol or .json", - extension - ), + _ => anyhow::bail!("Unsupported file extension: {}. Expected .sol or .json", extension), } } else if path.is_dir() { // Walk directory recursively for .sol files @@ -291,12 +284,10 @@ async fn execute_test_file( let test_context = TestExecutionContext::default(); let context = revive_dt_config::Context::Test(Box::new(test_context)); - // Optionally start a node based on the --start-platform flag let node: &'static dyn revive_dt_node_interaction::EthereumNode = if args.start_platform { info!("Starting blockchain node..."); - let node_handle = platform - .new_node(context.clone()) - .context("Failed to spawn node thread")?; + let node_handle = + platform.new_node(context.clone()).context("Failed to spawn node thread")?; info!("Waiting for node to start..."); let node = node_handle @@ -304,18 +295,12 @@ async fn execute_test_file( .map_err(|e| anyhow::anyhow!("Node thread panicked: {:?}", e))? .context("Failed to start node")?; - info!( - "Node started with ID: {}, connection: {}", - node.id(), - node.connection_string() - ); + info!("Node started with ID: {}, connection: {}", node.id(), node.connection_string()); // Run pre-transactions on the node let node = Box::leak(node); // Leak to get 'static lifetime for simplicity info!("Running pre-transactions..."); - node.pre_transactions() - .await - .context("Failed to run pre-transactions")?; + node.pre_transactions().await.context("Failed to run pre-transactions")?; info!("Pre-transactions completed"); node @@ -340,9 +325,8 @@ async fn execute_test_file( .context("Failed to create cached compiler")?; // Create a private key allocator - let private_key_allocator = Arc::new(Mutex::new(PrivateKeyAllocator::new( - alloy::primitives::U256::from(100), - ))); + let private_key_allocator = + Arc::new(Mutex::new(PrivateKeyAllocator::new(alloy::primitives::U256::from(100)))); // Create reporter infrastructure (minimal, just for the Driver API) // Note: We need to keep the report_task alive, otherwise the reporter channel closes @@ -352,10 +336,7 @@ async fn execute_test_file( // Spawn the report task in the background to keep the channel open tokio::spawn(report_task); - info!( - "Building test definitions for {} case(s)", - metadata_file.cases.len() - ); + info!("Building test definitions for {} case(s)", metadata_file.cases.len()); // Build all test definitions upfront let mut test_definitions = Vec::new(); for (case_idx, case) in metadata_file.cases.iter().enumerate() { @@ -404,20 +385,17 @@ async fn execute_test_file( test_definition.case.steps.len(), test_definition.case_idx ); - let steps_executed = driver.execute_all().await.context(format!( - "Failed to execute case {}", - test_definition.case_idx - ))?; + let steps_executed = driver + .execute_all() + .await + .context(format!("Failed to execute case {}", test_definition.case_idx))?; info!( "✓ Case {} completed successfully, executed {} step(s)", test_definition.case_idx, steps_executed ); } info!("─────────────────────────────────────────────────────────────────"); - info!( - "All {} test case(s) executed successfully", - test_definitions.len() - ); + info!("All {} test case(s) executed successfully", test_definitions.len()); Ok(()) } diff --git a/crates/node-interaction/src/lib.rs b/crates/node-interaction/src/lib.rs index 7549ba9..bffc4c8 100644 --- a/crates/node-interaction/src/lib.rs +++ b/crates/node-interaction/src/lib.rs @@ -1,11 +1,14 @@ //! This crate implements all node interactions. -use std::pin::Pin; -use std::sync::Arc; +use std::{pin::Pin, sync::Arc}; -use alloy::primitives::{Address, BlockNumber, BlockTimestamp, StorageKey, TxHash, U256}; -use alloy::rpc::types::trace::geth::{DiffMode, GethDebugTracingOptions, GethTrace}; -use alloy::rpc::types::{EIP1186AccountProofResponse, TransactionReceipt, TransactionRequest}; +use alloy::{ + primitives::{Address, BlockNumber, BlockTimestamp, StorageKey, TxHash, U256}, + rpc::types::{ + EIP1186AccountProofResponse, TransactionReceipt, TransactionRequest, + trace::geth::{DiffMode, GethDebugTracingOptions, GethTrace}, + }, +}; use anyhow::Result; use futures::Stream; @@ -75,13 +78,9 @@ pub trait EthereumNode { >, >; - /// Creates a node instance from an existing running node. - fn new_existing() -> Self - where - Self: Sized, - { - panic!("new_existing is not implemented for this node type") - } + /// Checks if the provided address is in the wallet. If it is, returns the address. + /// Otherwise, returns the default signer's address. + fn resolve_signer_or_default(&self, address: Address) -> Address; } #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] diff --git a/crates/node/src/helpers/process.rs b/crates/node/src/helpers/process.rs index 5ffa5f5..8f8970a 100644 --- a/crates/node/src/helpers/process.rs +++ b/crates/node/src/helpers/process.rs @@ -33,10 +33,7 @@ impl Process { let log_file_prefix = log_file_prefix.into(); let (stdout_file_name, stderr_file_name) = match log_file_prefix { - Some(prefix) => ( - format!("{prefix}_stdout.log"), - format!("{prefix}_stderr.log"), - ), + Some(prefix) => (format!("{prefix}_stdout.log"), format!("{prefix}_stderr.log")), None => ("stdout.log".to_string(), "stderr.log".to_string()), }; @@ -57,20 +54,16 @@ impl Process { .context("Failed to open the stderr logs file")?; let mut command = { - let stdout_logs_file = stdout_logs_file - .try_clone() - .context("Failed to clone the stdout logs file")?; - let stderr_logs_file = stderr_logs_file - .try_clone() - .context("Failed to clone the stderr logs file")?; + let stdout_logs_file = + stdout_logs_file.try_clone().context("Failed to clone the stdout logs file")?; + let stderr_logs_file = + stderr_logs_file.try_clone().context("Failed to clone the stderr logs file")?; let mut command = Command::new(binary_path.as_ref()); command_building_callback(&mut command, stdout_logs_file, stderr_logs_file); command }; - let mut child = command - .spawn() - .context("Failed to spawn the built command")?; + let mut child = command.spawn().context("Failed to spawn the built command")?; match process_readiness_wait_behavior { ProcessReadinessWaitBehavior::NoStartupWait => {} @@ -128,11 +121,7 @@ impl Process { } } ProcessReadinessWaitBehavior::WaitForCommandToExit => { - if !child - .wait() - .context("Failed waiting for process to finish")? - .success() - { + if !child.wait().context("Failed waiting for process to finish")?.success() { anyhow::bail!("Failed to spawn command"); } } @@ -149,12 +138,8 @@ impl Process { impl Drop for Process { fn drop(&mut self) { self.child.kill().expect("Failed to kill the process"); - self.stdout_logs_file - .flush() - .expect("Failed to flush the stdout logs file"); - self.stderr_logs_file - .flush() - .expect("Failed to flush the stderr logs file"); + self.stdout_logs_file.flush().expect("Failed to flush the stdout logs file"); + self.stderr_logs_file.flush().expect("Failed to flush the stderr logs file"); } } diff --git a/crates/node/src/node_implementations/geth.rs b/crates/node/src/node_implementations/geth.rs index 349db98..8d67bc1 100644 --- a/crates/node/src/node_implementations/geth.rs +++ b/crates/node/src/node_implementations/geth.rs @@ -18,7 +18,9 @@ use alloy::{ eips::BlockNumberOrTag, genesis::{Genesis, GenesisAccount}, network::{Ethereum, EthereumWallet, NetworkWallet}, - primitives::{Address, BlockHash, BlockNumber, BlockTimestamp, StorageKey, TxHash, U256}, + primitives::{ + Address, BlockHash, BlockNumber, BlockTimestamp, ChainId, StorageKey, TxHash, U256, + }, providers::{ Provider, ext::DebugApi, @@ -75,6 +77,7 @@ pub struct GethNode { wallet: Arc, nonce_manager: CachedNonceManager, provider: OnceCell>>, + chain_id: ChainId, } impl GethNode { @@ -105,9 +108,7 @@ impl GethNode { 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 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()); @@ -125,6 +126,25 @@ impl GethNode { wallet: wallet.clone(), nonce_manager: Default::default(), provider: Default::default(), + chain_id: CHAIN_ID, + } + } + + pub fn new_existing() -> Self { + let wallet_config = revive_dt_config::WalletConfiguration::default(); + Self { + connection_string: "http://localhost:8545".to_string(), + base_directory: PathBuf::new(), + data_directory: PathBuf::new(), + logs_directory: PathBuf::new(), + geth: PathBuf::new(), + id: 0, + chain_id: 1337, + handle: None, + start_timeout: Duration::from_secs(0), + wallet: wallet_config.wallet(), + nonce_manager: Default::default(), + provider: Default::default(), } } @@ -176,11 +196,7 @@ impl GethNode { .read_to_string(&mut stderr) .context("Failed to read geth --init stderr")?; - if !child - .wait() - .context("Failed waiting for geth --init process to finish")? - .success() - { + if !child.wait().context("Failed waiting for geth --init process to finish")?.success() { anyhow::bail!("failed to initialize geth node #{:?}: {stderr}", &self.id); } @@ -240,8 +256,7 @@ impl GethNode { Ok(process) => self.handle = Some(process), Err(err) => { error!(?err, "Failed to start geth, shutting down gracefully"); - self.shutdown() - .context("Failed to gracefully shutdown after geth start error")?; + self.shutdown().context("Failed to gracefully shutdown after geth start error")?; return Err(err); } } @@ -255,7 +270,7 @@ impl GethNode { construct_concurrency_limited_provider::( self.connection_string.as_str(), FallbackGasFiller::default(), - ChainIdFiller::new(Some(CHAIN_ID)), + ChainIdFiller::new(Some(self.chain_id)), NonceFiller::new(self.nonce_manager.clone()), self.wallet.clone(), ) @@ -386,10 +401,7 @@ impl EthereumNode for GethNode { } }, ) - .instrument(tracing::info_span!( - "Awaiting transaction receipt", - ?transaction_hash - )) + .instrument(tracing::info_span!("Awaiting transaction receipt", ?transaction_hash)) .await }) } @@ -401,10 +413,8 @@ impl EthereumNode for GethNode { trace_options: GethDebugTracingOptions, ) -> Pin> + '_>> { Box::pin(async move { - let provider = self - .provider() - .await - .context("Failed to create provider for tracing")?; + let provider = + self.provider().await.context("Failed to create provider for tracing")?; poll( Self::TRACE_POLLING_DURATION, PollingWaitBehavior::Constant(Duration::from_millis(200)), @@ -412,10 +422,7 @@ impl EthereumNode for GethNode { let provider = provider.clone(); let trace_options = trace_options.clone(); async move { - match provider - .debug_trace_transaction(tx_hash, trace_options) - .await - { + match provider.debug_trace_transaction(tx_hash, trace_options).await { Ok(trace) => Ok(ControlFlow::Break(trace)), Err(error) => { let error_string = error.to_string(); @@ -495,7 +502,10 @@ impl EthereumNode for GethNode { Box::pin(async move { let id = self.id; let provider = self.provider().await?; - Ok(Arc::new(GethNodeResolver { id, provider }) as Arc) + Ok(Arc::new(GethNodeResolver { + id, + provider, + }) as Arc) }) } @@ -543,19 +553,13 @@ impl EthereumNode for GethNode { }) } - fn new_existing() -> Self { - Self { - connection_string: "http://localhost:8545".to_string(), - base_directory: PathBuf::new(), - data_directory: PathBuf::new(), - logs_directory: PathBuf::new(), - geth: PathBuf::new(), - id: 0, - handle: None, - start_timeout: Duration::from_secs(0), - wallet: Arc::new(EthereumWallet::default()), - nonce_manager: Default::default(), - provider: Default::default(), + fn resolve_signer_or_default(&self, address: Address) -> Address { + let signer_addresses: Vec<_> = + >::signer_addresses(&self.wallet).collect(); + if signer_addresses.contains(&address) { + address + } else { + self.wallet.default_signer().address() } } } @@ -644,10 +648,7 @@ impl ResolverApi for GethNodeResolver { .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") + block.header.base_fee_per_gas.context("Failed to get the base fee per gas") }) }) } @@ -764,11 +765,7 @@ mod tests { // Arrange let (context, node) = shared_state(); - let account_address = context - .wallet_configuration - .wallet() - .default_signer() - .address(); + let account_address = context.wallet_configuration.wallet().default_signer().address(); let transaction = TransactionRequest::default() .to(account_address) .value(U256::from(100_000_000_000_000u128)); @@ -791,10 +788,7 @@ mod tests { // Assert let version = version.expect("Failed to get the version"); - assert!( - version.starts_with("geth version"), - "expected version string, got: '{version}'" - ); + assert!(version.starts_with("geth version"), "expected version string, got: '{version}'"); } #[tokio::test] @@ -818,12 +812,8 @@ mod tests { let node = shared_node(); // Act - let gas_limit = node - .resolver() - .await - .unwrap() - .block_gas_limit(BlockNumberOrTag::Latest) - .await; + let gas_limit = + node.resolver().await.unwrap().block_gas_limit(BlockNumberOrTag::Latest).await; // Assert let _ = gas_limit.expect("Failed to get the gas limit"); @@ -836,12 +826,8 @@ mod tests { let node = shared_node(); // Act - let coinbase = node - .resolver() - .await - .unwrap() - .block_coinbase(BlockNumberOrTag::Latest) - .await; + let coinbase = + node.resolver().await.unwrap().block_coinbase(BlockNumberOrTag::Latest).await; // Assert let _ = coinbase.expect("Failed to get the coinbase"); @@ -854,12 +840,8 @@ mod tests { let node = shared_node(); // Act - let block_difficulty = node - .resolver() - .await - .unwrap() - .block_difficulty(BlockNumberOrTag::Latest) - .await; + let block_difficulty = + node.resolver().await.unwrap().block_difficulty(BlockNumberOrTag::Latest).await; // Assert let _ = block_difficulty.expect("Failed to get the block difficulty"); @@ -872,12 +854,7 @@ mod tests { let node = shared_node(); // Act - let block_hash = node - .resolver() - .await - .unwrap() - .block_hash(BlockNumberOrTag::Latest) - .await; + let block_hash = node.resolver().await.unwrap().block_hash(BlockNumberOrTag::Latest).await; // Assert let _ = block_hash.expect("Failed to get the block hash"); @@ -890,12 +867,8 @@ mod tests { let node = shared_node(); // Act - let block_timestamp = node - .resolver() - .await - .unwrap() - .block_timestamp(BlockNumberOrTag::Latest) - .await; + let block_timestamp = + node.resolver().await.unwrap().block_timestamp(BlockNumberOrTag::Latest).await; // Assert let _ = block_timestamp.expect("Failed to get the block timestamp"); diff --git a/crates/node/src/node_implementations/lighthouse_geth.rs b/crates/node/src/node_implementations/lighthouse_geth.rs index 2c82ba4..2982af9 100644 --- a/crates/node/src/node_implementations/lighthouse_geth.rs +++ b/crates/node/src/node_implementations/lighthouse_geth.rs @@ -132,9 +132,7 @@ impl LighthouseGethNode { let wallet_configuration = AsRef::::as_ref(&context); let kurtosis_configuration = AsRef::::as_ref(&context); - let geth_directory = working_directory_configuration - .as_path() - .join(Self::BASE_DIRECTORY); + 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()); @@ -147,10 +145,7 @@ impl LighthouseGethNode { http_connection_string: String::default(), enclave_name: format!( "enclave-{}-{}", - SystemTime::now() - .duration_since(UNIX_EPOCH) - .expect("Must not fail") - .as_nanos(), + SystemTime::now().duration_since(UNIX_EPOCH).expect("Must not fail").as_nanos(), id ), @@ -183,8 +178,7 @@ impl LighthouseGethNode { fn init(&mut self, _: Genesis) -> anyhow::Result<&mut Self> { self.init_directories() .context("Failed to initialize the directories of the Lighthouse Geth node.")?; - self.init_kurtosis_config_file() - .context("Failed to write the config file to the FS")?; + self.init_kurtosis_config_file().context("Failed to write the config file to the FS")?; Ok(self) } @@ -426,9 +420,8 @@ impl LighthouseGethNode { .context("Full block subscriber")?; let mut tx_hashes = futures::future::try_join_all( - NetworkWallet::::signer_addresses(self.wallet.as_ref()) - .enumerate() - .map(|(nonce, address)| async move { + NetworkWallet::::signer_addresses(self.wallet.as_ref()).enumerate().map( + |(nonce, address)| async move { let mut transaction = TransactionRequest::default() .from(self.prefunded_account_address) .to(address) @@ -436,7 +429,8 @@ impl LighthouseGethNode { .value(INITIAL_BALANCE.try_into().unwrap()); transaction.chain_id = Some(CHAIN_ID); self.submit_transaction(transaction).await - }), + }, + ), ) .await .context("Failed to submit all transactions")? @@ -531,10 +525,7 @@ impl LighthouseGethNode { } }, ) - .instrument(tracing::info_span!( - "Awaiting transaction receipt", - ?transaction_hash - )) + .instrument(tracing::info_span!("Awaiting transaction receipt", ?transaction_hash)) .await }) } @@ -623,9 +614,7 @@ impl EthereumNode for LighthouseGethNode { ) -> Pin> + '_>> { Box::pin(async move { let provider = Arc::new( - self.http_provider() - .await - .context("Failed to create provider for tracing")?, + self.http_provider().await.context("Failed to create provider for tracing")?, ); poll( Self::TRACE_POLLING_DURATION, @@ -634,10 +623,7 @@ impl EthereumNode for LighthouseGethNode { let provider = provider.clone(); let trace_options = trace_options.clone(); async move { - match provider - .debug_trace_transaction(tx_hash, trace_options) - .await - { + match provider.debug_trace_transaction(tx_hash, trace_options).await { Ok(trace) => Ok(ControlFlow::Break(trace)), Err(error) => { let error_string = error.to_string(); @@ -717,7 +703,10 @@ impl EthereumNode for LighthouseGethNode { Box::pin(async move { let id = self.id; let provider = self.ws_provider().await?; - Ok(Arc::new(LighthouseGethNodeResolver { id, provider }) as Arc) + Ok(Arc::new(LighthouseGethNodeResolver { + id, + provider, + }) as Arc) }) } @@ -761,6 +750,16 @@ impl EthereumNode for LighthouseGethNode { as Pin>>) }) } + + fn resolve_signer_or_default(&self, address: Address) -> Address { + let signer_addresses: Vec<_> = + >::signer_addresses(&self.wallet).collect(); + if signer_addresses.contains(&address) { + address + } else { + self.wallet.default_signer().address() + } + } } pub struct LighthouseGethNodeResolver, P: Provider> { @@ -849,10 +848,7 @@ impl, P: Provider> ResolverApi .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") + block.header.base_fee_per_gas.context("Failed to get the base fee per gas") }) }) } @@ -906,11 +902,7 @@ impl Node for LighthouseGethNode { .spawn() .expect("Failed to spawn the enclave kill command"); - if !child - .wait() - .expect("Failed to wait for the enclave kill command") - .success() - { + if !child.wait().expect("Failed to wait for the enclave kill command").success() { let stdout = { let mut stdout = String::default(); child @@ -1136,11 +1128,7 @@ mod tests { let (context, node) = new_node(); node.fund_all_accounts().await.expect("Failed"); - let account_address = context - .wallet_configuration - .wallet() - .default_signer() - .address(); + let account_address = context.wallet_configuration.wallet().default_signer().address(); let transaction = TransactionRequest::default() .to(account_address) .value(U256::from(100_000_000_000_000u128)); @@ -1163,10 +1151,7 @@ mod tests { // Assert let version = version.expect("Failed to get the version"); - assert!( - version.starts_with("CLI Version"), - "expected version string, got: '{version}'" - ); + assert!(version.starts_with("CLI Version"), "expected version string, got: '{version}'"); } #[tokio::test] @@ -1190,12 +1175,8 @@ mod tests { let (_context, node) = new_node(); // Act - let gas_limit = node - .resolver() - .await - .unwrap() - .block_gas_limit(BlockNumberOrTag::Latest) - .await; + let gas_limit = + node.resolver().await.unwrap().block_gas_limit(BlockNumberOrTag::Latest).await; // Assert let _ = gas_limit.expect("Failed to get the gas limit"); @@ -1208,12 +1189,8 @@ mod tests { let (_context, node) = new_node(); // Act - let coinbase = node - .resolver() - .await - .unwrap() - .block_coinbase(BlockNumberOrTag::Latest) - .await; + let coinbase = + node.resolver().await.unwrap().block_coinbase(BlockNumberOrTag::Latest).await; // Assert let _ = coinbase.expect("Failed to get the coinbase"); @@ -1226,12 +1203,8 @@ mod tests { let (_context, node) = new_node(); // Act - let block_difficulty = node - .resolver() - .await - .unwrap() - .block_difficulty(BlockNumberOrTag::Latest) - .await; + let block_difficulty = + node.resolver().await.unwrap().block_difficulty(BlockNumberOrTag::Latest).await; // Assert let _ = block_difficulty.expect("Failed to get the block difficulty"); @@ -1244,12 +1217,7 @@ mod tests { let (_context, node) = new_node(); // Act - let block_hash = node - .resolver() - .await - .unwrap() - .block_hash(BlockNumberOrTag::Latest) - .await; + let block_hash = node.resolver().await.unwrap().block_hash(BlockNumberOrTag::Latest).await; // Assert let _ = block_hash.expect("Failed to get the block hash"); @@ -1262,12 +1230,8 @@ mod tests { let (_context, node) = new_node(); // Act - let block_timestamp = node - .resolver() - .await - .unwrap() - .block_timestamp(BlockNumberOrTag::Latest) - .await; + let block_timestamp = + node.resolver().await.unwrap().block_timestamp(BlockNumberOrTag::Latest).await; // Assert let _ = block_timestamp.expect("Failed to get the block timestamp"); diff --git a/crates/node/src/node_implementations/substrate.rs b/crates/node/src/node_implementations/substrate.rs index e3724ce..052e050 100644 --- a/crates/node/src/node_implementations/substrate.rs +++ b/crates/node/src/node_implementations/substrate.rs @@ -108,9 +108,7 @@ impl SubstrateNode { ) -> Self { let working_directory_path = AsRef::::as_ref(&context).as_path(); - let eth_rpc_path = AsRef::::as_ref(&context) - .path - .as_path(); + let eth_rpc_path = AsRef::::as_ref(&context).path.as_path(); let wallet = AsRef::::as_ref(&context).wallet(); let substrate_directory = working_directory_path.join(Self::BASE_DIRECTORY); @@ -134,6 +132,24 @@ impl SubstrateNode { } } + pub fn new_existing() -> Self { + let wallet_config = revive_dt_config::WalletConfiguration::default(); + Self { + id: 0, + node_binary: PathBuf::new(), + eth_proxy_binary: PathBuf::new(), + export_chainspec_command: String::new(), + rpc_url: "http://localhost:8545".to_string(), + base_directory: PathBuf::new(), + logs_directory: PathBuf::new(), + substrate_process: None, + eth_proxy_process: None, + wallet: wallet_config.wallet(), + nonce_manager: Default::default(), + provider: Default::default(), + } + } + fn init(&mut self, mut genesis: Genesis) -> anyhow::Result<&mut Self> { let _ = remove_dir_all(self.base_directory.as_path()); let _ = clear_directory(&self.base_directory); @@ -309,15 +325,12 @@ impl SubstrateNode { &self, genesis: &Genesis, ) -> anyhow::Result> { - genesis - .alloc - .iter() - .try_fold(Vec::new(), |mut vec, (address, acc)| { - let substrate_address = Self::eth_to_substrate_address(address); - let balance = acc.balance.try_into()?; - vec.push((substrate_address, balance)); - Ok(vec) - }) + genesis.alloc.iter().try_fold(Vec::new(), |mut vec, (address, acc)| { + let substrate_address = Self::eth_to_substrate_address(address); + let balance = acc.balance.try_into()?; + vec.push((substrate_address, balance)); + Ok(vec) + }) } fn eth_to_substrate_address(address: &Address) -> String { @@ -412,10 +425,7 @@ impl EthereumNode for SubstrateNode { transaction: TransactionRequest, ) -> Pin> + '_>> { Box::pin(async move { - let provider = self - .provider() - .await - .context("Failed to create the provider")?; + let provider = self.provider().await.context("Failed to create the provider")?; execute_transaction(provider, transaction).await }) } @@ -492,7 +502,10 @@ impl EthereumNode for SubstrateNode { Box::pin(async move { let id = self.id; let provider = self.provider().await?; - Ok(Arc::new(SubstrateNodeResolver { id, provider }) as Arc) + Ok(Arc::new(SubstrateNodeResolver { + id, + provider, + }) as Arc) }) } @@ -513,10 +526,8 @@ impl EthereumNode for SubstrateNode { .provider() .await .context("Failed to create the provider for block subscription")?; - let mut block_subscription = provider - .watch_full_blocks() - .await - .context("Failed to create the blocks stream")?; + let mut block_subscription = + provider.watch_full_blocks().await.context("Failed to create the blocks stream")?; block_subscription.set_channel_size(0xFFFF); block_subscription.set_poll_interval(Duration::from_secs(1)); let block_stream = block_subscription.into_stream(); @@ -542,20 +553,13 @@ impl EthereumNode for SubstrateNode { }) } - fn new_existing() -> Self { - Self { - id: 0, - node_binary: PathBuf::new(), - eth_proxy_binary: PathBuf::new(), - export_chainspec_command: String::new(), - rpc_url: "http://localhost:8545".to_string(), - base_directory: PathBuf::new(), - logs_directory: PathBuf::new(), - substrate_process: None, - eth_proxy_process: None, - wallet: Arc::new(EthereumWallet::default()), - nonce_manager: Default::default(), - provider: Default::default(), + fn resolve_signer_or_default(&self, address: Address) -> Address { + let signer_addresses: Vec<_> = + >::signer_addresses(&self.wallet).collect(); + if signer_addresses.contains(&address) { + address + } else { + self.wallet.default_signer().address() } } } @@ -644,10 +648,7 @@ impl ResolverApi for SubstrateNodeResolver { .context("Failed to get the substrate block")? .context("Failed to get the substrate 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") + block.header.base_fee_per_gas.context("Failed to get the base fee per gas") }) }) } @@ -926,25 +927,26 @@ impl TransactionBuilder for ::TransactionReq ); match result { Ok(unsigned_tx) => Ok(unsigned_tx), - Err(UnbuiltTransactionError { request, error }) => { - Err(UnbuiltTransactionError:: { - request, - error: match error { - TransactionBuilderError::InvalidTransactionRequest(tx_type, items) => { - TransactionBuilderError::InvalidTransactionRequest(tx_type, items) - } - TransactionBuilderError::UnsupportedSignatureType => { - TransactionBuilderError::UnsupportedSignatureType - } - TransactionBuilderError::Signer(error) => { - TransactionBuilderError::Signer(error) - } - TransactionBuilderError::Custom(error) => { - TransactionBuilderError::Custom(error) - } - }, - }) - } + Err(UnbuiltTransactionError { + request, + error, + }) => Err(UnbuiltTransactionError:: { + request, + error: match error { + TransactionBuilderError::InvalidTransactionRequest(tx_type, items) => { + TransactionBuilderError::InvalidTransactionRequest(tx_type, items) + } + TransactionBuilderError::UnsupportedSignatureType => { + TransactionBuilderError::UnsupportedSignatureType + } + TransactionBuilderError::Signer(error) => { + TransactionBuilderError::Signer(error) + } + TransactionBuilderError::Custom(error) => { + TransactionBuilderError::Custom(error) + } + }, + }), } } @@ -1212,11 +1214,7 @@ mod tests { let provider = node.provider().await.expect("Failed to create provider"); - let account_address = context - .wallet_configuration - .wallet() - .default_signer() - .address(); + let account_address = context.wallet_configuration.wallet().default_signer().address(); let transaction = TransactionRequest::default() .to(account_address) .value(U256::from(100_000_000_000_000u128)); @@ -1256,14 +1254,11 @@ mod tests { ); // Call `init()` - dummy_node - .init(serde_json::from_str(genesis_content).unwrap()) - .expect("init failed"); + dummy_node.init(serde_json::from_str(genesis_content).unwrap()).expect("init failed"); // Check that the patched chainspec file was generated - let final_chainspec_path = dummy_node - .base_directory - .join(SubstrateNode::CHAIN_SPEC_JSON_FILE); + let final_chainspec_path = + dummy_node.base_directory.join(SubstrateNode::CHAIN_SPEC_JSON_FILE); assert!(final_chainspec_path.exists(), "Chainspec file should exist"); let contents = fs::read_to_string(&final_chainspec_path).expect("Failed to read chainspec"); @@ -1369,10 +1364,7 @@ mod tests { for (eth_addr, expected_ss58) in cases { let result = SubstrateNode::eth_to_substrate_address(ð_addr.parse().unwrap()); - assert_eq!( - result, expected_ss58, - "Mismatch for Ethereum address {eth_addr}" - ); + assert_eq!(result, expected_ss58, "Mismatch for Ethereum address {eth_addr}"); } } @@ -1423,12 +1415,8 @@ mod tests { let node = shared_node(); // Act - let gas_limit = node - .resolver() - .await - .unwrap() - .block_gas_limit(BlockNumberOrTag::Latest) - .await; + let gas_limit = + node.resolver().await.unwrap().block_gas_limit(BlockNumberOrTag::Latest).await; // Assert let _ = gas_limit.expect("Failed to get the gas limit"); @@ -1441,12 +1429,8 @@ mod tests { let node = shared_node(); // Act - let coinbase = node - .resolver() - .await - .unwrap() - .block_coinbase(BlockNumberOrTag::Latest) - .await; + let coinbase = + node.resolver().await.unwrap().block_coinbase(BlockNumberOrTag::Latest).await; // Assert let _ = coinbase.expect("Failed to get the coinbase"); @@ -1459,12 +1443,8 @@ mod tests { let node = shared_node(); // Act - let block_difficulty = node - .resolver() - .await - .unwrap() - .block_difficulty(BlockNumberOrTag::Latest) - .await; + let block_difficulty = + node.resolver().await.unwrap().block_difficulty(BlockNumberOrTag::Latest).await; // Assert let _ = block_difficulty.expect("Failed to get the block difficulty"); @@ -1477,12 +1457,7 @@ mod tests { let node = shared_node(); // Act - let block_hash = node - .resolver() - .await - .unwrap() - .block_hash(BlockNumberOrTag::Latest) - .await; + let block_hash = node.resolver().await.unwrap().block_hash(BlockNumberOrTag::Latest).await; // Assert let _ = block_hash.expect("Failed to get the block hash"); @@ -1495,12 +1470,8 @@ mod tests { let node = shared_node(); // Act - let block_timestamp = node - .resolver() - .await - .unwrap() - .block_timestamp(BlockNumberOrTag::Latest) - .await; + let block_timestamp = + node.resolver().await.unwrap().block_timestamp(BlockNumberOrTag::Latest).await; // Assert let _ = block_timestamp.expect("Failed to get the block timestamp"); diff --git a/crates/node/src/node_implementations/zombienet.rs b/crates/node/src/node_implementations/zombienet.rs index 9a43f40..55b6c90 100644 --- a/crates/node/src/node_implementations/zombienet.rs +++ b/crates/node/src/node_implementations/zombienet.rs @@ -130,14 +130,10 @@ impl ZombieNode { + AsRef + AsRef, ) -> Self { - let eth_proxy_binary = AsRef::::as_ref(&context) - .path - .to_owned(); + let eth_proxy_binary = AsRef::::as_ref(&context).path.to_owned(); let working_directory_path = AsRef::::as_ref(&context); let id = NODE_COUNT.fetch_add(1, Ordering::SeqCst); - let base_directory = working_directory_path - .join(Self::BASE_DIRECTORY) - .join(id.to_string()); + let base_directory = working_directory_path.join(Self::BASE_DIRECTORY).join(id.to_string()); let logs_directory = base_directory.join(Self::LOGS_DIRECTORY); let wallet = AsRef::::as_ref(&context).wallet(); @@ -169,10 +165,8 @@ impl ZombieNode { let template_chainspec_path = self.base_directory.join(Self::CHAIN_SPEC_JSON_FILE); self.prepare_chainspec(template_chainspec_path.clone(), genesis)?; - let polkadot_parachain_path = self - .polkadot_parachain_path - .to_str() - .context("Invalid polkadot parachain path")?; + let polkadot_parachain_path = + self.polkadot_parachain_path.to_str().context("Invalid polkadot parachain path")?; let node_rpc_port = Self::NODE_BASE_RPC_PORT + self.id as u16; @@ -204,10 +198,8 @@ impl ZombieNode { } fn spawn_process(&mut self) -> anyhow::Result<()> { - let network_config = self - .network_config - .clone() - .context("Node not initialized, call init() first")?; + let network_config = + self.network_config.clone().context("Node not initialized, call init() first")?; let rt = tokio::runtime::Runtime::new().unwrap(); let network = rt.block_on(async { @@ -272,17 +264,12 @@ impl ZombieNode { mut genesis: Genesis, ) -> anyhow::Result<()> { let mut cmd: Command = std::process::Command::new(&self.polkadot_parachain_path); - cmd.arg(Self::EXPORT_CHAINSPEC_COMMAND) - .arg("--chain") - .arg("asset-hub-westend-local"); + cmd.arg(Self::EXPORT_CHAINSPEC_COMMAND).arg("--chain").arg("asset-hub-westend-local"); let output = cmd.output().context("Failed to export the chain-spec")?; if !output.status.success() { - anyhow::bail!( - "Build chain-spec failed: {}", - String::from_utf8_lossy(&output.stderr) - ); + anyhow::bail!("Build chain-spec failed: {}", String::from_utf8_lossy(&output.stderr)); } let content = String::from_utf8(output.stdout) @@ -343,15 +330,12 @@ impl ZombieNode { &self, genesis: &Genesis, ) -> anyhow::Result> { - genesis - .alloc - .iter() - .try_fold(Vec::new(), |mut vec, (address, acc)| { - let polkadot_address = Self::eth_to_polkadot_address(address); - let balance = acc.balance.try_into()?; - vec.push((polkadot_address, balance)); - Ok(vec) - }) + genesis.alloc.iter().try_fold(Vec::new(), |mut vec, (address, acc)| { + let polkadot_address = Self::eth_to_polkadot_address(address); + let balance = acc.balance.try_into()?; + vec.push((polkadot_address, balance)); + Ok(vec) + }) } fn eth_to_polkadot_address(address: &Address) -> String { @@ -535,7 +519,10 @@ impl EthereumNode for ZombieNode { let id = self.id; let provider = self.provider().await?; - Ok(Arc::new(ZombieNodeResolver { id, provider }) as Arc) + Ok(Arc::new(ZombieNodeResolver { + id, + provider, + }) as Arc) }) } @@ -556,10 +543,8 @@ impl EthereumNode for ZombieNode { .provider() .await .context("Failed to create the provider for block subscription")?; - let mut block_subscription = provider - .watch_full_blocks() - .await - .context("Failed to create the blocks stream")?; + let mut block_subscription = + provider.watch_full_blocks().await.context("Failed to create the blocks stream")?; block_subscription.set_channel_size(0xFFFF); block_subscription.set_poll_interval(Duration::from_secs(1)); let block_stream = block_subscription.into_stream(); @@ -584,6 +569,16 @@ impl EthereumNode for ZombieNode { as Pin>>) }) } + + fn resolve_signer_or_default(&self, address: Address) -> Address { + let signer_addresses: Vec<_> = + >::signer_addresses(&self.wallet).collect(); + if signer_addresses.contains(&address) { + address + } else { + self.wallet.default_signer().address() + } + } } pub struct ZombieNodeResolver, P: Provider> { @@ -672,10 +667,7 @@ impl, P: Provider> ResolverApi .context("Failed to get the zombie block")? .context("Failed to get the zombie 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") + block.header.base_fee_per_gas.context("Failed to get the base fee per gas") }) }) } @@ -787,10 +779,8 @@ mod tests { pub async fn new_node() -> (TestExecutionContext, ZombieNode) { let context = test_config(); - let mut node = ZombieNode::new( - context.polkadot_parachain_configuration.path.clone(), - &context, - ); + let mut node = + ZombieNode::new(context.polkadot_parachain_configuration.path.clone(), &context); let genesis = context.genesis_configuration.genesis().unwrap().clone(); node.init(genesis).unwrap(); @@ -855,14 +845,11 @@ mod tests { "#; let context = test_config(); - let mut node = ZombieNode::new( - context.polkadot_parachain_configuration.path.clone(), - &context, - ); + let mut node = + ZombieNode::new(context.polkadot_parachain_configuration.path.clone(), &context); // Call `init()` - node.init(serde_json::from_str(genesis_content).unwrap()) - .expect("init failed"); + node.init(serde_json::from_str(genesis_content).unwrap()).expect("init failed"); // Check that the patched chainspec file was generated let final_chainspec_path = node.base_directory.join(ZombieNode::CHAIN_SPEC_JSON_FILE); @@ -903,10 +890,7 @@ mod tests { "#; let context = test_config(); - let node = ZombieNode::new( - context.polkadot_parachain_configuration.path.clone(), - &context, - ); + let node = ZombieNode::new(context.polkadot_parachain_configuration.path.clone(), &context); let result = node .extract_balance_from_genesis_file(&serde_json::from_str(genesis_json).unwrap()) @@ -968,10 +952,7 @@ mod tests { for (eth_addr, expected_ss58) in cases { let result = ZombieNode::eth_to_polkadot_address(ð_addr.parse().unwrap()); - assert_eq!( - result, expected_ss58, - "Mismatch for Ethereum address {eth_addr}" - ); + assert_eq!(result, expected_ss58, "Mismatch for Ethereum address {eth_addr}"); } } @@ -979,10 +960,7 @@ mod tests { fn eth_rpc_version_works() { // Arrange let context = test_config(); - let node = ZombieNode::new( - context.polkadot_parachain_configuration.path.clone(), - &context, - ); + let node = ZombieNode::new(context.polkadot_parachain_configuration.path.clone(), &context); // Act let version = node.eth_rpc_version().unwrap(); @@ -998,10 +976,7 @@ mod tests { fn version_works() { // Arrange let context = test_config(); - let node = ZombieNode::new( - context.polkadot_parachain_configuration.path.clone(), - &context, - ); + let node = ZombieNode::new(context.polkadot_parachain_configuration.path.clone(), &context); // Act let version = node.version().unwrap(); @@ -1039,12 +1014,8 @@ mod tests { let node = shared_node().await; // Act - let gas_limit = node - .resolver() - .await - .unwrap() - .block_gas_limit(BlockNumberOrTag::Latest) - .await; + let gas_limit = + node.resolver().await.unwrap().block_gas_limit(BlockNumberOrTag::Latest).await; // Assert let _ = gas_limit.expect("Failed to get the gas limit"); @@ -1057,12 +1028,8 @@ mod tests { let node = shared_node().await; // Act - let coinbase = node - .resolver() - .await - .unwrap() - .block_coinbase(BlockNumberOrTag::Latest) - .await; + let coinbase = + node.resolver().await.unwrap().block_coinbase(BlockNumberOrTag::Latest).await; // Assert let _ = coinbase.expect("Failed to get the coinbase"); @@ -1075,12 +1042,8 @@ mod tests { let node = shared_node().await; // Act - let block_difficulty = node - .resolver() - .await - .unwrap() - .block_difficulty(BlockNumberOrTag::Latest) - .await; + let block_difficulty = + node.resolver().await.unwrap().block_difficulty(BlockNumberOrTag::Latest).await; // Assert let _ = block_difficulty.expect("Failed to get the block difficulty"); @@ -1093,12 +1056,7 @@ mod tests { let node = shared_node().await; // Act - let block_hash = node - .resolver() - .await - .unwrap() - .block_hash(BlockNumberOrTag::Latest) - .await; + let block_hash = node.resolver().await.unwrap().block_hash(BlockNumberOrTag::Latest).await; // Assert let _ = block_hash.expect("Failed to get the block hash"); @@ -1111,12 +1069,8 @@ mod tests { let node = shared_node().await; // Act - let block_timestamp = node - .resolver() - .await - .unwrap() - .block_timestamp(BlockNumberOrTag::Latest) - .await; + let block_timestamp = + node.resolver().await.unwrap().block_timestamp(BlockNumberOrTag::Latest).await; // Assert let _ = block_timestamp.expect("Failed to get the block timestamp"); diff --git a/crates/node/src/provider_utils/concurrency_limiter.rs b/crates/node/src/provider_utils/concurrency_limiter.rs index 73878b9..30b9e50 100644 --- a/crates/node/src/provider_utils/concurrency_limiter.rs +++ b/crates/node/src/provider_utils/concurrency_limiter.rs @@ -55,10 +55,7 @@ where let future = self.service.call(req); Box::pin(async move { - let _permit = semaphore - .acquire() - .await - .expect("Semaphore has been closed"); + let _permit = semaphore.acquire().await.expect("Semaphore has been closed"); tracing::debug!( available_permits = semaphore.available_permits(), "Acquired Semaphore Permit" diff --git a/crates/node/src/provider_utils/provider.rs b/crates/node/src/provider_utils/provider.rs index 6862537..5eca89b 100644 --- a/crates/node/src/provider_utils/provider.rs +++ b/crates/node/src/provider_utils/provider.rs @@ -80,10 +80,8 @@ where NonceFiller: TxFiller, WalletFiller: TxFiller, { - let sendable_transaction = provider - .fill(transaction) - .await - .context("Failed to fill transaction")?; + let sendable_transaction = + provider.fill(transaction).await.context("Failed to fill transaction")?; let transaction_envelope = sendable_transaction .try_into_envelope() @@ -105,24 +103,21 @@ where debug!(%tx_hash, "Submitted Transaction"); pending_transaction.set_timeout(Some(Duration::from_secs(120))); - let tx_hash = pending_transaction.watch().await.context(format!( - "Transaction inclusion watching timeout for {tx_hash}" - ))?; + let tx_hash = pending_transaction + .watch() + .await + .context(format!("Transaction inclusion watching timeout for {tx_hash}"))?; - poll( - Duration::from_secs(60), - PollingWaitBehavior::Constant(Duration::from_secs(3)), - || { - let provider = provider.clone(); + poll(Duration::from_secs(60), PollingWaitBehavior::Constant(Duration::from_secs(3)), || { + let provider = provider.clone(); - async move { - match provider.get_transaction_receipt(tx_hash).await { - Ok(Some(receipt)) => Ok(ControlFlow::Break(receipt)), - _ => Ok(ControlFlow::Continue(())), - } + async move { + match provider.get_transaction_receipt(tx_hash).await { + Ok(Some(receipt)) => Ok(ControlFlow::Break(receipt)), + _ => Ok(ControlFlow::Continue(())), } - }, - ) + } + }) .await .context(format!("Polling for receipt failed for {tx_hash}")) } diff --git a/crates/report/src/aggregator.rs b/crates/report/src/aggregator.rs index bb235eb..5015edb 100644 --- a/crates/report/src/aggregator.rs +++ b/crates/report/src/aggregator.rs @@ -123,12 +123,8 @@ impl ReportAggregator { file_name.push_str(".json"); file_name }; - let file_path = self - .report - .context - .working_directory_configuration() - .as_path() - .join(file_name); + let file_path = + self.report.context.working_directory_configuration().as_path().join(file_name); let file = OpenOptions::new() .create(true) .write(true) @@ -136,10 +132,7 @@ impl ReportAggregator { .read(false) .open(&file_path) .with_context(|| { - format!( - "Failed to open report file for writing: {}", - file_path.display() - ) + format!("Failed to open report file for writing: {}", file_path.display()) })?; serde_json::to_writer_pretty(&file, &self.report).with_context(|| { format!("Failed to serialize report JSON to {}", file_path.display()) @@ -241,10 +234,7 @@ impl ReportAggregator { .or_default() .iter() .map(|(case_idx, case_report)| { - ( - *case_idx, - case_report.status.clone().expect("Can't be uninitialized"), - ) + (*case_idx, case_report.status.clone().expect("Can't be uninitialized")) }) .collect::>(); let event = ReporterEvent::MetadataFileSolcModeCombinationExecutionCompleted { @@ -276,16 +266,8 @@ impl ReportAggregator { &mut self, event: PreLinkContractsCompilationSucceededEvent, ) { - let include_input = self - .report - .context - .report_configuration() - .include_compiler_input; - let include_output = self - .report - .context - .report_configuration() - .include_compiler_output; + let include_input = self.report.context.report_configuration().include_compiler_input; + let include_output = self.report.context.report_configuration().include_compiler_output; let execution_information = self.execution_information(&event.execution_specifier); @@ -313,16 +295,8 @@ impl ReportAggregator { &mut self, event: PostLinkContractsCompilationSucceededEvent, ) { - let include_input = self - .report - .context - .report_configuration() - .include_compiler_input; - let include_output = self - .report - .context - .report_configuration() - .include_compiler_output; + let include_input = self.report.context.report_configuration().include_compiler_input; + let include_output = self.report.context.report_configuration().include_compiler_output; let execution_information = self.execution_information(&event.execution_specifier); @@ -375,8 +349,8 @@ impl ReportAggregator { } fn handle_libraries_deployed_event(&mut self, event: LibrariesDeployedEvent) { - self.execution_information(&event.execution_specifier) - .deployed_libraries = Some(event.libraries); + self.execution_information(&event.execution_specifier).deployed_libraries = + Some(event.libraries); } fn handle_contract_deployed_event(&mut self, event: ContractDeployedEvent) { diff --git a/crates/report/src/runner_event.rs b/crates/report/src/runner_event.rs index f6d322f..a022dde 100644 --- a/crates/report/src/runner_event.rs +++ b/crates/report/src/runner_event.rs @@ -8,8 +8,10 @@ use anyhow::Context as _; use indexmap::IndexMap; use revive_dt_common::types::PlatformIdentifier; use revive_dt_compiler::{CompilerInput, CompilerOutput}; -use revive_dt_format::metadata::Metadata; -use revive_dt_format::{corpus::Corpus, metadata::ContractInstance}; +use revive_dt_format::{ + corpus::Corpus, + metadata::{ContractInstance, Metadata}, +}; use semver::Version; use tokio::sync::{broadcast, oneshot}; diff --git a/crates/solc-binaries/src/cache.rs b/crates/solc-binaries/src/cache.rs index 46211a7..388ce2d 100644 --- a/crates/solc-binaries/src/cache.rs +++ b/crates/solc-binaries/src/cache.rs @@ -22,9 +22,8 @@ pub(crate) async fn get_or_download( working_directory: &Path, downloader: &SolcDownloader, ) -> anyhow::Result<(Version, PathBuf)> { - let target_directory = working_directory - .join(SOLC_CACHE_DIRECTORY) - .join(downloader.version.to_string()); + let target_directory = + working_directory.join(SOLC_CACHE_DIRECTORY).join(downloader.version.to_string()); let target_file = target_directory.join(downloader.target); let mut cache = SOLC_CACHER.lock().await; @@ -34,19 +33,11 @@ pub(crate) async fn get_or_download( } create_dir_all(&target_directory).with_context(|| { - format!( - "Failed to create solc cache directory: {}", - target_directory.display() - ) + format!("Failed to create solc cache directory: {}", target_directory.display()) })?; download_to_file(&target_file, downloader) .await - .with_context(|| { - format!( - "Failed to write downloaded solc to {}", - target_file.display() - ) - })?; + .with_context(|| format!("Failed to write downloaded solc to {}", target_file.display()))?; cache.insert(target_file.clone()); Ok((downloader.version.clone(), target_file)) @@ -70,15 +61,9 @@ async fn download_to_file(path: &Path, downloader: &SolcDownloader) -> anyhow::R } let mut file = BufWriter::new(file); - file.write_all( - &downloader - .download() - .await - .context("Failed to download solc binary bytes")?, - ) - .with_context(|| format!("Failed to write solc binary to {}", path.display()))?; - file.flush() - .with_context(|| format!("Failed to flush file {}", path.display()))?; + file.write_all(&downloader.download().await.context("Failed to download solc binary bytes")?) + .with_context(|| format!("Failed to write solc binary to {}", path.display()))?; + file.flush().with_context(|| format!("Failed to flush file {}", path.display()))?; drop(file); #[cfg(target_os = "macos")] @@ -91,17 +76,11 @@ async fn download_to_file(path: &Path, downloader: &SolcDownloader) -> anyhow::R .stdout(std::process::Stdio::null()) .spawn() .with_context(|| { - format!( - "Failed to spawn xattr to remove quarantine attribute on {}", - path.display() - ) + format!("Failed to spawn xattr to remove quarantine attribute on {}", path.display()) })? .wait() .with_context(|| { - format!( - "Failed waiting for xattr operation to complete on {}", - path.display() - ) + format!("Failed waiting for xattr operation to complete on {}", path.display()) })?; Ok(()) diff --git a/crates/solc-binaries/src/download.rs b/crates/solc-binaries/src/download.rs index 19f7aa1..9e8d88f 100644 --- a/crates/solc-binaries/src/download.rs +++ b/crates/solc-binaries/src/download.rs @@ -130,11 +130,7 @@ impl SolcDownloader { })?; let path = build.path.clone(); - let expected_digest = build - .sha256 - .strip_prefix("0x") - .unwrap_or(&build.sha256) - .to_string(); + let expected_digest = build.sha256.strip_prefix("0x").unwrap_or(&build.sha256).to_string(); let url = format!("{}/{}/{}", Self::BASE_URL, self.target, path.display()); let file = reqwest::get(&url) @@ -159,54 +155,25 @@ mod tests { #[tokio::test] async fn try_get_windows() { - let version = List::download(List::WINDOWS_URL) - .await - .unwrap() - .latest_release; - SolcDownloader::windows(version) - .await - .unwrap() - .download() - .await - .unwrap(); + let version = List::download(List::WINDOWS_URL).await.unwrap().latest_release; + SolcDownloader::windows(version).await.unwrap().download().await.unwrap(); } #[tokio::test] async fn try_get_macosx() { - let version = List::download(List::MACOSX_URL) - .await - .unwrap() - .latest_release; - SolcDownloader::macosx(version) - .await - .unwrap() - .download() - .await - .unwrap(); + let version = List::download(List::MACOSX_URL).await.unwrap().latest_release; + SolcDownloader::macosx(version).await.unwrap().download().await.unwrap(); } #[tokio::test] async fn try_get_linux() { - let version = List::download(List::LINUX_URL) - .await - .unwrap() - .latest_release; - SolcDownloader::linux(version) - .await - .unwrap() - .download() - .await - .unwrap(); + let version = List::download(List::LINUX_URL).await.unwrap().latest_release; + SolcDownloader::linux(version).await.unwrap().download().await.unwrap(); } #[tokio::test] async fn try_get_wasm() { let version = List::download(List::WASM_URL).await.unwrap().latest_release; - SolcDownloader::wasm(version) - .await - .unwrap() - .download() - .await - .unwrap(); + SolcDownloader::wasm(version).await.unwrap().download().await.unwrap(); } }