mirror of
https://github.com/pezkuwichain/revive-differential-tests.git
synced 2026-07-21 23:15:43 +00:00
fix lint
This commit is contained in:
@@ -27,7 +27,10 @@ pub fn read(path: impl AsRef<Path>) -> Result<Vec<u8>> {
|
|||||||
pub fn read_to_string(path: impl AsRef<Path>) -> Result<String> {
|
pub fn read_to_string(path: impl AsRef<Path>) -> Result<String> {
|
||||||
let content = read(path)?;
|
let content = read(path)?;
|
||||||
String::from_utf8(content).map_err(|_| {
|
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",
|
||||||
|
)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,10 @@ pub fn clear_directory(path: impl AsRef<Path>) -> Result<()> {
|
|||||||
.with_context(|| format!("Failed to read directory: {}", path.as_ref().display()))?
|
.with_context(|| format!("Failed to read directory: {}", path.as_ref().display()))?
|
||||||
{
|
{
|
||||||
let entry = entry.with_context(|| {
|
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();
|
let entry_path = entry.path();
|
||||||
|
|
||||||
|
|||||||
@@ -37,7 +37,10 @@ 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(()) => {
|
ControlFlow::Continue(()) => {
|
||||||
let next_wait_duration = match polling_wait_behavior {
|
let next_wait_duration = match polling_wait_behavior {
|
||||||
PollingWaitBehavior::Constant(duration) => duration,
|
PollingWaitBehavior::Constant(duration) => duration,
|
||||||
|
|||||||
@@ -76,7 +76,9 @@ impl FromStr for ModePipeline {
|
|||||||
// Don't go via Yul IR
|
// Don't go via Yul IR
|
||||||
"E" => Ok(ModePipeline::ViaEVMAssembly),
|
"E" => Ok(ModePipeline::ViaEVMAssembly),
|
||||||
// Anything else that we see isn't a mode at all
|
// 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'"
|
||||||
|
)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -141,7 +141,9 @@ impl SolidityCompiler for Resolc {
|
|||||||
output_selection: Some(SolcStandardJsonInputSettingsSelection::new_required()),
|
output_selection: Some(SolcStandardJsonInputSettingsSelection::new_required()),
|
||||||
via_ir: Some(true),
|
via_ir: Some(true),
|
||||||
optimizer: SolcStandardJsonInputSettingsOptimizer::new(
|
optimizer: SolcStandardJsonInputSettingsOptimizer::new(
|
||||||
optimization.unwrap_or(ModeOptimizerSetting::M0).optimizations_enabled(),
|
optimization
|
||||||
|
.unwrap_or(ModeOptimizerSetting::M0)
|
||||||
|
.optimizations_enabled(),
|
||||||
None,
|
None,
|
||||||
&Version::new(0, 0, 0),
|
&Version::new(0, 0, 0),
|
||||||
false,
|
false,
|
||||||
|
|||||||
@@ -56,7 +56,9 @@ impl Solc {
|
|||||||
// resolution for us. Therefore, even if the download didn't proceed, this function will
|
// 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
|
// 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.
|
// 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) =
|
let (version, path) =
|
||||||
download_solc(working_directory_configuration.as_path(), version, false)
|
download_solc(working_directory_configuration.as_path(), version, false)
|
||||||
.await
|
.await
|
||||||
@@ -250,7 +252,10 @@ impl SolidityCompiler for Solc {
|
|||||||
let map = compiler_output
|
let map = compiler_output
|
||||||
.contracts
|
.contracts
|
||||||
.entry(contract_path.canonicalize().with_context(|| {
|
.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();
|
.or_default();
|
||||||
for (contract_name, contract_info) in contracts.into_iter() {
|
for (contract_name, contract_info) in contracts.into_iter() {
|
||||||
|
|||||||
@@ -9,8 +9,9 @@ use semver::Version;
|
|||||||
async fn contracts_can_be_compiled_with_solc() {
|
async fn contracts_can_be_compiled_with_solc() {
|
||||||
// Arrange
|
// Arrange
|
||||||
let args = TestExecutionContext::default();
|
let args = TestExecutionContext::default();
|
||||||
let solc =
|
let solc = Solc::new(&args, VersionOrRequirement::Version(Version::new(0, 8, 30)))
|
||||||
Solc::new(&args, VersionOrRequirement::Version(Version::new(0, 8, 30))).await.unwrap();
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
let output = Compiler::new()
|
let output = Compiler::new()
|
||||||
@@ -27,12 +28,18 @@ async fn contracts_can_be_compiled_with_solc() {
|
|||||||
|
|
||||||
let main_file_contracts = output
|
let main_file_contracts = output
|
||||||
.contracts
|
.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();
|
.unwrap();
|
||||||
let callable_file_contracts = output
|
let callable_file_contracts = output
|
||||||
.contracts
|
.contracts
|
||||||
.get(
|
.get(
|
||||||
&PathBuf::from("./tests/assets/array_one_element/callable.sol").canonicalize().unwrap(),
|
&PathBuf::from("./tests/assets/array_one_element/callable.sol")
|
||||||
|
.canonicalize()
|
||||||
|
.unwrap(),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert!(main_file_contracts.contains_key("Main"));
|
assert!(main_file_contracts.contains_key("Main"));
|
||||||
@@ -43,8 +50,9 @@ async fn contracts_can_be_compiled_with_solc() {
|
|||||||
async fn contracts_can_be_compiled_with_resolc() {
|
async fn contracts_can_be_compiled_with_resolc() {
|
||||||
// Arrange
|
// Arrange
|
||||||
let args = TestExecutionContext::default();
|
let args = TestExecutionContext::default();
|
||||||
let resolc =
|
let resolc = Resolc::new(&args, VersionOrRequirement::Version(Version::new(0, 8, 30)))
|
||||||
Resolc::new(&args, VersionOrRequirement::Version(Version::new(0, 8, 30))).await.unwrap();
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
let output = Compiler::new()
|
let output = Compiler::new()
|
||||||
@@ -61,12 +69,18 @@ async fn contracts_can_be_compiled_with_resolc() {
|
|||||||
|
|
||||||
let main_file_contracts = output
|
let main_file_contracts = output
|
||||||
.contracts
|
.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();
|
.unwrap();
|
||||||
let callable_file_contracts = output
|
let callable_file_contracts = output
|
||||||
.contracts
|
.contracts
|
||||||
.get(
|
.get(
|
||||||
&PathBuf::from("./tests/assets/array_one_element/callable.sol").canonicalize().unwrap(),
|
&PathBuf::from("./tests/assets/array_one_element/callable.sol")
|
||||||
|
.canonicalize()
|
||||||
|
.unwrap(),
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert!(main_file_contracts.contains_key("Main"));
|
assert!(main_file_contracts.contains_key("Main"));
|
||||||
|
|||||||
@@ -626,7 +626,11 @@ pub struct KurtosisConfiguration {
|
|||||||
///
|
///
|
||||||
/// If this is not specified, then the tool assumes that it should use the kurtosis binary that's
|
/// If this is not specified, then the tool assumes that it should use the kurtosis binary that's
|
||||||
/// provided in the user's $PATH.
|
/// 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,
|
pub path: PathBuf,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -637,7 +641,11 @@ pub struct KitchensinkConfiguration {
|
|||||||
///
|
///
|
||||||
/// If this is not specified, then the tool assumes that it should use the kitchensink binary
|
/// If this is not specified, then the tool assumes that it should use the kitchensink binary
|
||||||
/// that's provided in the user's $PATH.
|
/// 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,
|
pub path: PathBuf,
|
||||||
|
|
||||||
/// The amount of time to wait upon startup before considering that the node timed out.
|
/// The amount of time to wait upon startup before considering that the node timed out.
|
||||||
@@ -829,7 +837,10 @@ impl ConcurrencyConfiguration {
|
|||||||
pub fn concurrency_limit(&self) -> Option<usize> {
|
pub fn concurrency_limit(&self) -> Option<usize> {
|
||||||
match self.ignore_concurrency_limit {
|
match self.ignore_concurrency_limit {
|
||||||
true => None,
|
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),
|
||||||
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -920,7 +931,9 @@ impl Serialize for WorkingDirectoryConfiguration {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn parse_duration(s: &str) -> anyhow::Result<Duration> {
|
fn parse_duration(s: &str) -> anyhow::Result<Duration> {
|
||||||
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.
|
/// The Solidity compatible node implementation.
|
||||||
|
|||||||
@@ -206,7 +206,9 @@ where
|
|||||||
"Deployed library"
|
"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(
|
deployed_libraries.get_or_insert_default().insert(
|
||||||
library_instance.clone(),
|
library_instance.clone(),
|
||||||
@@ -234,8 +236,10 @@ where
|
|||||||
})
|
})
|
||||||
.context("Failed to compile the post-link contracts")?;
|
.context("Failed to compile the post-link contracts")?;
|
||||||
|
|
||||||
self.execution_state =
|
self.execution_state = ExecutionState::new(
|
||||||
ExecutionState::new(compiler_output.contracts, deployed_libraries.unwrap_or_default());
|
compiler_output.contracts,
|
||||||
|
deployed_libraries.unwrap_or_default(),
|
||||||
|
);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -321,7 +325,11 @@ where
|
|||||||
) -> Result<HashMap<ContractInstance, TransactionReceipt>> {
|
) -> Result<HashMap<ContractInstance, TransactionReceipt>> {
|
||||||
let mut instances_we_must_deploy = IndexMap::<ContractInstance, bool>::new();
|
let mut instances_we_must_deploy = IndexMap::<ContractInstance, bool>::new();
|
||||||
for instance in step.find_all_contract_instances().into_iter() {
|
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);
|
instances_we_must_deploy.entry(instance).or_insert(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -333,11 +341,15 @@ where
|
|||||||
let mut receipts = HashMap::new();
|
let mut receipts = HashMap::new();
|
||||||
for (instance, deploy_with_constructor_arguments) in instances_we_must_deploy.into_iter() {
|
for (instance, deploy_with_constructor_arguments) in instances_we_must_deploy.into_iter() {
|
||||||
let calldata = deploy_with_constructor_arguments.then_some(&step.calldata);
|
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 caller = {
|
||||||
let context = self.default_resolution_context();
|
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
|
if let (_, _, Some(receipt)) = self
|
||||||
.get_or_deploy_contract_instance(&instance, caller, calldata, value)
|
.get_or_deploy_contract_instance(&instance, caller, calldata, value)
|
||||||
@@ -412,13 +424,18 @@ where
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Handling the return data variable assignments.
|
// Handling the return data variable assignments.
|
||||||
for (variable_name, output_word) in assignments
|
for (variable_name, output_word) in assignments.return_data.iter().zip(
|
||||||
.return_data
|
tracing_result
|
||||||
.iter()
|
.output
|
||||||
.zip(tracing_result.output.as_ref().unwrap_or_default().to_vec().chunks(32))
|
.as_ref()
|
||||||
{
|
.unwrap_or_default()
|
||||||
|
.to_vec()
|
||||||
|
.chunks(32),
|
||||||
|
) {
|
||||||
let value = U256::from_be_slice(output_word);
|
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!(
|
tracing::info!(
|
||||||
variable_name,
|
variable_name,
|
||||||
variable_value = hex::encode(value.to_be_bytes::<32>()),
|
variable_value = hex::encode(value.to_be_bytes::<32>()),
|
||||||
@@ -491,8 +508,9 @@ where
|
|||||||
})
|
})
|
||||||
.context("Failed to send message on the watcher's tx")?;
|
.context("Failed to send message on the watcher's tx")?;
|
||||||
|
|
||||||
let res =
|
let res = futures::future::try_join_all(tasks)
|
||||||
futures::future::try_join_all(tasks).await.context("Repetition execution failed")?;
|
.await
|
||||||
|
.context("Repetition execution failed")?;
|
||||||
Ok(res.into_iter().sum())
|
Ok(res.into_iter().sum())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -515,7 +533,9 @@ where
|
|||||||
let account = private_key.address();
|
let account = private_key.address();
|
||||||
let variable = U256::from_be_slice(account.0.as_slice());
|
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)
|
Ok(1)
|
||||||
}
|
}
|
||||||
@@ -540,8 +560,10 @@ where
|
|||||||
calldata: Option<&Calldata>,
|
calldata: Option<&Calldata>,
|
||||||
value: Option<EtherValue>,
|
value: Option<EtherValue>,
|
||||||
) -> Result<(Address, JsonAbi, Option<TransactionReceipt>)> {
|
) -> Result<(Address, JsonAbi, Option<TransactionReceipt>)> {
|
||||||
if let Some((_, address, abi)) =
|
if let Some((_, address, abi)) = self
|
||||||
self.execution_state.deployed_contracts.get(contract_instance)
|
.execution_state
|
||||||
|
.deployed_contracts
|
||||||
|
.get(contract_instance)
|
||||||
{
|
{
|
||||||
info!(
|
info!(
|
||||||
|
|
||||||
@@ -584,9 +606,16 @@ where
|
|||||||
let Some(ContractPathAndIdent {
|
let Some(ContractPathAndIdent {
|
||||||
contract_source_path,
|
contract_source_path,
|
||||||
contract_ident,
|
contract_ident,
|
||||||
}) = self.test_definition.metadata.contract_sources()?.remove(contract_instance)
|
}) = self
|
||||||
|
.test_definition
|
||||||
|
.metadata
|
||||||
|
.contract_sources()?
|
||||||
|
.remove(contract_instance)
|
||||||
else {
|
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
|
let Some((code, abi)) = self
|
||||||
@@ -596,7 +625,10 @@ where
|
|||||||
.and_then(|source_file_contracts| source_file_contracts.get(contract_ident.as_ref()))
|
.and_then(|source_file_contracts| source_file_contracts.get(contract_ident.as_ref()))
|
||||||
.cloned()
|
.cloned()
|
||||||
else {
|
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) {
|
let mut code = match alloy::hex::decode(&code) {
|
||||||
@@ -648,9 +680,10 @@ where
|
|||||||
.reporter
|
.reporter
|
||||||
.report_contract_deployed_event(contract_instance.clone(), address)?;
|
.report_contract_deployed_event(contract_instance.clone(), address)?;
|
||||||
|
|
||||||
self.execution_state
|
self.execution_state.deployed_contracts.insert(
|
||||||
.deployed_contracts
|
contract_instance.clone(),
|
||||||
.insert(contract_instance.clone(), (contract_ident, address, abi.clone()));
|
(contract_ident, address, abi.clone()),
|
||||||
|
);
|
||||||
|
|
||||||
Ok((address, abi, receipt))
|
Ok((address, abi, receipt))
|
||||||
}
|
}
|
||||||
@@ -663,7 +696,9 @@ where
|
|||||||
match step_address {
|
match step_address {
|
||||||
StepAddress::Address(address) => Ok(*address),
|
StepAddress::Address(address) => Ok(*address),
|
||||||
StepAddress::ResolvableAddress(resolvable) => {
|
StepAddress::ResolvableAddress(resolvable) => {
|
||||||
let Some(instance) = resolvable.strip_suffix(".address").map(ContractInstance::new)
|
let Some(instance) = resolvable
|
||||||
|
.strip_suffix(".address")
|
||||||
|
.map(ContractInstance::new)
|
||||||
else {
|
else {
|
||||||
bail!("Not an address variable");
|
bail!("Not an address variable");
|
||||||
};
|
};
|
||||||
@@ -701,15 +736,15 @@ where
|
|||||||
transaction: TransactionRequest,
|
transaction: TransactionRequest,
|
||||||
) -> anyhow::Result<TransactionReceipt> {
|
) -> anyhow::Result<TransactionReceipt> {
|
||||||
let node = self.platform_information.node;
|
let node = self.platform_information.node;
|
||||||
let transaction_hash =
|
let transaction_hash = node
|
||||||
node.submit_transaction(transaction).await.context("Failed to submit transaction")?;
|
.submit_transaction(transaction)
|
||||||
|
.await
|
||||||
|
.context("Failed to submit transaction")?;
|
||||||
Span::current().record("transaction_hash", display(transaction_hash));
|
Span::current().record("transaction_hash", display(transaction_hash));
|
||||||
|
|
||||||
info!("Submitted transaction");
|
info!("Submitted transaction");
|
||||||
self.watcher_tx
|
self.watcher_tx
|
||||||
.send(WatcherEvent::SubmittedTransaction {
|
.send(WatcherEvent::SubmittedTransaction { transaction_hash })
|
||||||
transaction_hash,
|
|
||||||
})
|
|
||||||
.context("Failed to send the transaction hash to the watcher")?;
|
.context("Failed to send the transaction hash to the watcher")?;
|
||||||
|
|
||||||
info!("Starting to poll for transaction receipt");
|
info!("Starting to poll for transaction receipt");
|
||||||
|
|||||||
@@ -44,8 +44,12 @@ pub async fn handle_differential_benchmarks(
|
|||||||
info!(len = metadata_files.len(), "Discovered metadata files");
|
info!(len = metadata_files.len(), "Discovered metadata files");
|
||||||
|
|
||||||
// Discover the list of platforms that the tests should run on based on the context.
|
// Discover the list of platforms that the tests should run on based on the context.
|
||||||
let platforms =
|
let platforms = context
|
||||||
context.platforms.iter().copied().map(Into::<&dyn Platform>::into).collect::<Vec<_>>();
|
.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
|
// 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
|
// node pool since it contains all of the code needed to spawn nodes from A to Z and therefore
|
||||||
@@ -92,8 +96,13 @@ pub async fn handle_differential_benchmarks(
|
|||||||
// Creating the objects that will be shared between the various runs. The cached compiler is the
|
// 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.
|
// only one at the current moment of time that's safe to share between runs.
|
||||||
let cached_compiler = CachedCompiler::new(
|
let cached_compiler = CachedCompiler::new(
|
||||||
context.working_directory.as_path().join("compilation_cache"),
|
context
|
||||||
context.compilation_configuration.invalidate_compilation_cache,
|
.working_directory
|
||||||
|
.as_path()
|
||||||
|
.join("compilation_cache"),
|
||||||
|
context
|
||||||
|
.compilation_configuration
|
||||||
|
.invalidate_compilation_cache,
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.map(Arc::new)
|
.map(Arc::new)
|
||||||
@@ -152,7 +161,9 @@ pub async fn handle_differential_benchmarks(
|
|||||||
watcher.run(),
|
watcher.run(),
|
||||||
driver.execute_all().inspect(|_| {
|
driver.execute_all().inspect(|_| {
|
||||||
info!("All transactions submitted - driver completed execution");
|
info!("All transactions submitted - driver completed execution");
|
||||||
watcher_tx.send(WatcherEvent::AllTransactionsSubmitted).unwrap()
|
watcher_tx
|
||||||
|
.send(WatcherEvent::AllTransactionsSubmitted)
|
||||||
|
.unwrap()
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
|
|||||||
@@ -80,13 +80,12 @@ impl Watcher {
|
|||||||
// Subsequent repetition starts are ignored since certain workloads can
|
// Subsequent repetition starts are ignored since certain workloads can
|
||||||
// contain nested repetitions and therefore there's no use in doing any
|
// contain nested repetitions and therefore there's no use in doing any
|
||||||
// action if the repetitions are nested.
|
// action if the repetitions are nested.
|
||||||
WatcherEvent::RepetitionStartEvent {
|
WatcherEvent::RepetitionStartEvent { .. } => {}
|
||||||
..
|
WatcherEvent::SubmittedTransaction { transaction_hash } => {
|
||||||
} => {}
|
watch_for_transaction_hashes
|
||||||
WatcherEvent::SubmittedTransaction {
|
.write()
|
||||||
transaction_hash,
|
.await
|
||||||
} => {
|
.insert(transaction_hash);
|
||||||
watch_for_transaction_hashes.write().await.insert(transaction_hash);
|
|
||||||
}
|
}
|
||||||
WatcherEvent::AllTransactionsSubmitted => {
|
WatcherEvent::AllTransactionsSubmitted => {
|
||||||
*all_transactions_submitted.write().await = true;
|
*all_transactions_submitted.write().await = true;
|
||||||
@@ -152,8 +151,15 @@ impl Watcher {
|
|||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
|
|
||||||
let mut stderr = std::io::stderr().lock();
|
let mut stderr = std::io::stderr().lock();
|
||||||
writeln!(stderr, "Watcher information for {}", self.platform_identifier)?;
|
writeln!(
|
||||||
writeln!(stderr, "block_number,block_timestamp,mined_gas,block_gas_limit,tx_count")?;
|
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 {
|
for block in mined_blocks_information {
|
||||||
writeln!(
|
writeln!(
|
||||||
stderr,
|
stderr,
|
||||||
|
|||||||
@@ -76,9 +76,7 @@ impl<'a> Driver<'a, StepsIterator> {
|
|||||||
.into_iter()
|
.into_iter()
|
||||||
.collect::<BTreeMap<_, _>>();
|
.collect::<BTreeMap<_, _>>();
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self { platform_drivers })
|
||||||
platform_drivers,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn create_platform_driver(
|
async fn create_platform_driver(
|
||||||
@@ -114,7 +112,9 @@ impl<'a> Driver<'a, StepsIterator> {
|
|||||||
pub async fn execute_all(mut self) -> Result<usize> {
|
pub async fn execute_all(mut self) -> Result<usize> {
|
||||||
let platform_drivers = std::mem::take(&mut self.platform_drivers);
|
let platform_drivers = std::mem::take(&mut self.platform_drivers);
|
||||||
let results = futures::future::try_join_all(
|
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
|
.await
|
||||||
.context("Failed to execute all of the steps on the driver")?;
|
.context("Failed to execute all of the steps on the driver")?;
|
||||||
@@ -210,8 +210,12 @@ where
|
|||||||
)
|
)
|
||||||
})
|
})
|
||||||
.context("Failed to get the contract instances from the metadata file")?;
|
.context("Failed to get the contract instances from the metadata file")?;
|
||||||
for library_instance in
|
for library_instance in test_definition
|
||||||
test_definition.metadata.libraries.iter().flatten().flat_map(|(_, map)| map.values())
|
.metadata
|
||||||
|
.libraries
|
||||||
|
.iter()
|
||||||
|
.flatten()
|
||||||
|
.flat_map(|(_, map)| map.values())
|
||||||
{
|
{
|
||||||
let ContractPathAndIdent {
|
let ContractPathAndIdent {
|
||||||
contract_source_path: library_source_path,
|
contract_source_path: library_source_path,
|
||||||
@@ -248,8 +252,11 @@ where
|
|||||||
TransactionRequest::default().from(deployer_address),
|
TransactionRequest::default().from(deployer_address),
|
||||||
code,
|
code,
|
||||||
);
|
);
|
||||||
let receipt =
|
let receipt = platform_information
|
||||||
platform_information.node.execute_transaction(tx).await.inspect_err(|err| {
|
.node
|
||||||
|
.execute_transaction(tx)
|
||||||
|
.await
|
||||||
|
.inspect_err(|err| {
|
||||||
error!(
|
error!(
|
||||||
?err,
|
?err,
|
||||||
%library_instance,
|
%library_instance,
|
||||||
@@ -258,7 +265,9 @@ 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(
|
deployed_libraries.get_or_insert_default().insert(
|
||||||
library_instance.clone(),
|
library_instance.clone(),
|
||||||
@@ -286,7 +295,10 @@ where
|
|||||||
})
|
})
|
||||||
.context("Failed to compile the post-link contracts")?;
|
.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
|
// endregion:Constructors & Initialization
|
||||||
|
|
||||||
@@ -380,7 +392,11 @@ where
|
|||||||
) -> Result<HashMap<ContractInstance, TransactionReceipt>> {
|
) -> Result<HashMap<ContractInstance, TransactionReceipt>> {
|
||||||
let mut instances_we_must_deploy = IndexMap::<ContractInstance, bool>::new();
|
let mut instances_we_must_deploy = IndexMap::<ContractInstance, bool>::new();
|
||||||
for instance in step.find_all_contract_instances().into_iter() {
|
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);
|
instances_we_must_deploy.entry(instance).or_insert(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -392,13 +408,20 @@ where
|
|||||||
let mut receipts = HashMap::new();
|
let mut receipts = HashMap::new();
|
||||||
for (instance, deploy_with_constructor_arguments) in instances_we_must_deploy.into_iter() {
|
for (instance, deploy_with_constructor_arguments) in instances_we_must_deploy.into_iter() {
|
||||||
let calldata = deploy_with_constructor_arguments.then_some(&step.calldata);
|
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 caller = {
|
||||||
let context = self.default_resolution_context();
|
let context = self.default_resolution_context();
|
||||||
let resolver = self.platform_information.node.resolver().await?;
|
let resolver = self.platform_information.node.resolver().await?;
|
||||||
let resolved = step.caller.resolve_address(resolver.as_ref(), context).await?;
|
let resolved = step
|
||||||
self.platform_information.node.resolve_signer_or_default(resolved)
|
.caller
|
||||||
|
.resolve_address(resolver.as_ref(), context)
|
||||||
|
.await?;
|
||||||
|
self.platform_information
|
||||||
|
.node
|
||||||
|
.resolve_signer_or_default(resolved)
|
||||||
};
|
};
|
||||||
if let (_, _, Some(receipt)) = self
|
if let (_, _, Some(receipt)) = self
|
||||||
.get_or_deploy_contract_instance(&instance, caller, calldata, value)
|
.get_or_deploy_contract_instance(&instance, caller, calldata, value)
|
||||||
@@ -438,7 +461,11 @@ where
|
|||||||
|
|
||||||
// Resolve the signer to ensure we use an address that has keys
|
// Resolve the signer to ensure we use an address that has keys
|
||||||
if let Some(from) = tx.from {
|
if let Some(from) = tx.from {
|
||||||
tx.from = Some(self.platform_information.node.resolve_signer_or_default(from));
|
tx.from = Some(
|
||||||
|
self.platform_information
|
||||||
|
.node
|
||||||
|
.resolve_signer_or_default(from),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.platform_information.node.execute_transaction(tx).await
|
self.platform_information.node.execute_transaction(tx).await
|
||||||
@@ -489,13 +516,18 @@ where
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Handling the return data variable assignments.
|
// Handling the return data variable assignments.
|
||||||
for (variable_name, output_word) in assignments
|
for (variable_name, output_word) in assignments.return_data.iter().zip(
|
||||||
.return_data
|
tracing_result
|
||||||
.iter()
|
.output
|
||||||
.zip(tracing_result.output.as_ref().unwrap_or_default().to_vec().chunks(32))
|
.as_ref()
|
||||||
{
|
.unwrap_or_default()
|
||||||
|
.to_vec()
|
||||||
|
.chunks(32),
|
||||||
|
) {
|
||||||
let value = U256::from_be_slice(output_word);
|
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!(
|
tracing::info!(
|
||||||
variable_name,
|
variable_name,
|
||||||
variable_value = hex::encode(value.to_be_bytes::<32>()),
|
variable_value = hex::encode(value.to_be_bytes::<32>()),
|
||||||
@@ -527,10 +559,7 @@ where
|
|||||||
expected: Some(Expected::ExpectedMany(expected)),
|
expected: Some(Expected::ExpectedMany(expected)),
|
||||||
..
|
..
|
||||||
} => expected.clone(),
|
} => expected.clone(),
|
||||||
FunctionCallStep {
|
FunctionCallStep { expected: None, .. } => vec![ExpectedOutput::new().with_success()],
|
||||||
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
|
// This is a bit of a special case and we have to support it separately on it's own. If it's
|
||||||
@@ -546,7 +575,8 @@ where
|
|||||||
|
|
||||||
futures::stream::iter(expectations.into_iter().map(Ok))
|
futures::stream::iter(expectations.into_iter().map(Ok))
|
||||||
.try_for_each_concurrent(None, |expectation| async {
|
.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
|
.await
|
||||||
}
|
}
|
||||||
@@ -647,8 +677,11 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Handling the topics assertion.
|
// Handling the topics assertion.
|
||||||
for (expected, actual) in
|
for (expected, actual) in expected_event
|
||||||
expected_event.topics.as_slice().iter().zip(actual_event.topics())
|
.topics
|
||||||
|
.as_slice()
|
||||||
|
.iter()
|
||||||
|
.zip(actual_event.topics())
|
||||||
{
|
{
|
||||||
let expected = Calldata::new_compound([expected]);
|
let expected = Calldata::new_compound([expected]);
|
||||||
if !expected
|
if !expected
|
||||||
@@ -744,8 +777,11 @@ where
|
|||||||
.resolve_address(resolver.as_ref(), self.default_resolution_context())
|
.resolve_address(resolver.as_ref(), self.default_resolution_context())
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
let storage =
|
let storage = self
|
||||||
self.platform_information.node.latest_state_proof(address, Default::default()).await?;
|
.platform_information
|
||||||
|
.node
|
||||||
|
.latest_state_proof(address, Default::default())
|
||||||
|
.await?;
|
||||||
let is_empty = storage.storage_hash == EMPTY_ROOT_HASH;
|
let is_empty = storage.storage_hash == EMPTY_ROOT_HASH;
|
||||||
|
|
||||||
let expected = step.is_storage_empty;
|
let expected = step.is_storage_empty;
|
||||||
@@ -795,8 +831,9 @@ where
|
|||||||
})
|
})
|
||||||
.map(|driver| driver.execute_all())
|
.map(|driver| driver.execute_all())
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
let res =
|
let res = futures::future::try_join_all(tasks)
|
||||||
futures::future::try_join_all(tasks).await.context("Repetition execution failed")?;
|
.await
|
||||||
|
.context("Repetition execution failed")?;
|
||||||
Ok(res.first().copied().unwrap_or_default())
|
Ok(res.first().copied().unwrap_or_default())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -814,7 +851,9 @@ where
|
|||||||
let account = private_key.address();
|
let account = private_key.address();
|
||||||
let variable = U256::from_be_slice(account.0.as_slice());
|
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)
|
Ok(1)
|
||||||
}
|
}
|
||||||
@@ -837,8 +876,10 @@ where
|
|||||||
calldata: Option<&Calldata>,
|
calldata: Option<&Calldata>,
|
||||||
value: Option<EtherValue>,
|
value: Option<EtherValue>,
|
||||||
) -> Result<(Address, JsonAbi, Option<TransactionReceipt>)> {
|
) -> Result<(Address, JsonAbi, Option<TransactionReceipt>)> {
|
||||||
if let Some((_, address, abi)) =
|
if let Some((_, address, abi)) = self
|
||||||
self.execution_state.deployed_contracts.get(contract_instance)
|
.execution_state
|
||||||
|
.deployed_contracts
|
||||||
|
.get(contract_instance)
|
||||||
{
|
{
|
||||||
info!(
|
info!(
|
||||||
|
|
||||||
@@ -880,9 +921,16 @@ where
|
|||||||
let Some(ContractPathAndIdent {
|
let Some(ContractPathAndIdent {
|
||||||
contract_source_path,
|
contract_source_path,
|
||||||
contract_ident,
|
contract_ident,
|
||||||
}) = self.test_definition.metadata.contract_sources()?.remove(contract_instance)
|
}) = self
|
||||||
|
.test_definition
|
||||||
|
.metadata
|
||||||
|
.contract_sources()?
|
||||||
|
.remove(contract_instance)
|
||||||
else {
|
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
|
let Some((code, abi)) = self
|
||||||
@@ -892,7 +940,10 @@ where
|
|||||||
.and_then(|source_file_contracts| source_file_contracts.get(contract_ident.as_ref()))
|
.and_then(|source_file_contracts| source_file_contracts.get(contract_ident.as_ref()))
|
||||||
.cloned()
|
.cloned()
|
||||||
else {
|
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) {
|
let mut code = match alloy::hex::decode(&code) {
|
||||||
@@ -910,13 +961,17 @@ where
|
|||||||
|
|
||||||
if let Some(calldata) = calldata {
|
if let Some(calldata) = calldata {
|
||||||
let resolver = self.platform_information.node.resolver().await?;
|
let resolver = self.platform_information.node.resolver().await?;
|
||||||
let calldata =
|
let calldata = calldata
|
||||||
calldata.calldata(resolver.as_ref(), self.default_resolution_context()).await?;
|
.calldata(resolver.as_ref(), self.default_resolution_context())
|
||||||
|
.await?;
|
||||||
code.extend(calldata);
|
code.extend(calldata);
|
||||||
}
|
}
|
||||||
|
|
||||||
let tx = {
|
let tx = {
|
||||||
let deployer = self.platform_information.node.resolve_signer_or_default(deployer);
|
let deployer = self
|
||||||
|
.platform_information
|
||||||
|
.node
|
||||||
|
.resolve_signer_or_default(deployer);
|
||||||
let tx = TransactionRequest::default().from(deployer);
|
let tx = TransactionRequest::default().from(deployer);
|
||||||
let tx = match value {
|
let tx = match value {
|
||||||
Some(ref value) => tx.value(value.into_inner()),
|
Some(ref value) => tx.value(value.into_inner()),
|
||||||
@@ -945,9 +1000,10 @@ where
|
|||||||
.reporter
|
.reporter
|
||||||
.report_contract_deployed_event(contract_instance.clone(), address)?;
|
.report_contract_deployed_event(contract_instance.clone(), address)?;
|
||||||
|
|
||||||
self.execution_state
|
self.execution_state.deployed_contracts.insert(
|
||||||
.deployed_contracts
|
contract_instance.clone(),
|
||||||
.insert(contract_instance.clone(), (contract_ident, address, abi.clone()));
|
(contract_ident, address, abi.clone()),
|
||||||
|
);
|
||||||
|
|
||||||
Ok((address, abi, receipt))
|
Ok((address, abi, receipt))
|
||||||
}
|
}
|
||||||
@@ -960,7 +1016,9 @@ where
|
|||||||
match step_address {
|
match step_address {
|
||||||
StepAddress::Address(address) => Ok(*address),
|
StepAddress::Address(address) => Ok(*address),
|
||||||
StepAddress::ResolvableAddress(resolvable) => {
|
StepAddress::ResolvableAddress(resolvable) => {
|
||||||
let Some(instance) = resolvable.strip_suffix(".address").map(ContractInstance::new)
|
let Some(instance) = resolvable
|
||||||
|
.strip_suffix(".address")
|
||||||
|
.map(ContractInstance::new)
|
||||||
else {
|
else {
|
||||||
bail!("Not an address variable");
|
bail!("Not an address variable");
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -37,8 +37,12 @@ pub async fn handle_differential_tests(
|
|||||||
info!(len = metadata_files.len(), "Discovered metadata files");
|
info!(len = metadata_files.len(), "Discovered metadata files");
|
||||||
|
|
||||||
// Discover the list of platforms that the tests should run on based on the context.
|
// Discover the list of platforms that the tests should run on based on the context.
|
||||||
let platforms =
|
let platforms = context
|
||||||
context.platforms.iter().copied().map(Into::<&dyn Platform>::into).collect::<Vec<_>>();
|
.platforms
|
||||||
|
.iter()
|
||||||
|
.copied()
|
||||||
|
.map(Into::<&dyn Platform>::into)
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
// Starting the nodes of the various platforms specified in the context.
|
// Starting the nodes of the various platforms specified in the context.
|
||||||
let platforms_and_nodes = {
|
let platforms_and_nodes = {
|
||||||
@@ -81,8 +85,13 @@ pub async fn handle_differential_tests(
|
|||||||
|
|
||||||
// Creating everything else required for the driver to run.
|
// Creating everything else required for the driver to run.
|
||||||
let cached_compiler = CachedCompiler::new(
|
let cached_compiler = CachedCompiler::new(
|
||||||
context.working_directory.as_path().join("compilation_cache"),
|
context
|
||||||
context.compilation_configuration.invalidate_compilation_cache,
|
.working_directory
|
||||||
|
.as_path()
|
||||||
|
.join("compilation_cache"),
|
||||||
|
context
|
||||||
|
.compilation_configuration
|
||||||
|
.invalidate_compilation_cache,
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.map(Arc::new)
|
.map(Arc::new)
|
||||||
@@ -92,8 +101,11 @@ pub async fn handle_differential_tests(
|
|||||||
)));
|
)));
|
||||||
|
|
||||||
// Creating the driver and executing all of the steps.
|
// Creating the driver and executing all of the steps.
|
||||||
let semaphore =
|
let semaphore = context
|
||||||
context.concurrency_configuration.concurrency_limit().map(Semaphore::new).map(Arc::new);
|
.concurrency_configuration
|
||||||
|
.concurrency_limit()
|
||||||
|
.map(Semaphore::new)
|
||||||
|
.map(Arc::new);
|
||||||
let running_task_list = Arc::new(RwLock::new(BTreeSet::<usize>::new()));
|
let running_task_list = Arc::new(RwLock::new(BTreeSet::<usize>::new()));
|
||||||
let driver_task = futures::future::join_all(test_definitions.iter().enumerate().map(
|
let driver_task = futures::future::join_all(test_definitions.iter().enumerate().map(
|
||||||
|(test_id, test_definition)| {
|
|(test_id, test_definition)| {
|
||||||
@@ -160,14 +172,20 @@ pub async fn handle_differential_tests(
|
|||||||
))
|
))
|
||||||
.inspect(|_| {
|
.inspect(|_| {
|
||||||
info!("Finished executing all test cases");
|
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);
|
let cli_reporting_task = start_cli_reporting_task(reporter);
|
||||||
|
|
||||||
tokio::task::spawn(async move {
|
tokio::task::spawn(async move {
|
||||||
loop {
|
loop {
|
||||||
let remaining_tasks = running_task_list.read().await;
|
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
|
tokio::time::sleep(Duration::from_secs(10)).await
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -209,9 +227,7 @@ async fn start_cli_reporting_task(reporter: Reporter) {
|
|||||||
for (case_idx, case_status) in case_status.into_iter() {
|
for (case_idx, case_status) in case_status.into_iter() {
|
||||||
let _ = write!(buf, "\tCase Index {case_idx:>3}: ");
|
let _ = write!(buf, "\tCase Index {case_idx:>3}: ");
|
||||||
let _ = match case_status {
|
let _ = match case_status {
|
||||||
TestCaseStatus::Succeeded {
|
TestCaseStatus::Succeeded { steps_executed } => {
|
||||||
steps_executed,
|
|
||||||
} => {
|
|
||||||
number_of_successes += 1;
|
number_of_successes += 1;
|
||||||
writeln!(
|
writeln!(
|
||||||
buf,
|
buf,
|
||||||
@@ -219,9 +235,7 @@ async fn start_cli_reporting_task(reporter: Reporter) {
|
|||||||
GREEN, BOLD, BOLD_RESET, steps_executed, COLOR_RESET
|
GREEN, BOLD, BOLD_RESET, steps_executed, COLOR_RESET
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
TestCaseStatus::Failed {
|
TestCaseStatus::Failed { reason } => {
|
||||||
reason,
|
|
||||||
} => {
|
|
||||||
number_of_failures += 1;
|
number_of_failures += 1;
|
||||||
writeln!(
|
writeln!(
|
||||||
buf,
|
buf,
|
||||||
@@ -233,10 +247,7 @@ async fn start_cli_reporting_task(reporter: Reporter) {
|
|||||||
COLOR_RESET,
|
COLOR_RESET,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
TestCaseStatus::Ignored {
|
TestCaseStatus::Ignored { reason, .. } => writeln!(
|
||||||
reason,
|
|
||||||
..
|
|
||||||
} => writeln!(
|
|
||||||
buf,
|
buf,
|
||||||
"{}{}Case Ignored{} - Reason: {}{}",
|
"{}{}Case Ignored{} - Reason: {}{}",
|
||||||
GREY,
|
GREY,
|
||||||
|
|||||||
@@ -225,7 +225,9 @@ async fn compile_contracts(
|
|||||||
.flat_map(|value| value.iter())
|
.flat_map(|value| value.iter())
|
||||||
.map(|(instance, (ident, address, abi))| (instance, ident, address, abi))
|
.map(|(instance, (ident, address, abi))| (instance, ident, address, abi))
|
||||||
.flat_map(|(_, ident, address, _)| {
|
.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)| {
|
.fold(compiler, |compiler, (ident, address, path)| {
|
||||||
compiler.with_library(path, ident.as_str(), *address)
|
compiler.with_library(path, ident.as_str(), *address)
|
||||||
@@ -307,15 +309,19 @@ impl ArtifactsCache {
|
|||||||
pub async fn insert(&self, key: &CacheKey<'_>, value: &CacheValue) -> Result<()> {
|
pub async fn insert(&self, key: &CacheKey<'_>, value: &CacheValue) -> Result<()> {
|
||||||
let key = bson::to_vec(key).context("Failed to serialize cache key (bson)")?;
|
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)")?;
|
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(|| {
|
cacache::write(self.path.as_path(), key.encode_hex(), value)
|
||||||
format!("Failed to write cache entry under {}", self.path.display())
|
.await
|
||||||
})?;
|
.with_context(|| {
|
||||||
|
format!("Failed to write cache entry under {}", self.path.display())
|
||||||
|
})?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get(&self, key: &CacheKey<'_>) -> Option<CacheValue> {
|
pub async fn get(&self, key: &CacheKey<'_>) -> Option<CacheValue> {
|
||||||
let key = bson::to_vec(key).ok()?;
|
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()?;
|
let value = bson::from_slice::<CacheValue>(&value).ok()?;
|
||||||
Some(value)
|
Some(value)
|
||||||
}
|
}
|
||||||
@@ -364,8 +370,6 @@ struct CacheValue {
|
|||||||
|
|
||||||
impl CacheValue {
|
impl CacheValue {
|
||||||
pub fn new(compiler_output: CompilerOutput) -> Self {
|
pub fn new(compiler_output: CompilerOutput) -> Self {
|
||||||
Self {
|
Self { compiler_output }
|
||||||
compiler_output,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,8 +37,10 @@ impl NodePool {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let pre_transactions_tasks =
|
let pre_transactions_tasks = nodes
|
||||||
nodes.iter_mut().map(|node| node.pre_transactions()).collect::<Vec<_>>();
|
.iter_mut()
|
||||||
|
.map(|node| node.pre_transactions())
|
||||||
|
.collect::<Vec<_>>();
|
||||||
futures::future::try_join_all(pre_transactions_tasks)
|
futures::future::try_join_all(pre_transactions_tasks)
|
||||||
.await
|
.await
|
||||||
.context("Failed to run the pre-transactions task")?;
|
.context("Failed to run the pre-transactions task")?;
|
||||||
|
|||||||
@@ -66,68 +66,72 @@ 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
|
// Inform the reporter of each one of the test cases that were discovered which we expect to
|
||||||
// run.
|
// run.
|
||||||
.inspect(|(_, _, _, _, reporter)| {
|
.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
|
// Creating the Test Definition objects from all of the various objects we have and creating
|
||||||
// their required dependencies (e.g., compiler).
|
// their required dependencies (e.g., compiler).
|
||||||
.filter_map(move |(metadata_file, case_idx, case, mode, reporter)| async move {
|
.filter_map(
|
||||||
let mut platforms = BTreeMap::new();
|
move |(metadata_file, case_idx, case, mode, reporter)| async move {
|
||||||
for (platform, node_pool) in platforms_and_nodes.values() {
|
let mut platforms = BTreeMap::new();
|
||||||
let node = node_pool.round_robbin();
|
for (platform, node_pool) in platforms_and_nodes.values() {
|
||||||
let compiler = platform
|
let node = node_pool.round_robbin();
|
||||||
.new_compiler(context.clone(), mode.version.clone().map(Into::into))
|
let compiler = platform
|
||||||
.await
|
.new_compiler(context.clone(), mode.version.clone().map(Into::into))
|
||||||
.inspect_err(|err| {
|
.await
|
||||||
error!(
|
.inspect_err(|err| {
|
||||||
?err,
|
error!(
|
||||||
platform_identifier = %platform.platform_identifier(),
|
?err,
|
||||||
"Failed to instantiate the compiler"
|
platform_identifier = %platform.platform_identifier(),
|
||||||
|
"Failed to instantiate the compiler"
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.ok()?;
|
||||||
|
|
||||||
|
reporter
|
||||||
|
.report_node_assigned_event(
|
||||||
|
node.id(),
|
||||||
|
platform.platform_identifier(),
|
||||||
|
node.connection_string(),
|
||||||
)
|
)
|
||||||
})
|
.expect("Can't fail");
|
||||||
.ok()?;
|
|
||||||
|
|
||||||
reporter
|
let reporter =
|
||||||
.report_node_assigned_event(
|
reporter.execution_specific_reporter(node.id(), platform.platform_identifier());
|
||||||
node.id(),
|
|
||||||
|
platforms.insert(
|
||||||
platform.platform_identifier(),
|
platform.platform_identifier(),
|
||||||
node.connection_string(),
|
TestPlatformInformation {
|
||||||
)
|
platform: *platform,
|
||||||
.expect("Can't fail");
|
node,
|
||||||
|
compiler,
|
||||||
|
reporter,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
let reporter =
|
Some(TestDefinition {
|
||||||
reporter.execution_specific_reporter(node.id(), platform.platform_identifier());
|
/* Metadata file information */
|
||||||
|
metadata: metadata_file,
|
||||||
|
metadata_file_path: metadata_file.metadata_file_path.as_path(),
|
||||||
|
|
||||||
platforms.insert(
|
/* Mode Information */
|
||||||
platform.platform_identifier(),
|
mode: mode.clone(),
|
||||||
TestPlatformInformation {
|
|
||||||
platform: *platform,
|
|
||||||
node,
|
|
||||||
compiler,
|
|
||||||
reporter,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Some(TestDefinition {
|
/* Case Information */
|
||||||
/* Metadata file information */
|
case_idx: CaseIdx::new(case_idx),
|
||||||
metadata: metadata_file,
|
case,
|
||||||
metadata_file_path: metadata_file.metadata_file_path.as_path(),
|
|
||||||
|
|
||||||
/* Mode Information */
|
/* Platform and Node Assignment Information */
|
||||||
mode: mode.clone(),
|
platforms,
|
||||||
|
|
||||||
/* Case Information */
|
/* Reporter */
|
||||||
case_idx: CaseIdx::new(case_idx),
|
reporter,
|
||||||
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 out the test cases which are incompatible or that can't run in the current setup.
|
||||||
.filter_map(move |test| async move {
|
.filter_map(move |test| async move {
|
||||||
match test.check_compatibility() {
|
match test.check_compatibility() {
|
||||||
@@ -270,7 +274,10 @@ impl<'a> TestDefinition<'a> {
|
|||||||
if is_allowed {
|
if is_allowed {
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
Err(("EVM version is incompatible for the platforms specified", error_map))
|
Err((
|
||||||
|
"EVM version is incompatible for the platforms specified",
|
||||||
|
error_map,
|
||||||
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+35
-14
@@ -38,7 +38,11 @@ pub trait Platform {
|
|||||||
|
|
||||||
/// Returns a full identifier for the platform.
|
/// Returns a full identifier for the platform.
|
||||||
fn full_identifier(&self) -> (NodeIdentifier, VmIdentifier, CompilerIdentifier) {
|
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.
|
/// Returns the identifier of the node used.
|
||||||
@@ -180,7 +184,9 @@ impl Platform for KitchensinkPolkavmResolcPlatform {
|
|||||||
context: Context,
|
context: Context,
|
||||||
) -> anyhow::Result<JoinHandle<anyhow::Result<Box<dyn EthereumNode + Send + Sync>>>> {
|
) -> anyhow::Result<JoinHandle<anyhow::Result<Box<dyn EthereumNode + Send + Sync>>>> {
|
||||||
let genesis_configuration = AsRef::<GenesisConfiguration>::as_ref(&context);
|
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();
|
let genesis = genesis_configuration.genesis()?.clone();
|
||||||
Ok(thread::spawn(move || {
|
Ok(thread::spawn(move || {
|
||||||
let node = SubstrateNode::new(
|
let node = SubstrateNode::new(
|
||||||
@@ -230,7 +236,9 @@ impl Platform for KitchensinkRevmSolcPlatform {
|
|||||||
context: Context,
|
context: Context,
|
||||||
) -> anyhow::Result<JoinHandle<anyhow::Result<Box<dyn EthereumNode + Send + Sync>>>> {
|
) -> anyhow::Result<JoinHandle<anyhow::Result<Box<dyn EthereumNode + Send + Sync>>>> {
|
||||||
let genesis_configuration = AsRef::<GenesisConfiguration>::as_ref(&context);
|
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();
|
let genesis = genesis_configuration.genesis()?.clone();
|
||||||
Ok(thread::spawn(move || {
|
Ok(thread::spawn(move || {
|
||||||
let node = SubstrateNode::new(
|
let node = SubstrateNode::new(
|
||||||
@@ -280,8 +288,9 @@ impl Platform for ReviveDevNodePolkavmResolcPlatform {
|
|||||||
context: Context,
|
context: Context,
|
||||||
) -> anyhow::Result<JoinHandle<anyhow::Result<Box<dyn EthereumNode + Send + Sync>>>> {
|
) -> anyhow::Result<JoinHandle<anyhow::Result<Box<dyn EthereumNode + Send + Sync>>>> {
|
||||||
let genesis_configuration = AsRef::<GenesisConfiguration>::as_ref(&context);
|
let genesis_configuration = AsRef::<GenesisConfiguration>::as_ref(&context);
|
||||||
let revive_dev_node_path =
|
let revive_dev_node_path = AsRef::<ReviveDevNodeConfiguration>::as_ref(&context)
|
||||||
AsRef::<ReviveDevNodeConfiguration>::as_ref(&context).path.clone();
|
.path
|
||||||
|
.clone();
|
||||||
let genesis = genesis_configuration.genesis()?.clone();
|
let genesis = genesis_configuration.genesis()?.clone();
|
||||||
Ok(thread::spawn(move || {
|
Ok(thread::spawn(move || {
|
||||||
let node = SubstrateNode::new(
|
let node = SubstrateNode::new(
|
||||||
@@ -331,8 +340,9 @@ impl Platform for ReviveDevNodeRevmSolcPlatform {
|
|||||||
context: Context,
|
context: Context,
|
||||||
) -> anyhow::Result<JoinHandle<anyhow::Result<Box<dyn EthereumNode + Send + Sync>>>> {
|
) -> anyhow::Result<JoinHandle<anyhow::Result<Box<dyn EthereumNode + Send + Sync>>>> {
|
||||||
let genesis_configuration = AsRef::<GenesisConfiguration>::as_ref(&context);
|
let genesis_configuration = AsRef::<GenesisConfiguration>::as_ref(&context);
|
||||||
let revive_dev_node_path =
|
let revive_dev_node_path = AsRef::<ReviveDevNodeConfiguration>::as_ref(&context)
|
||||||
AsRef::<ReviveDevNodeConfiguration>::as_ref(&context).path.clone();
|
.path
|
||||||
|
.clone();
|
||||||
let genesis = genesis_configuration.genesis()?.clone();
|
let genesis = genesis_configuration.genesis()?.clone();
|
||||||
Ok(thread::spawn(move || {
|
Ok(thread::spawn(move || {
|
||||||
let node = SubstrateNode::new(
|
let node = SubstrateNode::new(
|
||||||
@@ -382,8 +392,9 @@ impl Platform for ZombienetPolkavmResolcPlatform {
|
|||||||
context: Context,
|
context: Context,
|
||||||
) -> anyhow::Result<JoinHandle<anyhow::Result<Box<dyn EthereumNode + Send + Sync>>>> {
|
) -> anyhow::Result<JoinHandle<anyhow::Result<Box<dyn EthereumNode + Send + Sync>>>> {
|
||||||
let genesis_configuration = AsRef::<GenesisConfiguration>::as_ref(&context);
|
let genesis_configuration = AsRef::<GenesisConfiguration>::as_ref(&context);
|
||||||
let polkadot_parachain_path =
|
let polkadot_parachain_path = AsRef::<PolkadotParachainConfiguration>::as_ref(&context)
|
||||||
AsRef::<PolkadotParachainConfiguration>::as_ref(&context).path.clone();
|
.path
|
||||||
|
.clone();
|
||||||
let genesis = genesis_configuration.genesis()?.clone();
|
let genesis = genesis_configuration.genesis()?.clone();
|
||||||
Ok(thread::spawn(move || {
|
Ok(thread::spawn(move || {
|
||||||
let node = ZombieNode::new(polkadot_parachain_path, context);
|
let node = ZombieNode::new(polkadot_parachain_path, context);
|
||||||
@@ -429,8 +440,9 @@ impl Platform for ZombienetRevmSolcPlatform {
|
|||||||
context: Context,
|
context: Context,
|
||||||
) -> anyhow::Result<JoinHandle<anyhow::Result<Box<dyn EthereumNode + Send + Sync>>>> {
|
) -> anyhow::Result<JoinHandle<anyhow::Result<Box<dyn EthereumNode + Send + Sync>>>> {
|
||||||
let genesis_configuration = AsRef::<GenesisConfiguration>::as_ref(&context);
|
let genesis_configuration = AsRef::<GenesisConfiguration>::as_ref(&context);
|
||||||
let polkadot_parachain_path =
|
let polkadot_parachain_path = AsRef::<PolkadotParachainConfiguration>::as_ref(&context)
|
||||||
AsRef::<PolkadotParachainConfiguration>::as_ref(&context).path.clone();
|
.path
|
||||||
|
.clone();
|
||||||
let genesis = genesis_configuration.genesis()?.clone();
|
let genesis = genesis_configuration.genesis()?.clone();
|
||||||
Ok(thread::spawn(move || {
|
Ok(thread::spawn(move || {
|
||||||
let node = ZombieNode::new(polkadot_parachain_path, context);
|
let node = ZombieNode::new(polkadot_parachain_path, context);
|
||||||
@@ -509,8 +521,17 @@ fn spawn_node<T: Node + EthereumNode + Send + Sync>(
|
|||||||
mut node: T,
|
mut node: T,
|
||||||
genesis: Genesis,
|
genesis: Genesis,
|
||||||
) -> anyhow::Result<T> {
|
) -> anyhow::Result<T> {
|
||||||
info!(id = node.id(), connection_string = node.connection_string(), "Spawning node");
|
info!(
|
||||||
node.spawn(genesis).context("Failed to spawn node process")?;
|
id = node.id(),
|
||||||
info!(id = node.id(), connection_string = node.connection_string(), "Spawned node");
|
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)
|
Ok(node)
|
||||||
}
|
}
|
||||||
|
|||||||
+25
-19
@@ -54,33 +54,39 @@ pub struct Case {
|
|||||||
impl Case {
|
impl Case {
|
||||||
pub fn steps_iterator(&self) -> impl Iterator<Item = Step> {
|
pub fn steps_iterator(&self) -> impl Iterator<Item = Step> {
|
||||||
let steps_len = self.steps.len();
|
let steps_len = self.steps.len();
|
||||||
self.steps.clone().into_iter().enumerate().map(move |(idx, mut step)| {
|
self.steps
|
||||||
let Step::FunctionCall(ref mut input) = step else {
|
.clone()
|
||||||
return step;
|
.into_iter()
|
||||||
};
|
.enumerate()
|
||||||
|
.map(move |(idx, mut step)| {
|
||||||
|
let Step::FunctionCall(ref mut input) = step else {
|
||||||
|
return step;
|
||||||
|
};
|
||||||
|
|
||||||
if idx + 1 == steps_len {
|
if idx + 1 == steps_len {
|
||||||
if input.expected.is_none() {
|
if input.expected.is_none() {
|
||||||
input.expected = self.expected.clone();
|
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
|
||||||
}
|
}
|
||||||
|
})
|
||||||
// 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(
|
pub fn steps_iterator_for_benchmarks(
|
||||||
&self,
|
&self,
|
||||||
default_repeat_count: usize,
|
default_repeat_count: usize,
|
||||||
) -> Box<dyn Iterator<Item = Step> + '_> {
|
) -> Box<dyn Iterator<Item = Step> + '_> {
|
||||||
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 {
|
if contains_repeat {
|
||||||
Box::new(self.steps_iterator()) as Box<_>
|
Box::new(self.steps_iterator()) as Box<_>
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
+22
-40
@@ -13,14 +13,8 @@ use anyhow::Context as _;
|
|||||||
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
|
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
|
||||||
#[serde(untagged)]
|
#[serde(untagged)]
|
||||||
pub enum Corpus {
|
pub enum Corpus {
|
||||||
SinglePath {
|
SinglePath { name: String, path: PathBuf },
|
||||||
name: String,
|
MultiplePaths { name: String, paths: Vec<PathBuf> },
|
||||||
path: PathBuf,
|
|
||||||
},
|
|
||||||
MultiplePaths {
|
|
||||||
name: String,
|
|
||||||
paths: Vec<PathBuf>,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Corpus {
|
impl Corpus {
|
||||||
@@ -92,58 +86,46 @@ impl Corpus {
|
|||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
tests.sort_by(|a, b| a.metadata_file_path.cmp(&b.metadata_file_path));
|
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);
|
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
|
tests
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn name(&self) -> &str {
|
pub fn name(&self) -> &str {
|
||||||
match self {
|
match self {
|
||||||
Corpus::SinglePath {
|
Corpus::SinglePath { name, .. } | Corpus::MultiplePaths { name, .. } => name.as_str(),
|
||||||
name,
|
|
||||||
..
|
|
||||||
}
|
|
||||||
| Corpus::MultiplePaths {
|
|
||||||
name,
|
|
||||||
..
|
|
||||||
} => name.as_str(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn paths_iter(&self) -> impl Iterator<Item = &Path> {
|
pub fn paths_iter(&self) -> impl Iterator<Item = &Path> {
|
||||||
match self {
|
match self {
|
||||||
Corpus::SinglePath {
|
Corpus::SinglePath { path, .. } => {
|
||||||
path,
|
Box::new(std::iter::once(path.as_path())) as Box<dyn Iterator<Item = _>>
|
||||||
..
|
}
|
||||||
} => Box::new(std::iter::once(path.as_path())) as Box<dyn Iterator<Item = _>>,
|
Corpus::MultiplePaths { paths, .. } => {
|
||||||
Corpus::MultiplePaths {
|
Box::new(paths.iter().map(|path| path.as_path())) as Box<dyn Iterator<Item = _>>
|
||||||
paths,
|
}
|
||||||
..
|
|
||||||
} => Box::new(paths.iter().map(|path| path.as_path())) as Box<dyn Iterator<Item = _>>,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn paths_iter_mut(&mut self) -> impl Iterator<Item = &mut PathBuf> {
|
pub fn paths_iter_mut(&mut self) -> impl Iterator<Item = &mut PathBuf> {
|
||||||
match self {
|
match self {
|
||||||
Corpus::SinglePath {
|
Corpus::SinglePath { path, .. } => {
|
||||||
path,
|
Box::new(std::iter::once(path)) as Box<dyn Iterator<Item = _>>
|
||||||
..
|
}
|
||||||
} => Box::new(std::iter::once(path)) as Box<dyn Iterator<Item = _>>,
|
Corpus::MultiplePaths { paths, .. } => {
|
||||||
Corpus::MultiplePaths {
|
Box::new(paths.iter_mut()) as Box<dyn Iterator<Item = _>>
|
||||||
paths,
|
}
|
||||||
..
|
|
||||||
} => Box::new(paths.iter_mut()) as Box<dyn Iterator<Item = _>>,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn path_count(&self) -> usize {
|
pub fn path_count(&self) -> usize {
|
||||||
match self {
|
match self {
|
||||||
Corpus::SinglePath {
|
Corpus::SinglePath { .. } => 1,
|
||||||
..
|
Corpus::MultiplePaths { paths, .. } => paths.len(),
|
||||||
} => 1,
|
|
||||||
Corpus::MultiplePaths {
|
|
||||||
paths,
|
|
||||||
..
|
|
||||||
} => paths.len(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,7 +44,9 @@ impl MetadataFile {
|
|||||||
if self.corpus_file_path.is_file() {
|
if self.corpus_file_path.is_file() {
|
||||||
&self.corpus_file_path
|
&self.corpus_file_path
|
||||||
} else {
|
} else {
|
||||||
self.metadata_file_path.strip_prefix(&self.corpus_file_path).unwrap()
|
self.metadata_file_path
|
||||||
|
.strip_prefix(&self.corpus_file_path)
|
||||||
|
.unwrap()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -165,8 +167,10 @@ impl Metadata {
|
|||||||
) in contracts
|
) in contracts
|
||||||
{
|
{
|
||||||
let alias = alias.clone();
|
let alias = alias.clone();
|
||||||
let absolute_path =
|
let absolute_path = directory
|
||||||
directory.join(contract_source_path).canonicalize().map_err(|error| {
|
.join(contract_source_path)
|
||||||
|
.canonicalize()
|
||||||
|
.map_err(|error| {
|
||||||
anyhow::anyhow!(
|
anyhow::anyhow!(
|
||||||
"Failed to canonicalize contract source path '{}': {error}",
|
"Failed to canonicalize contract source path '{}': {error}",
|
||||||
directory.join(contract_source_path).display()
|
directory.join(contract_source_path).display()
|
||||||
@@ -331,7 +335,12 @@ pub struct ContractPathAndIdent {
|
|||||||
|
|
||||||
impl Display for ContractPathAndIdent {
|
impl Display for ContractPathAndIdent {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
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()
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -587,7 +596,10 @@ mod test {
|
|||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
let identifier = identifier.expect("Failed to parse");
|
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());
|
assert_eq!(identifier.contract_ident, "ERC20".to_owned().into());
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
|
|||||||
+12
-11
@@ -93,11 +93,7 @@ impl Display for ParsedMode {
|
|||||||
if let Some(pipeline) = self.pipeline {
|
if let Some(pipeline) = self.pipeline {
|
||||||
pipeline.fmt(f)?;
|
pipeline.fmt(f)?;
|
||||||
if let Some(optimize_flag) = self.optimize_flag {
|
if let Some(optimize_flag) = self.optimize_flag {
|
||||||
f.write_str(if optimize_flag {
|
f.write_str(if optimize_flag { "+" } else { "-" })?;
|
||||||
"+"
|
|
||||||
} else {
|
|
||||||
"-"
|
|
||||||
})?;
|
|
||||||
}
|
}
|
||||||
has_written = true;
|
has_written = true;
|
||||||
}
|
}
|
||||||
@@ -161,11 +157,13 @@ impl ParsedMode {
|
|||||||
);
|
);
|
||||||
|
|
||||||
pipeline_iter.flat_map(move |pipeline| {
|
pipeline_iter.flat_map(move |pipeline| {
|
||||||
optimize_settings_iter.clone().map(move |optimize_setting| Mode {
|
optimize_settings_iter
|
||||||
pipeline,
|
.clone()
|
||||||
optimize_setting,
|
.map(move |optimize_setting| Mode {
|
||||||
version: self.version.clone(),
|
pipeline,
|
||||||
})
|
optimize_setting,
|
||||||
|
version: self.version.clone(),
|
||||||
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -237,7 +235,10 @@ mod tests {
|
|||||||
("Y+", vec!["Y M3"]),
|
("Y+", vec!["Y M3"]),
|
||||||
("Y-", vec!["Y M0"]),
|
("Y-", vec!["Y M0"]),
|
||||||
("Y <=0.8", vec!["Y M0 <=0.8", "Y M3 <=0.8"]),
|
("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 {
|
for (actual, expected) in strings {
|
||||||
|
|||||||
+102
-23
@@ -78,7 +78,12 @@ impl StepPath {
|
|||||||
|
|
||||||
impl Display for StepPath {
|
impl Display for StepPath {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
self.0.iter().map(|idx| idx.to_string()).collect::<Vec<_>>().join(".").fmt(f)
|
self.0
|
||||||
|
.iter()
|
||||||
|
.map(|idx| idx.to_string())
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.join(".")
|
||||||
|
.fmt(f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -86,7 +91,10 @@ impl FromStr for StepPath {
|
|||||||
type Err = anyhow::Error;
|
type Err = anyhow::Error;
|
||||||
|
|
||||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
s.split(".").map(StepIdx::from_str).collect::<anyhow::Result<Vec<_>>>().map(Self)
|
s.split(".")
|
||||||
|
.map(StepIdx::from_str)
|
||||||
|
.collect::<anyhow::Result<Vec<_>>>()
|
||||||
|
.map(Self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -448,7 +456,9 @@ impl StepAddress {
|
|||||||
|
|
||||||
impl FunctionCallStep {
|
impl FunctionCallStep {
|
||||||
pub const fn default_caller_address() -> Address {
|
pub const fn default_caller_address() -> Address {
|
||||||
Address(FixedBytes(alloy::hex!("0x90F8bf6A479f320ead074411a4B0e7944Ea8c9C1")))
|
Address(FixedBytes(alloy::hex!(
|
||||||
|
"0x90F8bf6A479f320ead074411a4B0e7944Ea8c9C1"
|
||||||
|
)))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const fn default_caller() -> StepAddress {
|
pub const fn default_caller() -> StepAddress {
|
||||||
@@ -538,9 +548,11 @@ impl FunctionCallStep {
|
|||||||
.await
|
.await
|
||||||
.context("Failed to encode input bytes for transaction request")?;
|
.context("Failed to encode input bytes for transaction request")?;
|
||||||
let caller = self.caller.resolve_address(resolver, context).await?;
|
let caller = self.caller.resolve_address(resolver, context).await?;
|
||||||
let transaction_request = TransactionRequest::default()
|
let transaction_request = TransactionRequest::default().from(caller).value(
|
||||||
.from(caller)
|
self.value
|
||||||
.value(self.value.map(|value| value.into_inner()).unwrap_or_default());
|
.map(|value| value.into_inner())
|
||||||
|
.unwrap_or_default(),
|
||||||
|
);
|
||||||
match self.method {
|
match self.method {
|
||||||
Method::Deployer => Ok(transaction_request.with_deploy_code(input_data)),
|
Method::Deployer => Ok(transaction_request.with_deploy_code(input_data)),
|
||||||
_ => Ok(transaction_request
|
_ => Ok(transaction_request
|
||||||
@@ -596,7 +608,11 @@ impl Calldata {
|
|||||||
|
|
||||||
pub fn new_compound(items: impl IntoIterator<Item = impl AsRef<str>>) -> Self {
|
pub fn new_compound(items: impl IntoIterator<Item = impl AsRef<str>>) -> Self {
|
||||||
Self::Compound(
|
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(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -618,7 +634,8 @@ impl Calldata {
|
|||||||
context: ResolutionContext<'_>,
|
context: ResolutionContext<'_>,
|
||||||
) -> anyhow::Result<Vec<u8>> {
|
) -> anyhow::Result<Vec<u8>> {
|
||||||
let mut buffer = Vec::<u8>::with_capacity(self.size_requirement());
|
let mut buffer = Vec::<u8>::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)
|
Ok(buffer)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -709,7 +726,10 @@ impl CalldataItem {
|
|||||||
) -> anyhow::Result<U256> {
|
) -> anyhow::Result<U256> {
|
||||||
let mut stack = Vec::<CalldataToken<U256>>::new();
|
let mut stack = Vec::<CalldataToken<U256>>::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 token = token.await?;
|
||||||
let new_token = match token {
|
let new_token = match token {
|
||||||
CalldataToken::Item(_) => token,
|
CalldataToken::Item(_) => token,
|
||||||
@@ -750,7 +770,9 @@ impl CalldataItem {
|
|||||||
// Empty stack means that we got an empty compound calldata which we resolve to zero.
|
// Empty stack means that we got an empty compound calldata which we resolve to zero.
|
||||||
[] => Ok(U256::ZERO),
|
[] => Ok(U256::ZERO),
|
||||||
[CalldataToken::Item(item)] => Ok(*item),
|
[CalldataToken::Item(item)] => Ok(*item),
|
||||||
_ => Err(anyhow::anyhow!("Invalid calldata arithmetic operation - Invalid stack")),
|
_ => Err(anyhow::anyhow!(
|
||||||
|
"Invalid calldata arithmetic operation - Invalid stack"
|
||||||
|
)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -894,7 +916,10 @@ impl<T: AsRef<str>> CalldataToken<T> {
|
|||||||
.await
|
.await
|
||||||
.map(U256::from)
|
.map(U256::from)
|
||||||
} else if let Some(variable_name) = item.strip_prefix(Self::VARIABLE_PREFIX) {
|
} 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 {
|
} else {
|
||||||
U256::from_str_radix(item, 10)
|
U256::from_str_radix(item, 10)
|
||||||
.map_err(|error| anyhow::anyhow!("Invalid decimal literal: {}", error))
|
.map_err(|error| anyhow::anyhow!("Invalid decimal literal: {}", error))
|
||||||
@@ -1024,7 +1049,13 @@ mod tests {
|
|||||||
"#;
|
"#;
|
||||||
|
|
||||||
let parsed_abi: JsonAbi = serde_json::from_str(raw_metadata).unwrap();
|
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 {
|
let input = FunctionCallStep {
|
||||||
instance: ContractInstance::new("Contract"),
|
instance: ContractInstance::new("Contract"),
|
||||||
@@ -1062,7 +1093,13 @@ mod tests {
|
|||||||
]"#;
|
]"#;
|
||||||
|
|
||||||
let parsed_abi: JsonAbi = serde_json::from_str(raw_abi).unwrap();
|
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 {
|
let input: FunctionCallStep = FunctionCallStep {
|
||||||
instance: "Contract".to_owned().into(),
|
instance: "Contract".to_owned().into(),
|
||||||
@@ -1084,7 +1121,10 @@ mod tests {
|
|||||||
|
|
||||||
type T = (alloy::primitives::Address,);
|
type T = (alloy::primitives::Address,);
|
||||||
let decoded: T = T::abi_decode(&encoded.0[4..]).unwrap();
|
let decoded: T = T::abi_decode(&encoded.0[4..]).unwrap();
|
||||||
assert_eq!(decoded.0, address!("0x1000000000000000000000000000000000000001"));
|
assert_eq!(
|
||||||
|
decoded.0,
|
||||||
|
address!("0x1000000000000000000000000000000000000001")
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -1100,7 +1140,13 @@ mod tests {
|
|||||||
]"#;
|
]"#;
|
||||||
|
|
||||||
let parsed_abi: JsonAbi = serde_json::from_str(raw_abi).unwrap();
|
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 {
|
let input: FunctionCallStep = FunctionCallStep {
|
||||||
instance: ContractInstance::new("Contract"),
|
instance: ContractInstance::new("Contract"),
|
||||||
@@ -1122,7 +1168,10 @@ mod tests {
|
|||||||
|
|
||||||
type T = (alloy::primitives::Address,);
|
type T = (alloy::primitives::Address,);
|
||||||
let decoded: T = T::abi_decode(&encoded.0[4..]).unwrap();
|
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(
|
async fn resolve_calldata_item(
|
||||||
@@ -1159,7 +1208,12 @@ mod tests {
|
|||||||
let resolved = resolved.expect("Failed to resolve argument");
|
let resolved = resolved.expect("Failed to resolve argument");
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
resolved,
|
resolved,
|
||||||
U256::from(MockResolver.block_gas_limit(Default::default()).await.unwrap())
|
U256::from(
|
||||||
|
MockResolver
|
||||||
|
.block_gas_limit(Default::default())
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1176,7 +1230,11 @@ mod tests {
|
|||||||
assert_eq!(
|
assert_eq!(
|
||||||
resolved,
|
resolved,
|
||||||
U256::from_be_slice(
|
U256::from_be_slice(
|
||||||
MockResolver.block_coinbase(Default::default()).await.unwrap().as_ref()
|
MockResolver
|
||||||
|
.block_coinbase(Default::default())
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
.as_ref()
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -1191,7 +1249,13 @@ mod tests {
|
|||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
let resolved = resolved.expect("Failed to resolve argument");
|
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]
|
#[tokio::test]
|
||||||
@@ -1206,7 +1270,11 @@ mod tests {
|
|||||||
let resolved = resolved.expect("Failed to resolve argument");
|
let resolved = resolved.expect("Failed to resolve argument");
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
resolved,
|
resolved,
|
||||||
MockResolver.block_base_fee(Default::default()).await.map(U256::from).unwrap()
|
MockResolver
|
||||||
|
.block_base_fee(Default::default())
|
||||||
|
.await
|
||||||
|
.map(U256::from)
|
||||||
|
.unwrap()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1236,7 +1304,10 @@ mod tests {
|
|||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
let resolved = resolved.expect("Failed to resolve argument");
|
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]
|
#[tokio::test]
|
||||||
@@ -1251,7 +1322,12 @@ mod tests {
|
|||||||
let resolved = resolved.expect("Failed to resolve argument");
|
let resolved = resolved.expect("Failed to resolve argument");
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
resolved,
|
resolved,
|
||||||
U256::from(MockResolver.block_timestamp(Default::default()).await.unwrap())
|
U256::from(
|
||||||
|
MockResolver
|
||||||
|
.block_timestamp(Default::default())
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1329,7 +1405,10 @@ mod tests {
|
|||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
let resolved = resolved.expect("Failed to resolve argument");
|
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]
|
#[tokio::test]
|
||||||
|
|||||||
@@ -149,7 +149,8 @@ impl<'a> ResolutionContext<'a> {
|
|||||||
&self,
|
&self,
|
||||||
instance: &ContractInstance,
|
instance: &ContractInstance,
|
||||||
) -> Option<&(ContractIdent, Address, JsonAbi)> {
|
) -> 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> {
|
pub fn deployed_contract_address(&self, instance: &ContractInstance) -> Option<&Address> {
|
||||||
@@ -161,7 +162,8 @@ impl<'a> ResolutionContext<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn variable(&self, name: impl AsRef<str>) -> Option<&U256> {
|
pub fn variable(&self, name: impl AsRef<str>) -> 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> {
|
pub fn tip_block_number(&self) -> Option<&'a BlockNumber> {
|
||||||
|
|||||||
@@ -129,7 +129,10 @@ async fn run(args: MlTestRunnerArgs) -> anyhow::Result<()> {
|
|||||||
println!("test {} ... {RED}FAILED{COLOUR_RESET}", file_display);
|
println!("test {} ... {RED}FAILED{COLOUR_RESET}", file_display);
|
||||||
println!(" Error loading metadata: {}", e);
|
println!(" Error loading metadata: {}", e);
|
||||||
failed_files += 1;
|
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 {
|
if args.bail {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -229,7 +232,10 @@ fn discover_test_files(path: &Path) -> anyhow::Result<Vec<PathBuf>> {
|
|||||||
files.push(metadata.metadata_file_path);
|
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() {
|
} else if path.is_dir() {
|
||||||
// Walk directory recursively for .sol files
|
// Walk directory recursively for .sol files
|
||||||
@@ -286,8 +292,9 @@ async fn execute_test_file(
|
|||||||
|
|
||||||
let node: &'static dyn revive_dt_node_interaction::EthereumNode = if args.start_platform {
|
let node: &'static dyn revive_dt_node_interaction::EthereumNode = if args.start_platform {
|
||||||
info!("Starting blockchain node...");
|
info!("Starting blockchain node...");
|
||||||
let node_handle =
|
let node_handle = platform
|
||||||
platform.new_node(context.clone()).context("Failed to spawn node thread")?;
|
.new_node(context.clone())
|
||||||
|
.context("Failed to spawn node thread")?;
|
||||||
|
|
||||||
info!("Waiting for node to start...");
|
info!("Waiting for node to start...");
|
||||||
let node = node_handle
|
let node = node_handle
|
||||||
@@ -295,12 +302,18 @@ async fn execute_test_file(
|
|||||||
.map_err(|e| anyhow::anyhow!("Node thread panicked: {:?}", e))?
|
.map_err(|e| anyhow::anyhow!("Node thread panicked: {:?}", e))?
|
||||||
.context("Failed to start node")?;
|
.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
|
// Run pre-transactions on the node
|
||||||
let node = Box::leak(node); // Leak to get 'static lifetime for simplicity
|
let node = Box::leak(node); // Leak to get 'static lifetime for simplicity
|
||||||
info!("Running pre-transactions...");
|
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");
|
info!("Pre-transactions completed");
|
||||||
|
|
||||||
node
|
node
|
||||||
@@ -325,8 +338,9 @@ async fn execute_test_file(
|
|||||||
.context("Failed to create cached compiler")?;
|
.context("Failed to create cached compiler")?;
|
||||||
|
|
||||||
// Create a private key allocator
|
// Create a private key allocator
|
||||||
let private_key_allocator =
|
let private_key_allocator = Arc::new(Mutex::new(PrivateKeyAllocator::new(
|
||||||
Arc::new(Mutex::new(PrivateKeyAllocator::new(alloy::primitives::U256::from(100))));
|
alloy::primitives::U256::from(100),
|
||||||
|
)));
|
||||||
|
|
||||||
// Create reporter infrastructure (minimal, just for the Driver API)
|
// Create reporter infrastructure (minimal, just for the Driver API)
|
||||||
// Note: We need to keep the report_task alive, otherwise the reporter channel closes
|
// Note: We need to keep the report_task alive, otherwise the reporter channel closes
|
||||||
@@ -336,7 +350,10 @@ async fn execute_test_file(
|
|||||||
// Spawn the report task in the background to keep the channel open
|
// Spawn the report task in the background to keep the channel open
|
||||||
tokio::spawn(report_task);
|
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
|
// Build all test definitions upfront
|
||||||
let mut test_definitions = Vec::new();
|
let mut test_definitions = Vec::new();
|
||||||
for (case_idx, case) in metadata_file.cases.iter().enumerate() {
|
for (case_idx, case) in metadata_file.cases.iter().enumerate() {
|
||||||
@@ -385,17 +402,20 @@ async fn execute_test_file(
|
|||||||
test_definition.case.steps.len(),
|
test_definition.case.steps.len(),
|
||||||
test_definition.case_idx
|
test_definition.case_idx
|
||||||
);
|
);
|
||||||
let steps_executed = driver
|
let steps_executed = driver.execute_all().await.context(format!(
|
||||||
.execute_all()
|
"Failed to execute case {}",
|
||||||
.await
|
test_definition.case_idx
|
||||||
.context(format!("Failed to execute case {}", test_definition.case_idx))?;
|
))?;
|
||||||
info!(
|
info!(
|
||||||
"✓ Case {} completed successfully, executed {} step(s)",
|
"✓ Case {} completed successfully, executed {} step(s)",
|
||||||
test_definition.case_idx, steps_executed
|
test_definition.case_idx, steps_executed
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
info!("─────────────────────────────────────────────────────────────────");
|
info!("─────────────────────────────────────────────────────────────────");
|
||||||
info!("All {} test case(s) executed successfully", test_definitions.len());
|
info!(
|
||||||
|
"All {} test case(s) executed successfully",
|
||||||
|
test_definitions.len()
|
||||||
|
);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,7 +33,10 @@ impl Process {
|
|||||||
let log_file_prefix = log_file_prefix.into();
|
let log_file_prefix = log_file_prefix.into();
|
||||||
|
|
||||||
let (stdout_file_name, stderr_file_name) = match log_file_prefix {
|
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()),
|
None => ("stdout.log".to_string(), "stderr.log".to_string()),
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -54,16 +57,20 @@ impl Process {
|
|||||||
.context("Failed to open the stderr logs file")?;
|
.context("Failed to open the stderr logs file")?;
|
||||||
|
|
||||||
let mut command = {
|
let mut command = {
|
||||||
let stdout_logs_file =
|
let stdout_logs_file = stdout_logs_file
|
||||||
stdout_logs_file.try_clone().context("Failed to clone the stdout logs file")?;
|
.try_clone()
|
||||||
let stderr_logs_file =
|
.context("Failed to clone the stdout logs file")?;
|
||||||
stderr_logs_file.try_clone().context("Failed to clone the stderr 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());
|
let mut command = Command::new(binary_path.as_ref());
|
||||||
command_building_callback(&mut command, stdout_logs_file, stderr_logs_file);
|
command_building_callback(&mut command, stdout_logs_file, stderr_logs_file);
|
||||||
command
|
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 {
|
match process_readiness_wait_behavior {
|
||||||
ProcessReadinessWaitBehavior::NoStartupWait => {}
|
ProcessReadinessWaitBehavior::NoStartupWait => {}
|
||||||
@@ -121,7 +128,11 @@ impl Process {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
ProcessReadinessWaitBehavior::WaitForCommandToExit => {
|
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");
|
anyhow::bail!("Failed to spawn command");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -138,8 +149,12 @@ impl Process {
|
|||||||
impl Drop for Process {
|
impl Drop for Process {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
self.child.kill().expect("Failed to kill the process");
|
self.child.kill().expect("Failed to kill the process");
|
||||||
self.stdout_logs_file.flush().expect("Failed to flush the stdout logs file");
|
self.stdout_logs_file
|
||||||
self.stderr_logs_file.flush().expect("Failed to flush the stderr logs file");
|
.flush()
|
||||||
|
.expect("Failed to flush the stdout logs file");
|
||||||
|
self.stderr_logs_file
|
||||||
|
.flush()
|
||||||
|
.expect("Failed to flush the stderr logs file");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -108,7 +108,9 @@ impl GethNode {
|
|||||||
let wallet_configuration = AsRef::<WalletConfiguration>::as_ref(&context);
|
let wallet_configuration = AsRef::<WalletConfiguration>::as_ref(&context);
|
||||||
let geth_configuration = AsRef::<GethConfiguration>::as_ref(&context);
|
let geth_configuration = AsRef::<GethConfiguration>::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 id = NODE_COUNT.fetch_add(1, Ordering::SeqCst);
|
||||||
let base_directory = geth_directory.join(id.to_string());
|
let base_directory = geth_directory.join(id.to_string());
|
||||||
|
|
||||||
@@ -196,7 +198,11 @@ impl GethNode {
|
|||||||
.read_to_string(&mut stderr)
|
.read_to_string(&mut stderr)
|
||||||
.context("Failed to read geth --init 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);
|
anyhow::bail!("failed to initialize geth node #{:?}: {stderr}", &self.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -256,7 +262,8 @@ impl GethNode {
|
|||||||
Ok(process) => self.handle = Some(process),
|
Ok(process) => self.handle = Some(process),
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
error!(?err, "Failed to start geth, shutting down gracefully");
|
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);
|
return Err(err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -401,7 +408,10 @@ impl EthereumNode for GethNode {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
.instrument(tracing::info_span!("Awaiting transaction receipt", ?transaction_hash))
|
.instrument(tracing::info_span!(
|
||||||
|
"Awaiting transaction receipt",
|
||||||
|
?transaction_hash
|
||||||
|
))
|
||||||
.await
|
.await
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -413,8 +423,10 @@ impl EthereumNode for GethNode {
|
|||||||
trace_options: GethDebugTracingOptions,
|
trace_options: GethDebugTracingOptions,
|
||||||
) -> Pin<Box<dyn Future<Output = anyhow::Result<GethTrace>> + '_>> {
|
) -> Pin<Box<dyn Future<Output = anyhow::Result<GethTrace>> + '_>> {
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
let provider =
|
let provider = self
|
||||||
self.provider().await.context("Failed to create provider for tracing")?;
|
.provider()
|
||||||
|
.await
|
||||||
|
.context("Failed to create provider for tracing")?;
|
||||||
poll(
|
poll(
|
||||||
Self::TRACE_POLLING_DURATION,
|
Self::TRACE_POLLING_DURATION,
|
||||||
PollingWaitBehavior::Constant(Duration::from_millis(200)),
|
PollingWaitBehavior::Constant(Duration::from_millis(200)),
|
||||||
@@ -422,7 +434,10 @@ impl EthereumNode for GethNode {
|
|||||||
let provider = provider.clone();
|
let provider = provider.clone();
|
||||||
let trace_options = trace_options.clone();
|
let trace_options = trace_options.clone();
|
||||||
async move {
|
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)),
|
Ok(trace) => Ok(ControlFlow::Break(trace)),
|
||||||
Err(error) => {
|
Err(error) => {
|
||||||
let error_string = error.to_string();
|
let error_string = error.to_string();
|
||||||
@@ -502,10 +517,7 @@ impl EthereumNode for GethNode {
|
|||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
let id = self.id;
|
let id = self.id;
|
||||||
let provider = self.provider().await?;
|
let provider = self.provider().await?;
|
||||||
Ok(Arc::new(GethNodeResolver {
|
Ok(Arc::new(GethNodeResolver { id, provider }) as Arc<dyn ResolverApi>)
|
||||||
id,
|
|
||||||
provider,
|
|
||||||
}) as Arc<dyn ResolverApi>)
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -648,7 +660,10 @@ impl ResolverApi for GethNodeResolver {
|
|||||||
.context("Failed to get the geth block")?
|
.context("Failed to get the geth block")?
|
||||||
.context("Failed to get the Geth block, perhaps there are no blocks?")
|
.context("Failed to get the Geth block, perhaps there are no blocks?")
|
||||||
.and_then(|block| {
|
.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")
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -765,7 +780,11 @@ mod tests {
|
|||||||
// Arrange
|
// Arrange
|
||||||
let (context, node) = shared_state();
|
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()
|
let transaction = TransactionRequest::default()
|
||||||
.to(account_address)
|
.to(account_address)
|
||||||
.value(U256::from(100_000_000_000_000u128));
|
.value(U256::from(100_000_000_000_000u128));
|
||||||
@@ -788,7 +807,10 @@ mod tests {
|
|||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
let version = version.expect("Failed to get the version");
|
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]
|
#[tokio::test]
|
||||||
@@ -812,8 +834,12 @@ mod tests {
|
|||||||
let node = shared_node();
|
let node = shared_node();
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
let gas_limit =
|
let gas_limit = node
|
||||||
node.resolver().await.unwrap().block_gas_limit(BlockNumberOrTag::Latest).await;
|
.resolver()
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
.block_gas_limit(BlockNumberOrTag::Latest)
|
||||||
|
.await;
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
let _ = gas_limit.expect("Failed to get the gas limit");
|
let _ = gas_limit.expect("Failed to get the gas limit");
|
||||||
@@ -826,8 +852,12 @@ mod tests {
|
|||||||
let node = shared_node();
|
let node = shared_node();
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
let coinbase =
|
let coinbase = node
|
||||||
node.resolver().await.unwrap().block_coinbase(BlockNumberOrTag::Latest).await;
|
.resolver()
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
.block_coinbase(BlockNumberOrTag::Latest)
|
||||||
|
.await;
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
let _ = coinbase.expect("Failed to get the coinbase");
|
let _ = coinbase.expect("Failed to get the coinbase");
|
||||||
@@ -840,8 +870,12 @@ mod tests {
|
|||||||
let node = shared_node();
|
let node = shared_node();
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
let block_difficulty =
|
let block_difficulty = node
|
||||||
node.resolver().await.unwrap().block_difficulty(BlockNumberOrTag::Latest).await;
|
.resolver()
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
.block_difficulty(BlockNumberOrTag::Latest)
|
||||||
|
.await;
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
let _ = block_difficulty.expect("Failed to get the block difficulty");
|
let _ = block_difficulty.expect("Failed to get the block difficulty");
|
||||||
@@ -854,7 +888,12 @@ mod tests {
|
|||||||
let node = shared_node();
|
let node = shared_node();
|
||||||
|
|
||||||
// Act
|
// 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
|
// Assert
|
||||||
let _ = block_hash.expect("Failed to get the block hash");
|
let _ = block_hash.expect("Failed to get the block hash");
|
||||||
@@ -867,8 +906,12 @@ mod tests {
|
|||||||
let node = shared_node();
|
let node = shared_node();
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
let block_timestamp =
|
let block_timestamp = node
|
||||||
node.resolver().await.unwrap().block_timestamp(BlockNumberOrTag::Latest).await;
|
.resolver()
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
.block_timestamp(BlockNumberOrTag::Latest)
|
||||||
|
.await;
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
let _ = block_timestamp.expect("Failed to get the block timestamp");
|
let _ = block_timestamp.expect("Failed to get the block timestamp");
|
||||||
|
|||||||
@@ -132,7 +132,9 @@ impl LighthouseGethNode {
|
|||||||
let wallet_configuration = AsRef::<WalletConfiguration>::as_ref(&context);
|
let wallet_configuration = AsRef::<WalletConfiguration>::as_ref(&context);
|
||||||
let kurtosis_configuration = AsRef::<KurtosisConfiguration>::as_ref(&context);
|
let kurtosis_configuration = AsRef::<KurtosisConfiguration>::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 id = NODE_COUNT.fetch_add(1, Ordering::SeqCst);
|
||||||
let base_directory = geth_directory.join(id.to_string());
|
let base_directory = geth_directory.join(id.to_string());
|
||||||
|
|
||||||
@@ -145,7 +147,10 @@ impl LighthouseGethNode {
|
|||||||
http_connection_string: String::default(),
|
http_connection_string: String::default(),
|
||||||
enclave_name: format!(
|
enclave_name: format!(
|
||||||
"enclave-{}-{}",
|
"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
|
id
|
||||||
),
|
),
|
||||||
|
|
||||||
@@ -178,7 +183,8 @@ impl LighthouseGethNode {
|
|||||||
fn init(&mut self, _: Genesis) -> anyhow::Result<&mut Self> {
|
fn init(&mut self, _: Genesis) -> anyhow::Result<&mut Self> {
|
||||||
self.init_directories()
|
self.init_directories()
|
||||||
.context("Failed to initialize the directories of the Lighthouse Geth node.")?;
|
.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)
|
Ok(self)
|
||||||
}
|
}
|
||||||
@@ -420,8 +426,9 @@ impl LighthouseGethNode {
|
|||||||
.context("Full block subscriber")?;
|
.context("Full block subscriber")?;
|
||||||
|
|
||||||
let mut tx_hashes = futures::future::try_join_all(
|
let mut tx_hashes = futures::future::try_join_all(
|
||||||
NetworkWallet::<Ethereum>::signer_addresses(self.wallet.as_ref()).enumerate().map(
|
NetworkWallet::<Ethereum>::signer_addresses(self.wallet.as_ref())
|
||||||
|(nonce, address)| async move {
|
.enumerate()
|
||||||
|
.map(|(nonce, address)| async move {
|
||||||
let mut transaction = TransactionRequest::default()
|
let mut transaction = TransactionRequest::default()
|
||||||
.from(self.prefunded_account_address)
|
.from(self.prefunded_account_address)
|
||||||
.to(address)
|
.to(address)
|
||||||
@@ -429,8 +436,7 @@ impl LighthouseGethNode {
|
|||||||
.value(INITIAL_BALANCE.try_into().unwrap());
|
.value(INITIAL_BALANCE.try_into().unwrap());
|
||||||
transaction.chain_id = Some(CHAIN_ID);
|
transaction.chain_id = Some(CHAIN_ID);
|
||||||
self.submit_transaction(transaction).await
|
self.submit_transaction(transaction).await
|
||||||
},
|
}),
|
||||||
),
|
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.context("Failed to submit all transactions")?
|
.context("Failed to submit all transactions")?
|
||||||
@@ -525,7 +531,10 @@ impl LighthouseGethNode {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
.instrument(tracing::info_span!("Awaiting transaction receipt", ?transaction_hash))
|
.instrument(tracing::info_span!(
|
||||||
|
"Awaiting transaction receipt",
|
||||||
|
?transaction_hash
|
||||||
|
))
|
||||||
.await
|
.await
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -614,7 +623,9 @@ impl EthereumNode for LighthouseGethNode {
|
|||||||
) -> Pin<Box<dyn Future<Output = anyhow::Result<GethTrace>> + '_>> {
|
) -> Pin<Box<dyn Future<Output = anyhow::Result<GethTrace>> + '_>> {
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
let provider = Arc::new(
|
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(
|
poll(
|
||||||
Self::TRACE_POLLING_DURATION,
|
Self::TRACE_POLLING_DURATION,
|
||||||
@@ -623,7 +634,10 @@ impl EthereumNode for LighthouseGethNode {
|
|||||||
let provider = provider.clone();
|
let provider = provider.clone();
|
||||||
let trace_options = trace_options.clone();
|
let trace_options = trace_options.clone();
|
||||||
async move {
|
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)),
|
Ok(trace) => Ok(ControlFlow::Break(trace)),
|
||||||
Err(error) => {
|
Err(error) => {
|
||||||
let error_string = error.to_string();
|
let error_string = error.to_string();
|
||||||
@@ -703,10 +717,7 @@ impl EthereumNode for LighthouseGethNode {
|
|||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
let id = self.id;
|
let id = self.id;
|
||||||
let provider = self.ws_provider().await?;
|
let provider = self.ws_provider().await?;
|
||||||
Ok(Arc::new(LighthouseGethNodeResolver {
|
Ok(Arc::new(LighthouseGethNodeResolver { id, provider }) as Arc<dyn ResolverApi>)
|
||||||
id,
|
|
||||||
provider,
|
|
||||||
}) as Arc<dyn ResolverApi>)
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -848,7 +859,10 @@ impl<F: TxFiller<Ethereum>, P: Provider<Ethereum>> ResolverApi
|
|||||||
.context("Failed to get the geth block")?
|
.context("Failed to get the geth block")?
|
||||||
.context("Failed to get the Geth block, perhaps there are no blocks?")
|
.context("Failed to get the Geth block, perhaps there are no blocks?")
|
||||||
.and_then(|block| {
|
.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")
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -902,7 +916,11 @@ impl Node for LighthouseGethNode {
|
|||||||
.spawn()
|
.spawn()
|
||||||
.expect("Failed to spawn the enclave kill command");
|
.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 stdout = {
|
||||||
let mut stdout = String::default();
|
let mut stdout = String::default();
|
||||||
child
|
child
|
||||||
@@ -1128,7 +1146,11 @@ mod tests {
|
|||||||
let (context, node) = new_node();
|
let (context, node) = new_node();
|
||||||
node.fund_all_accounts().await.expect("Failed");
|
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()
|
let transaction = TransactionRequest::default()
|
||||||
.to(account_address)
|
.to(account_address)
|
||||||
.value(U256::from(100_000_000_000_000u128));
|
.value(U256::from(100_000_000_000_000u128));
|
||||||
@@ -1151,7 +1173,10 @@ mod tests {
|
|||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
let version = version.expect("Failed to get the version");
|
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]
|
#[tokio::test]
|
||||||
@@ -1175,8 +1200,12 @@ mod tests {
|
|||||||
let (_context, node) = new_node();
|
let (_context, node) = new_node();
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
let gas_limit =
|
let gas_limit = node
|
||||||
node.resolver().await.unwrap().block_gas_limit(BlockNumberOrTag::Latest).await;
|
.resolver()
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
.block_gas_limit(BlockNumberOrTag::Latest)
|
||||||
|
.await;
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
let _ = gas_limit.expect("Failed to get the gas limit");
|
let _ = gas_limit.expect("Failed to get the gas limit");
|
||||||
@@ -1189,8 +1218,12 @@ mod tests {
|
|||||||
let (_context, node) = new_node();
|
let (_context, node) = new_node();
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
let coinbase =
|
let coinbase = node
|
||||||
node.resolver().await.unwrap().block_coinbase(BlockNumberOrTag::Latest).await;
|
.resolver()
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
.block_coinbase(BlockNumberOrTag::Latest)
|
||||||
|
.await;
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
let _ = coinbase.expect("Failed to get the coinbase");
|
let _ = coinbase.expect("Failed to get the coinbase");
|
||||||
@@ -1203,8 +1236,12 @@ mod tests {
|
|||||||
let (_context, node) = new_node();
|
let (_context, node) = new_node();
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
let block_difficulty =
|
let block_difficulty = node
|
||||||
node.resolver().await.unwrap().block_difficulty(BlockNumberOrTag::Latest).await;
|
.resolver()
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
.block_difficulty(BlockNumberOrTag::Latest)
|
||||||
|
.await;
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
let _ = block_difficulty.expect("Failed to get the block difficulty");
|
let _ = block_difficulty.expect("Failed to get the block difficulty");
|
||||||
@@ -1217,7 +1254,12 @@ mod tests {
|
|||||||
let (_context, node) = new_node();
|
let (_context, node) = new_node();
|
||||||
|
|
||||||
// Act
|
// 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
|
// Assert
|
||||||
let _ = block_hash.expect("Failed to get the block hash");
|
let _ = block_hash.expect("Failed to get the block hash");
|
||||||
@@ -1230,8 +1272,12 @@ mod tests {
|
|||||||
let (_context, node) = new_node();
|
let (_context, node) = new_node();
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
let block_timestamp =
|
let block_timestamp = node
|
||||||
node.resolver().await.unwrap().block_timestamp(BlockNumberOrTag::Latest).await;
|
.resolver()
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
.block_timestamp(BlockNumberOrTag::Latest)
|
||||||
|
.await;
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
let _ = block_timestamp.expect("Failed to get the block timestamp");
|
let _ = block_timestamp.expect("Failed to get the block timestamp");
|
||||||
|
|||||||
@@ -108,7 +108,9 @@ impl SubstrateNode {
|
|||||||
) -> Self {
|
) -> Self {
|
||||||
let working_directory_path =
|
let working_directory_path =
|
||||||
AsRef::<WorkingDirectoryConfiguration>::as_ref(&context).as_path();
|
AsRef::<WorkingDirectoryConfiguration>::as_ref(&context).as_path();
|
||||||
let eth_rpc_path = AsRef::<EthRpcConfiguration>::as_ref(&context).path.as_path();
|
let eth_rpc_path = AsRef::<EthRpcConfiguration>::as_ref(&context)
|
||||||
|
.path
|
||||||
|
.as_path();
|
||||||
let wallet = AsRef::<WalletConfiguration>::as_ref(&context).wallet();
|
let wallet = AsRef::<WalletConfiguration>::as_ref(&context).wallet();
|
||||||
|
|
||||||
let substrate_directory = working_directory_path.join(Self::BASE_DIRECTORY);
|
let substrate_directory = working_directory_path.join(Self::BASE_DIRECTORY);
|
||||||
@@ -325,12 +327,15 @@ impl SubstrateNode {
|
|||||||
&self,
|
&self,
|
||||||
genesis: &Genesis,
|
genesis: &Genesis,
|
||||||
) -> anyhow::Result<Vec<(String, u128)>> {
|
) -> anyhow::Result<Vec<(String, u128)>> {
|
||||||
genesis.alloc.iter().try_fold(Vec::new(), |mut vec, (address, acc)| {
|
genesis
|
||||||
let substrate_address = Self::eth_to_substrate_address(address);
|
.alloc
|
||||||
let balance = acc.balance.try_into()?;
|
.iter()
|
||||||
vec.push((substrate_address, balance));
|
.try_fold(Vec::new(), |mut vec, (address, acc)| {
|
||||||
Ok(vec)
|
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 {
|
fn eth_to_substrate_address(address: &Address) -> String {
|
||||||
@@ -425,7 +430,10 @@ impl EthereumNode for SubstrateNode {
|
|||||||
transaction: TransactionRequest,
|
transaction: TransactionRequest,
|
||||||
) -> Pin<Box<dyn Future<Output = anyhow::Result<TransactionReceipt>> + '_>> {
|
) -> Pin<Box<dyn Future<Output = anyhow::Result<TransactionReceipt>> + '_>> {
|
||||||
Box::pin(async move {
|
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
|
execute_transaction(provider, transaction).await
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -502,10 +510,7 @@ impl EthereumNode for SubstrateNode {
|
|||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
let id = self.id;
|
let id = self.id;
|
||||||
let provider = self.provider().await?;
|
let provider = self.provider().await?;
|
||||||
Ok(Arc::new(SubstrateNodeResolver {
|
Ok(Arc::new(SubstrateNodeResolver { id, provider }) as Arc<dyn ResolverApi>)
|
||||||
id,
|
|
||||||
provider,
|
|
||||||
}) as Arc<dyn ResolverApi>)
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -526,8 +531,10 @@ impl EthereumNode for SubstrateNode {
|
|||||||
.provider()
|
.provider()
|
||||||
.await
|
.await
|
||||||
.context("Failed to create the provider for block subscription")?;
|
.context("Failed to create the provider for block subscription")?;
|
||||||
let mut block_subscription =
|
let mut block_subscription = provider
|
||||||
provider.watch_full_blocks().await.context("Failed to create the blocks stream")?;
|
.watch_full_blocks()
|
||||||
|
.await
|
||||||
|
.context("Failed to create the blocks stream")?;
|
||||||
block_subscription.set_channel_size(0xFFFF);
|
block_subscription.set_channel_size(0xFFFF);
|
||||||
block_subscription.set_poll_interval(Duration::from_secs(1));
|
block_subscription.set_poll_interval(Duration::from_secs(1));
|
||||||
let block_stream = block_subscription.into_stream();
|
let block_stream = block_subscription.into_stream();
|
||||||
@@ -648,7 +655,10 @@ impl ResolverApi for SubstrateNodeResolver {
|
|||||||
.context("Failed to get the substrate block")?
|
.context("Failed to get the substrate block")?
|
||||||
.context("Failed to get the substrate block, perhaps the chain has no blocks?")
|
.context("Failed to get the substrate block, perhaps the chain has no blocks?")
|
||||||
.and_then(|block| {
|
.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")
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -927,26 +937,25 @@ impl TransactionBuilder<ReviveNetwork> for <Ethereum as Network>::TransactionReq
|
|||||||
);
|
);
|
||||||
match result {
|
match result {
|
||||||
Ok(unsigned_tx) => Ok(unsigned_tx),
|
Ok(unsigned_tx) => Ok(unsigned_tx),
|
||||||
Err(UnbuiltTransactionError {
|
Err(UnbuiltTransactionError { request, error }) => {
|
||||||
request,
|
Err(UnbuiltTransactionError::<ReviveNetwork> {
|
||||||
error,
|
request,
|
||||||
}) => Err(UnbuiltTransactionError::<ReviveNetwork> {
|
error: match error {
|
||||||
request,
|
TransactionBuilderError::InvalidTransactionRequest(tx_type, items) => {
|
||||||
error: match error {
|
TransactionBuilderError::InvalidTransactionRequest(tx_type, items)
|
||||||
TransactionBuilderError::InvalidTransactionRequest(tx_type, items) => {
|
}
|
||||||
TransactionBuilderError::InvalidTransactionRequest(tx_type, items)
|
TransactionBuilderError::UnsupportedSignatureType => {
|
||||||
}
|
TransactionBuilderError::UnsupportedSignatureType
|
||||||
TransactionBuilderError::UnsupportedSignatureType => {
|
}
|
||||||
TransactionBuilderError::UnsupportedSignatureType
|
TransactionBuilderError::Signer(error) => {
|
||||||
}
|
TransactionBuilderError::Signer(error)
|
||||||
TransactionBuilderError::Signer(error) => {
|
}
|
||||||
TransactionBuilderError::Signer(error)
|
TransactionBuilderError::Custom(error) => {
|
||||||
}
|
TransactionBuilderError::Custom(error)
|
||||||
TransactionBuilderError::Custom(error) => {
|
}
|
||||||
TransactionBuilderError::Custom(error)
|
},
|
||||||
}
|
})
|
||||||
},
|
}
|
||||||
}),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1214,7 +1223,11 @@ mod tests {
|
|||||||
|
|
||||||
let provider = node.provider().await.expect("Failed to create provider");
|
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()
|
let transaction = TransactionRequest::default()
|
||||||
.to(account_address)
|
.to(account_address)
|
||||||
.value(U256::from(100_000_000_000_000u128));
|
.value(U256::from(100_000_000_000_000u128));
|
||||||
@@ -1254,11 +1267,14 @@ mod tests {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Call `init()`
|
// 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
|
// Check that the patched chainspec file was generated
|
||||||
let final_chainspec_path =
|
let final_chainspec_path = dummy_node
|
||||||
dummy_node.base_directory.join(SubstrateNode::CHAIN_SPEC_JSON_FILE);
|
.base_directory
|
||||||
|
.join(SubstrateNode::CHAIN_SPEC_JSON_FILE);
|
||||||
assert!(final_chainspec_path.exists(), "Chainspec file should exist");
|
assert!(final_chainspec_path.exists(), "Chainspec file should exist");
|
||||||
|
|
||||||
let contents = fs::read_to_string(&final_chainspec_path).expect("Failed to read chainspec");
|
let contents = fs::read_to_string(&final_chainspec_path).expect("Failed to read chainspec");
|
||||||
@@ -1364,7 +1380,10 @@ mod tests {
|
|||||||
|
|
||||||
for (eth_addr, expected_ss58) in cases {
|
for (eth_addr, expected_ss58) in cases {
|
||||||
let result = SubstrateNode::eth_to_substrate_address(ð_addr.parse().unwrap());
|
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}"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1415,8 +1434,12 @@ mod tests {
|
|||||||
let node = shared_node();
|
let node = shared_node();
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
let gas_limit =
|
let gas_limit = node
|
||||||
node.resolver().await.unwrap().block_gas_limit(BlockNumberOrTag::Latest).await;
|
.resolver()
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
.block_gas_limit(BlockNumberOrTag::Latest)
|
||||||
|
.await;
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
let _ = gas_limit.expect("Failed to get the gas limit");
|
let _ = gas_limit.expect("Failed to get the gas limit");
|
||||||
@@ -1429,8 +1452,12 @@ mod tests {
|
|||||||
let node = shared_node();
|
let node = shared_node();
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
let coinbase =
|
let coinbase = node
|
||||||
node.resolver().await.unwrap().block_coinbase(BlockNumberOrTag::Latest).await;
|
.resolver()
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
.block_coinbase(BlockNumberOrTag::Latest)
|
||||||
|
.await;
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
let _ = coinbase.expect("Failed to get the coinbase");
|
let _ = coinbase.expect("Failed to get the coinbase");
|
||||||
@@ -1443,8 +1470,12 @@ mod tests {
|
|||||||
let node = shared_node();
|
let node = shared_node();
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
let block_difficulty =
|
let block_difficulty = node
|
||||||
node.resolver().await.unwrap().block_difficulty(BlockNumberOrTag::Latest).await;
|
.resolver()
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
.block_difficulty(BlockNumberOrTag::Latest)
|
||||||
|
.await;
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
let _ = block_difficulty.expect("Failed to get the block difficulty");
|
let _ = block_difficulty.expect("Failed to get the block difficulty");
|
||||||
@@ -1457,7 +1488,12 @@ mod tests {
|
|||||||
let node = shared_node();
|
let node = shared_node();
|
||||||
|
|
||||||
// Act
|
// 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
|
// Assert
|
||||||
let _ = block_hash.expect("Failed to get the block hash");
|
let _ = block_hash.expect("Failed to get the block hash");
|
||||||
@@ -1470,8 +1506,12 @@ mod tests {
|
|||||||
let node = shared_node();
|
let node = shared_node();
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
let block_timestamp =
|
let block_timestamp = node
|
||||||
node.resolver().await.unwrap().block_timestamp(BlockNumberOrTag::Latest).await;
|
.resolver()
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
.block_timestamp(BlockNumberOrTag::Latest)
|
||||||
|
.await;
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
let _ = block_timestamp.expect("Failed to get the block timestamp");
|
let _ = block_timestamp.expect("Failed to get the block timestamp");
|
||||||
|
|||||||
@@ -130,10 +130,14 @@ impl ZombieNode {
|
|||||||
+ AsRef<EthRpcConfiguration>
|
+ AsRef<EthRpcConfiguration>
|
||||||
+ AsRef<WalletConfiguration>,
|
+ AsRef<WalletConfiguration>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let eth_proxy_binary = AsRef::<EthRpcConfiguration>::as_ref(&context).path.to_owned();
|
let eth_proxy_binary = AsRef::<EthRpcConfiguration>::as_ref(&context)
|
||||||
|
.path
|
||||||
|
.to_owned();
|
||||||
let working_directory_path = AsRef::<WorkingDirectoryConfiguration>::as_ref(&context);
|
let working_directory_path = AsRef::<WorkingDirectoryConfiguration>::as_ref(&context);
|
||||||
let id = NODE_COUNT.fetch_add(1, Ordering::SeqCst);
|
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 logs_directory = base_directory.join(Self::LOGS_DIRECTORY);
|
||||||
let wallet = AsRef::<WalletConfiguration>::as_ref(&context).wallet();
|
let wallet = AsRef::<WalletConfiguration>::as_ref(&context).wallet();
|
||||||
|
|
||||||
@@ -165,8 +169,10 @@ impl ZombieNode {
|
|||||||
|
|
||||||
let template_chainspec_path = self.base_directory.join(Self::CHAIN_SPEC_JSON_FILE);
|
let template_chainspec_path = self.base_directory.join(Self::CHAIN_SPEC_JSON_FILE);
|
||||||
self.prepare_chainspec(template_chainspec_path.clone(), genesis)?;
|
self.prepare_chainspec(template_chainspec_path.clone(), genesis)?;
|
||||||
let polkadot_parachain_path =
|
let polkadot_parachain_path = self
|
||||||
self.polkadot_parachain_path.to_str().context("Invalid polkadot parachain path")?;
|
.polkadot_parachain_path
|
||||||
|
.to_str()
|
||||||
|
.context("Invalid polkadot parachain path")?;
|
||||||
|
|
||||||
let node_rpc_port = Self::NODE_BASE_RPC_PORT + self.id as u16;
|
let node_rpc_port = Self::NODE_BASE_RPC_PORT + self.id as u16;
|
||||||
|
|
||||||
@@ -198,8 +204,10 @@ impl ZombieNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn spawn_process(&mut self) -> anyhow::Result<()> {
|
fn spawn_process(&mut self) -> anyhow::Result<()> {
|
||||||
let network_config =
|
let network_config = self
|
||||||
self.network_config.clone().context("Node not initialized, call init() first")?;
|
.network_config
|
||||||
|
.clone()
|
||||||
|
.context("Node not initialized, call init() first")?;
|
||||||
|
|
||||||
let rt = tokio::runtime::Runtime::new().unwrap();
|
let rt = tokio::runtime::Runtime::new().unwrap();
|
||||||
let network = rt.block_on(async {
|
let network = rt.block_on(async {
|
||||||
@@ -264,12 +272,17 @@ impl ZombieNode {
|
|||||||
mut genesis: Genesis,
|
mut genesis: Genesis,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
let mut cmd: Command = std::process::Command::new(&self.polkadot_parachain_path);
|
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")?;
|
let output = cmd.output().context("Failed to export the chain-spec")?;
|
||||||
|
|
||||||
if !output.status.success() {
|
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)
|
let content = String::from_utf8(output.stdout)
|
||||||
@@ -330,12 +343,15 @@ impl ZombieNode {
|
|||||||
&self,
|
&self,
|
||||||
genesis: &Genesis,
|
genesis: &Genesis,
|
||||||
) -> anyhow::Result<Vec<(String, u128)>> {
|
) -> anyhow::Result<Vec<(String, u128)>> {
|
||||||
genesis.alloc.iter().try_fold(Vec::new(), |mut vec, (address, acc)| {
|
genesis
|
||||||
let polkadot_address = Self::eth_to_polkadot_address(address);
|
.alloc
|
||||||
let balance = acc.balance.try_into()?;
|
.iter()
|
||||||
vec.push((polkadot_address, balance));
|
.try_fold(Vec::new(), |mut vec, (address, acc)| {
|
||||||
Ok(vec)
|
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 {
|
fn eth_to_polkadot_address(address: &Address) -> String {
|
||||||
@@ -519,10 +535,7 @@ impl EthereumNode for ZombieNode {
|
|||||||
let id = self.id;
|
let id = self.id;
|
||||||
let provider = self.provider().await?;
|
let provider = self.provider().await?;
|
||||||
|
|
||||||
Ok(Arc::new(ZombieNodeResolver {
|
Ok(Arc::new(ZombieNodeResolver { id, provider }) as Arc<dyn ResolverApi>)
|
||||||
id,
|
|
||||||
provider,
|
|
||||||
}) as Arc<dyn ResolverApi>)
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -543,8 +556,10 @@ impl EthereumNode for ZombieNode {
|
|||||||
.provider()
|
.provider()
|
||||||
.await
|
.await
|
||||||
.context("Failed to create the provider for block subscription")?;
|
.context("Failed to create the provider for block subscription")?;
|
||||||
let mut block_subscription =
|
let mut block_subscription = provider
|
||||||
provider.watch_full_blocks().await.context("Failed to create the blocks stream")?;
|
.watch_full_blocks()
|
||||||
|
.await
|
||||||
|
.context("Failed to create the blocks stream")?;
|
||||||
block_subscription.set_channel_size(0xFFFF);
|
block_subscription.set_channel_size(0xFFFF);
|
||||||
block_subscription.set_poll_interval(Duration::from_secs(1));
|
block_subscription.set_poll_interval(Duration::from_secs(1));
|
||||||
let block_stream = block_subscription.into_stream();
|
let block_stream = block_subscription.into_stream();
|
||||||
@@ -667,7 +682,10 @@ impl<F: TxFiller<ReviveNetwork>, P: Provider<ReviveNetwork>> ResolverApi
|
|||||||
.context("Failed to get the zombie block")?
|
.context("Failed to get the zombie block")?
|
||||||
.context("Failed to get the zombie block, perhaps the chain has no blocks?")
|
.context("Failed to get the zombie block, perhaps the chain has no blocks?")
|
||||||
.and_then(|block| {
|
.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")
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -779,8 +797,10 @@ mod tests {
|
|||||||
|
|
||||||
pub async fn new_node() -> (TestExecutionContext, ZombieNode) {
|
pub async fn new_node() -> (TestExecutionContext, ZombieNode) {
|
||||||
let context = test_config();
|
let context = test_config();
|
||||||
let mut node =
|
let mut node = ZombieNode::new(
|
||||||
ZombieNode::new(context.polkadot_parachain_configuration.path.clone(), &context);
|
context.polkadot_parachain_configuration.path.clone(),
|
||||||
|
&context,
|
||||||
|
);
|
||||||
let genesis = context.genesis_configuration.genesis().unwrap().clone();
|
let genesis = context.genesis_configuration.genesis().unwrap().clone();
|
||||||
node.init(genesis).unwrap();
|
node.init(genesis).unwrap();
|
||||||
|
|
||||||
@@ -845,11 +865,14 @@ mod tests {
|
|||||||
"#;
|
"#;
|
||||||
|
|
||||||
let context = test_config();
|
let context = test_config();
|
||||||
let mut node =
|
let mut node = ZombieNode::new(
|
||||||
ZombieNode::new(context.polkadot_parachain_configuration.path.clone(), &context);
|
context.polkadot_parachain_configuration.path.clone(),
|
||||||
|
&context,
|
||||||
|
);
|
||||||
|
|
||||||
// Call `init()`
|
// 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
|
// Check that the patched chainspec file was generated
|
||||||
let final_chainspec_path = node.base_directory.join(ZombieNode::CHAIN_SPEC_JSON_FILE);
|
let final_chainspec_path = node.base_directory.join(ZombieNode::CHAIN_SPEC_JSON_FILE);
|
||||||
@@ -890,7 +913,10 @@ mod tests {
|
|||||||
"#;
|
"#;
|
||||||
|
|
||||||
let context = test_config();
|
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
|
let result = node
|
||||||
.extract_balance_from_genesis_file(&serde_json::from_str(genesis_json).unwrap())
|
.extract_balance_from_genesis_file(&serde_json::from_str(genesis_json).unwrap())
|
||||||
@@ -952,7 +978,10 @@ mod tests {
|
|||||||
|
|
||||||
for (eth_addr, expected_ss58) in cases {
|
for (eth_addr, expected_ss58) in cases {
|
||||||
let result = ZombieNode::eth_to_polkadot_address(ð_addr.parse().unwrap());
|
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}"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -960,7 +989,10 @@ mod tests {
|
|||||||
fn eth_rpc_version_works() {
|
fn eth_rpc_version_works() {
|
||||||
// Arrange
|
// Arrange
|
||||||
let context = test_config();
|
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
|
// Act
|
||||||
let version = node.eth_rpc_version().unwrap();
|
let version = node.eth_rpc_version().unwrap();
|
||||||
@@ -976,7 +1008,10 @@ mod tests {
|
|||||||
fn version_works() {
|
fn version_works() {
|
||||||
// Arrange
|
// Arrange
|
||||||
let context = test_config();
|
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
|
// Act
|
||||||
let version = node.version().unwrap();
|
let version = node.version().unwrap();
|
||||||
@@ -1014,8 +1049,12 @@ mod tests {
|
|||||||
let node = shared_node().await;
|
let node = shared_node().await;
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
let gas_limit =
|
let gas_limit = node
|
||||||
node.resolver().await.unwrap().block_gas_limit(BlockNumberOrTag::Latest).await;
|
.resolver()
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
.block_gas_limit(BlockNumberOrTag::Latest)
|
||||||
|
.await;
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
let _ = gas_limit.expect("Failed to get the gas limit");
|
let _ = gas_limit.expect("Failed to get the gas limit");
|
||||||
@@ -1028,8 +1067,12 @@ mod tests {
|
|||||||
let node = shared_node().await;
|
let node = shared_node().await;
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
let coinbase =
|
let coinbase = node
|
||||||
node.resolver().await.unwrap().block_coinbase(BlockNumberOrTag::Latest).await;
|
.resolver()
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
.block_coinbase(BlockNumberOrTag::Latest)
|
||||||
|
.await;
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
let _ = coinbase.expect("Failed to get the coinbase");
|
let _ = coinbase.expect("Failed to get the coinbase");
|
||||||
@@ -1042,8 +1085,12 @@ mod tests {
|
|||||||
let node = shared_node().await;
|
let node = shared_node().await;
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
let block_difficulty =
|
let block_difficulty = node
|
||||||
node.resolver().await.unwrap().block_difficulty(BlockNumberOrTag::Latest).await;
|
.resolver()
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
.block_difficulty(BlockNumberOrTag::Latest)
|
||||||
|
.await;
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
let _ = block_difficulty.expect("Failed to get the block difficulty");
|
let _ = block_difficulty.expect("Failed to get the block difficulty");
|
||||||
@@ -1056,7 +1103,12 @@ mod tests {
|
|||||||
let node = shared_node().await;
|
let node = shared_node().await;
|
||||||
|
|
||||||
// Act
|
// 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
|
// Assert
|
||||||
let _ = block_hash.expect("Failed to get the block hash");
|
let _ = block_hash.expect("Failed to get the block hash");
|
||||||
@@ -1069,8 +1121,12 @@ mod tests {
|
|||||||
let node = shared_node().await;
|
let node = shared_node().await;
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
let block_timestamp =
|
let block_timestamp = node
|
||||||
node.resolver().await.unwrap().block_timestamp(BlockNumberOrTag::Latest).await;
|
.resolver()
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
.block_timestamp(BlockNumberOrTag::Latest)
|
||||||
|
.await;
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
let _ = block_timestamp.expect("Failed to get the block timestamp");
|
let _ = block_timestamp.expect("Failed to get the block timestamp");
|
||||||
|
|||||||
@@ -55,7 +55,10 @@ where
|
|||||||
let future = self.service.call(req);
|
let future = self.service.call(req);
|
||||||
|
|
||||||
Box::pin(async move {
|
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!(
|
tracing::debug!(
|
||||||
available_permits = semaphore.available_permits(),
|
available_permits = semaphore.available_permits(),
|
||||||
"Acquired Semaphore Permit"
|
"Acquired Semaphore Permit"
|
||||||
|
|||||||
@@ -80,8 +80,10 @@ where
|
|||||||
NonceFiller: TxFiller<N>,
|
NonceFiller: TxFiller<N>,
|
||||||
WalletFiller<W>: TxFiller<N>,
|
WalletFiller<W>: TxFiller<N>,
|
||||||
{
|
{
|
||||||
let sendable_transaction =
|
let sendable_transaction = provider
|
||||||
provider.fill(transaction).await.context("Failed to fill transaction")?;
|
.fill(transaction)
|
||||||
|
.await
|
||||||
|
.context("Failed to fill transaction")?;
|
||||||
|
|
||||||
let transaction_envelope = sendable_transaction
|
let transaction_envelope = sendable_transaction
|
||||||
.try_into_envelope()
|
.try_into_envelope()
|
||||||
@@ -103,21 +105,24 @@ where
|
|||||||
debug!(%tx_hash, "Submitted Transaction");
|
debug!(%tx_hash, "Submitted Transaction");
|
||||||
|
|
||||||
pending_transaction.set_timeout(Some(Duration::from_secs(120)));
|
pending_transaction.set_timeout(Some(Duration::from_secs(120)));
|
||||||
let tx_hash = pending_transaction
|
let tx_hash = pending_transaction.watch().await.context(format!(
|
||||||
.watch()
|
"Transaction inclusion watching timeout for {tx_hash}"
|
||||||
.await
|
))?;
|
||||||
.context(format!("Transaction inclusion watching timeout for {tx_hash}"))?;
|
|
||||||
|
|
||||||
poll(Duration::from_secs(60), PollingWaitBehavior::Constant(Duration::from_secs(3)), || {
|
poll(
|
||||||
let provider = provider.clone();
|
Duration::from_secs(60),
|
||||||
|
PollingWaitBehavior::Constant(Duration::from_secs(3)),
|
||||||
|
|| {
|
||||||
|
let provider = provider.clone();
|
||||||
|
|
||||||
async move {
|
async move {
|
||||||
match provider.get_transaction_receipt(tx_hash).await {
|
match provider.get_transaction_receipt(tx_hash).await {
|
||||||
Ok(Some(receipt)) => Ok(ControlFlow::Break(receipt)),
|
Ok(Some(receipt)) => Ok(ControlFlow::Break(receipt)),
|
||||||
_ => Ok(ControlFlow::Continue(())),
|
_ => Ok(ControlFlow::Continue(())),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
})
|
)
|
||||||
.await
|
.await
|
||||||
.context(format!("Polling for receipt failed for {tx_hash}"))
|
.context(format!("Polling for receipt failed for {tx_hash}"))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -123,8 +123,12 @@ impl ReportAggregator {
|
|||||||
file_name.push_str(".json");
|
file_name.push_str(".json");
|
||||||
file_name
|
file_name
|
||||||
};
|
};
|
||||||
let file_path =
|
let file_path = self
|
||||||
self.report.context.working_directory_configuration().as_path().join(file_name);
|
.report
|
||||||
|
.context
|
||||||
|
.working_directory_configuration()
|
||||||
|
.as_path()
|
||||||
|
.join(file_name);
|
||||||
let file = OpenOptions::new()
|
let file = OpenOptions::new()
|
||||||
.create(true)
|
.create(true)
|
||||||
.write(true)
|
.write(true)
|
||||||
@@ -132,7 +136,10 @@ impl ReportAggregator {
|
|||||||
.read(false)
|
.read(false)
|
||||||
.open(&file_path)
|
.open(&file_path)
|
||||||
.with_context(|| {
|
.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(|| {
|
serde_json::to_writer_pretty(&file, &self.report).with_context(|| {
|
||||||
format!("Failed to serialize report JSON to {}", file_path.display())
|
format!("Failed to serialize report JSON to {}", file_path.display())
|
||||||
@@ -234,7 +241,10 @@ impl ReportAggregator {
|
|||||||
.or_default()
|
.or_default()
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(case_idx, case_report)| {
|
.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::<BTreeMap<_, _>>();
|
.collect::<BTreeMap<_, _>>();
|
||||||
let event = ReporterEvent::MetadataFileSolcModeCombinationExecutionCompleted {
|
let event = ReporterEvent::MetadataFileSolcModeCombinationExecutionCompleted {
|
||||||
@@ -266,8 +276,16 @@ impl ReportAggregator {
|
|||||||
&mut self,
|
&mut self,
|
||||||
event: PreLinkContractsCompilationSucceededEvent,
|
event: PreLinkContractsCompilationSucceededEvent,
|
||||||
) {
|
) {
|
||||||
let include_input = self.report.context.report_configuration().include_compiler_input;
|
let include_input = self
|
||||||
let include_output = self.report.context.report_configuration().include_compiler_output;
|
.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);
|
let execution_information = self.execution_information(&event.execution_specifier);
|
||||||
|
|
||||||
@@ -295,8 +313,16 @@ impl ReportAggregator {
|
|||||||
&mut self,
|
&mut self,
|
||||||
event: PostLinkContractsCompilationSucceededEvent,
|
event: PostLinkContractsCompilationSucceededEvent,
|
||||||
) {
|
) {
|
||||||
let include_input = self.report.context.report_configuration().include_compiler_input;
|
let include_input = self
|
||||||
let include_output = self.report.context.report_configuration().include_compiler_output;
|
.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);
|
let execution_information = self.execution_information(&event.execution_specifier);
|
||||||
|
|
||||||
@@ -349,8 +375,8 @@ impl ReportAggregator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn handle_libraries_deployed_event(&mut self, event: LibrariesDeployedEvent) {
|
fn handle_libraries_deployed_event(&mut self, event: LibrariesDeployedEvent) {
|
||||||
self.execution_information(&event.execution_specifier).deployed_libraries =
|
self.execution_information(&event.execution_specifier)
|
||||||
Some(event.libraries);
|
.deployed_libraries = Some(event.libraries);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_contract_deployed_event(&mut self, event: ContractDeployedEvent) {
|
fn handle_contract_deployed_event(&mut self, event: ContractDeployedEvent) {
|
||||||
|
|||||||
@@ -22,8 +22,9 @@ pub(crate) async fn get_or_download(
|
|||||||
working_directory: &Path,
|
working_directory: &Path,
|
||||||
downloader: &SolcDownloader,
|
downloader: &SolcDownloader,
|
||||||
) -> anyhow::Result<(Version, PathBuf)> {
|
) -> anyhow::Result<(Version, PathBuf)> {
|
||||||
let target_directory =
|
let target_directory = working_directory
|
||||||
working_directory.join(SOLC_CACHE_DIRECTORY).join(downloader.version.to_string());
|
.join(SOLC_CACHE_DIRECTORY)
|
||||||
|
.join(downloader.version.to_string());
|
||||||
let target_file = target_directory.join(downloader.target);
|
let target_file = target_directory.join(downloader.target);
|
||||||
|
|
||||||
let mut cache = SOLC_CACHER.lock().await;
|
let mut cache = SOLC_CACHER.lock().await;
|
||||||
@@ -33,11 +34,19 @@ pub(crate) async fn get_or_download(
|
|||||||
}
|
}
|
||||||
|
|
||||||
create_dir_all(&target_directory).with_context(|| {
|
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)
|
download_to_file(&target_file, downloader)
|
||||||
.await
|
.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());
|
cache.insert(target_file.clone());
|
||||||
|
|
||||||
Ok((downloader.version.clone(), target_file))
|
Ok((downloader.version.clone(), target_file))
|
||||||
@@ -61,9 +70,15 @@ async fn download_to_file(path: &Path, downloader: &SolcDownloader) -> anyhow::R
|
|||||||
}
|
}
|
||||||
|
|
||||||
let mut file = BufWriter::new(file);
|
let mut file = BufWriter::new(file);
|
||||||
file.write_all(&downloader.download().await.context("Failed to download solc binary bytes")?)
|
file.write_all(
|
||||||
.with_context(|| format!("Failed to write solc binary to {}", path.display()))?;
|
&downloader
|
||||||
file.flush().with_context(|| format!("Failed to flush file {}", path.display()))?;
|
.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);
|
drop(file);
|
||||||
|
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
@@ -76,11 +91,17 @@ async fn download_to_file(path: &Path, downloader: &SolcDownloader) -> anyhow::R
|
|||||||
.stdout(std::process::Stdio::null())
|
.stdout(std::process::Stdio::null())
|
||||||
.spawn()
|
.spawn()
|
||||||
.with_context(|| {
|
.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()
|
.wait()
|
||||||
.with_context(|| {
|
.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(())
|
Ok(())
|
||||||
|
|||||||
@@ -130,7 +130,11 @@ impl SolcDownloader {
|
|||||||
})?;
|
})?;
|
||||||
|
|
||||||
let path = build.path.clone();
|
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 url = format!("{}/{}/{}", Self::BASE_URL, self.target, path.display());
|
||||||
|
|
||||||
let file = reqwest::get(&url)
|
let file = reqwest::get(&url)
|
||||||
@@ -155,25 +159,54 @@ mod tests {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn try_get_windows() {
|
async fn try_get_windows() {
|
||||||
let version = List::download(List::WINDOWS_URL).await.unwrap().latest_release;
|
let version = List::download(List::WINDOWS_URL)
|
||||||
SolcDownloader::windows(version).await.unwrap().download().await.unwrap();
|
.await
|
||||||
|
.unwrap()
|
||||||
|
.latest_release;
|
||||||
|
SolcDownloader::windows(version)
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
.download()
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn try_get_macosx() {
|
async fn try_get_macosx() {
|
||||||
let version = List::download(List::MACOSX_URL).await.unwrap().latest_release;
|
let version = List::download(List::MACOSX_URL)
|
||||||
SolcDownloader::macosx(version).await.unwrap().download().await.unwrap();
|
.await
|
||||||
|
.unwrap()
|
||||||
|
.latest_release;
|
||||||
|
SolcDownloader::macosx(version)
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
.download()
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn try_get_linux() {
|
async fn try_get_linux() {
|
||||||
let version = List::download(List::LINUX_URL).await.unwrap().latest_release;
|
let version = List::download(List::LINUX_URL)
|
||||||
SolcDownloader::linux(version).await.unwrap().download().await.unwrap();
|
.await
|
||||||
|
.unwrap()
|
||||||
|
.latest_release;
|
||||||
|
SolcDownloader::linux(version)
|
||||||
|
.await
|
||||||
|
.unwrap()
|
||||||
|
.download()
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn try_get_wasm() {
|
async fn try_get_wasm() {
|
||||||
let version = List::download(List::WASM_URL).await.unwrap().latest_release;
|
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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user