This commit is contained in:
pgherveou
2025-10-08 08:22:26 +02:00
parent 6e64f678ee
commit 765569a8b6
39 changed files with 662 additions and 1178 deletions
@@ -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<HashMap<ContractInstance, TransactionReceipt>> {
let mut instances_we_must_deploy = IndexMap::<ContractInstance, bool>::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<EtherValue>,
) -> Result<(Address, JsonAbi, Option<TransactionReceipt>)> {
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<TransactionReceipt> {
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");
@@ -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::<Vec<_>>();
let platforms =
context.platforms.iter().copied().map(Into::<&dyn Platform>::into).collect::<Vec<_>>();
// 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
@@ -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,
+51 -91
View File
@@ -76,7 +76,9 @@ impl<'a> Driver<'a, StepsIterator> {
.into_iter()
.collect::<BTreeMap<_, _>>();
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<usize> {
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<HashMap<ContractInstance, TransactionReceipt>> {
let mut instances_we_must_deploy = IndexMap::<ContractInstance, bool>::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::<Vec<_>>();
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<EtherValue>,
) -> Result<(Address, JsonAbi, Option<TransactionReceipt>)> {
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");
};
@@ -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::<Vec<_>>();
let platforms =
context.platforms.iter().copied().map(Into::<&dyn Platform>::into).collect::<Vec<_>>();
// 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::<usize>::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,
+9 -13
View File
@@ -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<CacheValue> {
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::<CacheValue>(&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,
}
}
}
+3 -5
View File
@@ -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::<Vec<_>>();
let pre_transactions_tasks =
nodes.iter_mut().map(|node| node.pre_transactions()).collect::<Vec<_>>();
futures::future::try_join_all(pre_transactions_tasks)
.await
.context("Failed to run the pre-transactions task")?;
+56 -69
View File
@@ -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))
}
}
+20 -39
View File
@@ -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<JoinHandle<anyhow::Result<Box<dyn EthereumNode + Send + Sync>>>> {
let genesis_configuration = AsRef::<GenesisConfiguration>::as_ref(&context);
let kitchensink_path = AsRef::<KitchensinkConfiguration>::as_ref(&context)
.path
.clone();
let kitchensink_path = AsRef::<KitchensinkConfiguration>::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<JoinHandle<anyhow::Result<Box<dyn EthereumNode + Send + Sync>>>> {
let genesis_configuration = AsRef::<GenesisConfiguration>::as_ref(&context);
let kitchensink_path = AsRef::<KitchensinkConfiguration>::as_ref(&context)
.path
.clone();
let kitchensink_path = AsRef::<KitchensinkConfiguration>::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<JoinHandle<anyhow::Result<Box<dyn EthereumNode + Send + Sync>>>> {
let genesis_configuration = AsRef::<GenesisConfiguration>::as_ref(&context);
let revive_dev_node_path = AsRef::<ReviveDevNodeConfiguration>::as_ref(&context)
.path
.clone();
let revive_dev_node_path =
AsRef::<ReviveDevNodeConfiguration>::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<JoinHandle<anyhow::Result<Box<dyn EthereumNode + Send + Sync>>>> {
let genesis_configuration = AsRef::<GenesisConfiguration>::as_ref(&context);
let revive_dev_node_path = AsRef::<ReviveDevNodeConfiguration>::as_ref(&context)
.path
.clone();
let revive_dev_node_path =
AsRef::<ReviveDevNodeConfiguration>::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<JoinHandle<anyhow::Result<Box<dyn EthereumNode + Send + Sync>>>> {
let genesis_configuration = AsRef::<GenesisConfiguration>::as_ref(&context);
let polkadot_parachain_path = AsRef::<PolkadotParachainConfiguration>::as_ref(&context)
.path
.clone();
let polkadot_parachain_path =
AsRef::<PolkadotParachainConfiguration>::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<JoinHandle<anyhow::Result<Box<dyn EthereumNode + Send + Sync>>>> {
let genesis_configuration = AsRef::<GenesisConfiguration>::as_ref(&context);
let polkadot_parachain_path = AsRef::<PolkadotParachainConfiguration>::as_ref(&context)
.path
.clone();
let polkadot_parachain_path =
AsRef::<PolkadotParachainConfiguration>::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<T: Node + EthereumNode + Send + Sync>(
mut node: T,
genesis: Genesis,
) -> anyhow::Result<T> {
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)
}