mirror of
https://github.com/pezkuwichain/revive-differential-tests.git
synced 2026-06-11 22:21:11 +00:00
Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 1659164310 | |||
| 0a68800856 | |||
| 8303d789cd | |||
| 40bf44fe58 | |||
| ba8ad03290 | |||
| 3dd99f3ac8 | |||
| 6618463c68 |
@@ -18,28 +18,9 @@ env:
|
|||||||
POLKADOT_VERSION: polkadot-stable2506-2
|
POLKADOT_VERSION: polkadot-stable2506-2
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
fmt:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout repo
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Setup Rust toolchain
|
|
||||||
uses: actions-rust-lang/setup-rust-toolchain@v1
|
|
||||||
|
|
||||||
- name: Install nightly toolchain
|
|
||||||
run: rustup toolchain install nightly
|
|
||||||
|
|
||||||
- name: Install rustfmt for nightly
|
|
||||||
run: rustup component add --toolchain nightly rustfmt
|
|
||||||
|
|
||||||
- name: Cargo fmt
|
|
||||||
run: cargo +nightly fmt --all -- --check
|
|
||||||
|
|
||||||
cache-polkadot:
|
cache-polkadot:
|
||||||
name: Build and cache Polkadot binaries on ${{ matrix.os }}
|
name: Build and cache Polkadot binaries on ${{ matrix.os }}
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
needs: [fmt]
|
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
os: [ubuntu-24.04, macos-14]
|
os: [ubuntu-24.04, macos-14]
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
# Basic
|
||||||
|
edition = "2024"
|
||||||
|
hard_tabs = true
|
||||||
|
max_width = 100
|
||||||
|
use_small_heuristics = "Max"
|
||||||
|
# Imports
|
||||||
|
imports_granularity = "Crate"
|
||||||
|
reorder_imports = true
|
||||||
|
# Consistency
|
||||||
|
newline_style = "Unix"
|
||||||
|
# Misc
|
||||||
|
chain_width = 80
|
||||||
|
spaces_around_ranges = false
|
||||||
|
binop_separator = "Back"
|
||||||
|
reorder_impl_items = false
|
||||||
|
match_arm_leading_pipes = "Preserve"
|
||||||
|
match_arm_blocks = false
|
||||||
|
match_block_trailing_comma = true
|
||||||
|
trailing_comma = "Vertical"
|
||||||
|
trailing_semicolon = false
|
||||||
|
use_field_init_shorthand = true
|
||||||
|
# Format comments
|
||||||
|
comment_width = 100
|
||||||
|
wrap_comments = true
|
||||||
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
.PHONY: format clippy test machete
|
.PHONY: format clippy test machete
|
||||||
|
|
||||||
format:
|
format:
|
||||||
cargo fmt --all -- --check
|
cargo +nightly fmt --all -- --check
|
||||||
|
|
||||||
clippy:
|
clippy:
|
||||||
cargo clippy --all-features --workspace -- --deny warnings
|
cargo clippy --all-features --workspace -- --deny warnings
|
||||||
|
|||||||
@@ -20,17 +20,14 @@ pub fn read(path: impl AsRef<Path>) -> Result<Vec<u8>> {
|
|||||||
let content = fs::read(path.as_path())?;
|
let content = fs::read(path.as_path())?;
|
||||||
READ_CACHE.insert(path, content.clone());
|
READ_CACHE.insert(path, content.clone());
|
||||||
Ok(content)
|
Ok(content)
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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(
|
Error::new(std::io::ErrorKind::InvalidData, "The contents of the file are not valid UTF8")
|
||||||
std::io::ErrorKind::InvalidData,
|
|
||||||
"The contents of the file are not valid UTF8",
|
|
||||||
)
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -46,6 +43,6 @@ pub fn read_dir(path: impl AsRef<Path>) -> Result<Box<dyn Iterator<Item = Result
|
|||||||
.collect();
|
.collect();
|
||||||
READ_DIR_CACHE.insert(path.clone(), entries);
|
READ_DIR_CACHE.insert(path.clone(), entries);
|
||||||
Ok(read_dir(path).unwrap())
|
Ok(read_dir(path).unwrap())
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,10 +12,7 @@ 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!(
|
format!("Failed to read an entry in directory: {}", path.as_ref().display())
|
||||||
"Failed to read an entry in directory: {}",
|
|
||||||
path.as_ref().display()
|
|
||||||
)
|
|
||||||
})?;
|
})?;
|
||||||
let entry_path = entry.path();
|
let entry_path = entry.path();
|
||||||
|
|
||||||
|
|||||||
@@ -37,17 +37,13 @@ where
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
match future()
|
match future().await.context("Polled future returned an error during polling loop")? {
|
||||||
.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,
|
||||||
PollingWaitBehavior::ExponentialBackoff => {
|
PollingWaitBehavior::ExponentialBackoff =>
|
||||||
Duration::from_secs(2u64.pow(retries))
|
Duration::from_secs(2u64.pow(retries))
|
||||||
.min(EXPONENTIAL_BACKOFF_MAX_WAIT_DURATION)
|
.min(EXPONENTIAL_BACKOFF_MAX_WAIT_DURATION),
|
||||||
}
|
|
||||||
};
|
};
|
||||||
let next_wait_duration =
|
let next_wait_duration =
|
||||||
next_wait_duration.min(max_allowed_wait_duration - total_wait_duration);
|
next_wait_duration.min(max_allowed_wait_duration - total_wait_duration);
|
||||||
@@ -55,10 +51,10 @@ where
|
|||||||
retries += 1;
|
retries += 1;
|
||||||
|
|
||||||
tokio::time::sleep(next_wait_duration).await;
|
tokio::time::sleep(next_wait_duration).await;
|
||||||
}
|
},
|
||||||
ControlFlow::Break(output) => {
|
ControlFlow::Break(output) => {
|
||||||
break Ok(output);
|
break Ok(output);
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -75,13 +75,12 @@ impl Iterator for FilesWithExtensionIterator {
|
|||||||
for entry_path in iterator.flatten() {
|
for entry_path in iterator.flatten() {
|
||||||
if entry_path.is_dir() {
|
if entry_path.is_dir() {
|
||||||
self.directories_to_search.push(entry_path)
|
self.directories_to_search.push(entry_path)
|
||||||
} else if entry_path.is_file()
|
} else if entry_path.is_file() &&
|
||||||
&& entry_path.extension().is_some_and(|ext| {
|
entry_path.extension().is_some_and(|ext| {
|
||||||
self.allowed_extensions
|
self.allowed_extensions
|
||||||
.iter()
|
.iter()
|
||||||
.any(|allowed| ext.eq_ignore_ascii_case(allowed.as_ref()))
|
.any(|allowed| ext.eq_ignore_ascii_case(allowed.as_ref()))
|
||||||
})
|
}) {
|
||||||
{
|
|
||||||
self.files_matching_allowed_extensions.push(entry_path)
|
self.files_matching_allowed_extensions.push(entry_path)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -76,9 +76,7 @@ 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!(
|
_ => Err(anyhow::anyhow!("Unsupported pipeline '{s}': expected 'Y' or 'E'")),
|
||||||
"Unsupported pipeline '{s}': expected 'Y' or 'E'"
|
|
||||||
)),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,10 +15,7 @@ pub struct PrivateKeyAllocator {
|
|||||||
impl PrivateKeyAllocator {
|
impl PrivateKeyAllocator {
|
||||||
/// Creates a new instance of the private key allocator.
|
/// Creates a new instance of the private key allocator.
|
||||||
pub fn new(highest_private_key_inclusive: U256) -> Self {
|
pub fn new(highest_private_key_inclusive: U256) -> Self {
|
||||||
Self {
|
Self { next_private_key: U256::ONE, highest_private_key_inclusive }
|
||||||
next_private_key: U256::ONE,
|
|
||||||
highest_private_key_inclusive,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Allocates a new private key and errors out if the maximum private key has been reached.
|
/// Allocates a new private key and errors out if the maximum private key has been reached.
|
||||||
|
|||||||
@@ -7,10 +7,7 @@ pub struct RoundRobinPool<T> {
|
|||||||
|
|
||||||
impl<T> RoundRobinPool<T> {
|
impl<T> RoundRobinPool<T> {
|
||||||
pub fn new(items: Vec<T>) -> Self {
|
pub fn new(items: Vec<T>) -> Self {
|
||||||
Self {
|
Self { next_index: Default::default(), items }
|
||||||
next_index: Default::default(),
|
|
||||||
items,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn round_robin(&self) -> &T {
|
pub fn round_robin(&self) -> &T {
|
||||||
|
|||||||
@@ -60,10 +60,7 @@ impl Resolc {
|
|||||||
Ok(COMPILERS_CACHE
|
Ok(COMPILERS_CACHE
|
||||||
.entry(solc.clone())
|
.entry(solc.clone())
|
||||||
.or_insert_with(|| {
|
.or_insert_with(|| {
|
||||||
Self(Arc::new(ResolcInner {
|
Self(Arc::new(ResolcInner { solc, resolc_path: resolc_configuration.path.clone() }))
|
||||||
solc,
|
|
||||||
resolc_path: resolc_configuration.path.clone(),
|
|
||||||
}))
|
|
||||||
})
|
})
|
||||||
.clone())
|
.clone())
|
||||||
}
|
}
|
||||||
@@ -141,9 +138,7 @@ 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
|
optimization.unwrap_or(ModeOptimizerSetting::M0).optimizations_enabled(),
|
||||||
.unwrap_or(ModeOptimizerSetting::M0)
|
|
||||||
.optimizations_enabled(),
|
|
||||||
None,
|
None,
|
||||||
&Version::new(0, 0, 0),
|
&Version::new(0, 0, 0),
|
||||||
false,
|
false,
|
||||||
@@ -253,16 +248,14 @@ impl SolidityCompiler for Resolc {
|
|||||||
.evm
|
.evm
|
||||||
.and_then(|evm| evm.bytecode.clone())
|
.and_then(|evm| evm.bytecode.clone())
|
||||||
.context("Unexpected - Contract compiled with resolc has no bytecode")?;
|
.context("Unexpected - Contract compiled with resolc has no bytecode")?;
|
||||||
let abi =
|
let abi = {
|
||||||
{
|
|
||||||
let metadata = contract_information
|
let metadata = contract_information
|
||||||
.metadata
|
.metadata
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.context("No metadata found for the contract")?;
|
.context("No metadata found for the contract")?;
|
||||||
let solc_metadata_str = match metadata {
|
let solc_metadata_str = match metadata {
|
||||||
serde_json::Value::String(solc_metadata_str) => {
|
serde_json::Value::String(solc_metadata_str) =>
|
||||||
solc_metadata_str.as_str()
|
solc_metadata_str.as_str(),
|
||||||
}
|
|
||||||
serde_json::Value::Object(metadata_object) => {
|
serde_json::Value::Object(metadata_object) => {
|
||||||
let solc_metadata_value = metadata_object
|
let solc_metadata_value = metadata_object
|
||||||
.get("solc_metadata")
|
.get("solc_metadata")
|
||||||
@@ -270,13 +263,13 @@ impl SolidityCompiler for Resolc {
|
|||||||
solc_metadata_value
|
solc_metadata_value
|
||||||
.as_str()
|
.as_str()
|
||||||
.context("The 'solc_metadata' field is not a string")?
|
.context("The 'solc_metadata' field is not a string")?
|
||||||
}
|
},
|
||||||
serde_json::Value::Null
|
serde_json::Value::Null |
|
||||||
| serde_json::Value::Bool(_)
|
serde_json::Value::Bool(_) |
|
||||||
| serde_json::Value::Number(_)
|
serde_json::Value::Number(_) |
|
||||||
| serde_json::Value::Array(_) => {
|
serde_json::Value::Array(_) => {
|
||||||
anyhow::bail!("Unsupported type of metadata {metadata:?}")
|
anyhow::bail!("Unsupported type of metadata {metadata:?}")
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
let solc_metadata =
|
let solc_metadata =
|
||||||
serde_json::from_str::<serde_json::Value>(solc_metadata_str).context(
|
serde_json::from_str::<serde_json::Value>(solc_metadata_str).context(
|
||||||
@@ -304,7 +297,7 @@ impl SolidityCompiler for Resolc {
|
|||||||
optimize_setting: ModeOptimizerSetting,
|
optimize_setting: ModeOptimizerSetting,
|
||||||
pipeline: ModePipeline,
|
pipeline: ModePipeline,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
pipeline == ModePipeline::ViaYulIR
|
pipeline == ModePipeline::ViaYulIR &&
|
||||||
&& SolidityCompiler::supports_mode(&self.0.solc, optimize_setting, pipeline)
|
SolidityCompiler::supports_mode(&self.0.solc, optimize_setting, pipeline)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,9 +56,7 @@ 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
|
let version = version.into().unwrap_or_else(|| solc_configuration.version.clone().into());
|
||||||
.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
|
||||||
@@ -72,10 +70,7 @@ impl Solc {
|
|||||||
solc_version = %version,
|
solc_version = %version,
|
||||||
"Created a new solc compiler object"
|
"Created a new solc compiler object"
|
||||||
);
|
);
|
||||||
Self(Arc::new(SolcInner {
|
Self(Arc::new(SolcInner { solc_path: path, solc_version: version }))
|
||||||
solc_path: path,
|
|
||||||
solc_version: version,
|
|
||||||
}))
|
|
||||||
})
|
})
|
||||||
.clone())
|
.clone())
|
||||||
}
|
}
|
||||||
@@ -252,10 +247,7 @@ 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!(
|
format!("Failed to canonicalize contract path {}", contract_path.display())
|
||||||
"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() {
|
||||||
@@ -286,8 +278,8 @@ impl SolidityCompiler for Solc {
|
|||||||
// solc 0.8.13 and above supports --via-ir, and less than that does not. Thus, we support
|
// solc 0.8.13 and above supports --via-ir, and less than that does not. Thus, we support
|
||||||
// mode E (ie no Yul IR) in either case, but only support Y (via Yul IR) if the compiler
|
// mode E (ie no Yul IR) in either case, but only support Y (via Yul IR) if the compiler
|
||||||
// is new enough.
|
// is new enough.
|
||||||
pipeline == ModePipeline::ViaEVMAssembly
|
pipeline == ModePipeline::ViaEVMAssembly ||
|
||||||
|| (pipeline == ModePipeline::ViaYulIR && self.compiler_supports_yul())
|
(pipeline == ModePipeline::ViaYulIR && self.compiler_supports_yul())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -154,7 +154,7 @@ impl AsRef<GenesisConfiguration> for Context {
|
|||||||
Self::Benchmark(..) => {
|
Self::Benchmark(..) => {
|
||||||
static GENESIS: LazyLock<GenesisConfiguration> = LazyLock::new(Default::default);
|
static GENESIS: LazyLock<GenesisConfiguration> = LazyLock::new(Default::default);
|
||||||
&GENESIS
|
&GENESIS
|
||||||
}
|
},
|
||||||
Self::ExportJsonSchema => unreachable!(),
|
Self::ExportJsonSchema => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -626,11 +626,7 @@ pub struct KurtosisConfiguration {
|
|||||||
///
|
///
|
||||||
/// If this is not specified, then the tool assumes that it should use the kurtosis binary
|
/// If this is not specified, then the tool assumes that it should use the kurtosis binary
|
||||||
/// that's provided in the user's $PATH.
|
/// that's provided in the user's $PATH.
|
||||||
#[clap(
|
#[clap(id = "kurtosis.path", long = "kurtosis.path", default_value = "kurtosis")]
|
||||||
id = "kurtosis.path",
|
|
||||||
long = "kurtosis.path",
|
|
||||||
default_value = "kurtosis"
|
|
||||||
)]
|
|
||||||
pub path: PathBuf,
|
pub path: PathBuf,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -641,11 +637,7 @@ pub struct KitchensinkConfiguration {
|
|||||||
///
|
///
|
||||||
/// If this is not specified, then the tool assumes that it should use the kitchensink binary
|
/// 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(
|
#[clap(id = "kitchensink.path", long = "kitchensink.path", default_value = "substrate-node")]
|
||||||
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.
|
||||||
@@ -731,11 +723,11 @@ impl GenesisConfiguration {
|
|||||||
Some(genesis_path) => {
|
Some(genesis_path) => {
|
||||||
let genesis_content = read_to_string(genesis_path)?;
|
let genesis_content = read_to_string(genesis_path)?;
|
||||||
serde_json::from_str(genesis_content.as_str())?
|
serde_json::from_str(genesis_content.as_str())?
|
||||||
}
|
},
|
||||||
None => DEFAULT_GENESIS.clone(),
|
None => DEFAULT_GENESIS.clone(),
|
||||||
};
|
};
|
||||||
Ok(self.genesis.get_or_init(|| genesis))
|
Ok(self.genesis.get_or_init(|| genesis))
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -823,10 +815,7 @@ 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(
|
false => Some(self.number_concurrent_tasks.unwrap_or(20 * self.number_of_nodes)),
|
||||||
self.number_concurrent_tasks
|
|
||||||
.unwrap_or(20 * self.number_of_nodes),
|
|
||||||
),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -917,9 +906,7 @@ impl Serialize for WorkingDirectoryConfiguration {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn parse_duration(s: &str) -> anyhow::Result<Duration> {
|
fn parse_duration(s: &str) -> anyhow::Result<Duration> {
|
||||||
u64::from_str(s)
|
u64::from_str(s).map(Duration::from_millis).map_err(Into::into)
|
||||||
.map(Duration::from_millis)
|
|
||||||
.map_err(Into::into)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The Solidity compatible node implementation.
|
/// The Solidity compatible node implementation.
|
||||||
|
|||||||
@@ -206,9 +206,7 @@ where
|
|||||||
"Deployed library"
|
"Deployed library"
|
||||||
);
|
);
|
||||||
|
|
||||||
let library_address = receipt
|
let library_address = receipt.contract_address.expect("Failed to deploy the library");
|
||||||
.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(),
|
||||||
@@ -236,10 +234,8 @@ where
|
|||||||
})
|
})
|
||||||
.context("Failed to compile the post-link contracts")?;
|
.context("Failed to compile the post-link contracts")?;
|
||||||
|
|
||||||
self.execution_state = ExecutionState::new(
|
self.execution_state =
|
||||||
compiler_output.contracts,
|
ExecutionState::new(compiler_output.contracts, deployed_libraries.unwrap_or_default());
|
||||||
deployed_libraries.unwrap_or_default(),
|
|
||||||
);
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -325,11 +321,7 @@ 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
|
if !self.execution_state.deployed_contracts.contains_key(&instance) {
|
||||||
.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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -341,15 +333,11 @@ 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
|
let value = deploy_with_constructor_arguments.then_some(step.value).flatten();
|
||||||
.then_some(step.value)
|
|
||||||
.flatten();
|
|
||||||
|
|
||||||
let caller = {
|
let caller = {
|
||||||
let context = self.default_resolution_context();
|
let context = self.default_resolution_context();
|
||||||
step.caller
|
step.caller.resolve_address(self.resolver.as_ref(), context).await?
|
||||||
.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)
|
||||||
@@ -379,7 +367,7 @@ where
|
|||||||
.as_transaction(self.resolver.as_ref(), self.default_resolution_context())
|
.as_transaction(self.resolver.as_ref(), self.default_resolution_context())
|
||||||
.await?;
|
.await?;
|
||||||
self.execute_transaction(tx).await
|
self.execute_transaction(tx).await
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -424,18 +412,13 @@ where
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Handling the return data variable assignments.
|
// Handling the return data variable assignments.
|
||||||
for (variable_name, output_word) in assignments.return_data.iter().zip(
|
for (variable_name, output_word) in assignments
|
||||||
tracing_result
|
.return_data
|
||||||
.output
|
.iter()
|
||||||
.as_ref()
|
.zip(tracing_result.output.as_ref().unwrap_or_default().to_vec().chunks(32))
|
||||||
.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
|
self.execution_state.variables.insert(variable_name.clone(), value);
|
||||||
.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>()),
|
||||||
@@ -503,9 +486,7 @@ where
|
|||||||
// receipt and how this would impact the architecture and the possibility of us not waiting
|
// receipt and how this would impact the architecture and the possibility of us not waiting
|
||||||
// for receipts in the future.
|
// for receipts in the future.
|
||||||
self.watcher_tx
|
self.watcher_tx
|
||||||
.send(WatcherEvent::RepetitionStartEvent {
|
.send(WatcherEvent::RepetitionStartEvent { ignore_block_before: 0 })
|
||||||
ignore_block_before: 0,
|
|
||||||
})
|
|
||||||
.context("Failed to send message on the watcher's tx")?;
|
.context("Failed to send message on the watcher's tx")?;
|
||||||
|
|
||||||
let res = futures::future::try_join_all(tasks)
|
let res = futures::future::try_join_all(tasks)
|
||||||
@@ -533,9 +514,7 @@ 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
|
self.execution_state.variables.insert(variable_name.to_string(), variable);
|
||||||
.variables
|
|
||||||
.insert(variable_name.to_string(), variable);
|
|
||||||
|
|
||||||
Ok(1)
|
Ok(1)
|
||||||
}
|
}
|
||||||
@@ -560,10 +539,8 @@ 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)) = self
|
if let Some((_, address, abi)) =
|
||||||
.execution_state
|
self.execution_state.deployed_contracts.get(contract_instance)
|
||||||
.deployed_contracts
|
|
||||||
.get(contract_instance)
|
|
||||||
{
|
{
|
||||||
info!(
|
info!(
|
||||||
|
|
||||||
@@ -603,19 +580,10 @@ where
|
|||||||
calldata: Option<&Calldata>,
|
calldata: Option<&Calldata>,
|
||||||
value: Option<EtherValue>,
|
value: Option<EtherValue>,
|
||||||
) -> Result<(Address, JsonAbi, TransactionReceipt)> {
|
) -> Result<(Address, JsonAbi, TransactionReceipt)> {
|
||||||
let Some(ContractPathAndIdent {
|
let Some(ContractPathAndIdent { contract_source_path, contract_ident }) =
|
||||||
contract_source_path,
|
self.test_definition.metadata.contract_sources()?.remove(contract_instance)
|
||||||
contract_ident,
|
|
||||||
}) = self
|
|
||||||
.test_definition
|
|
||||||
.metadata
|
|
||||||
.contract_sources()?
|
|
||||||
.remove(contract_instance)
|
|
||||||
else {
|
else {
|
||||||
anyhow::bail!(
|
anyhow::bail!("Contract source not found for instance {:?}", contract_instance)
|
||||||
"Contract source not found for instance {:?}",
|
|
||||||
contract_instance
|
|
||||||
)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let Some((code, abi)) = self
|
let Some((code, abi)) = self
|
||||||
@@ -625,10 +593,7 @@ 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!(
|
anyhow::bail!("Failed to find information for contract {:?}", contract_instance)
|
||||||
"Failed to find information for contract {:?}",
|
|
||||||
contract_instance
|
|
||||||
)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut code = match alloy::hex::decode(&code) {
|
let mut code = match alloy::hex::decode(&code) {
|
||||||
@@ -641,7 +606,7 @@ where
|
|||||||
"Failed to hex-decode byte code - This could possibly mean that the bytecode requires linking"
|
"Failed to hex-decode byte code - This could possibly mean that the bytecode requires linking"
|
||||||
);
|
);
|
||||||
anyhow::bail!("Failed to hex-decode the byte code {}", error)
|
anyhow::bail!("Failed to hex-decode the byte code {}", error)
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(calldata) = calldata {
|
if let Some(calldata) = calldata {
|
||||||
@@ -665,7 +630,7 @@ where
|
|||||||
Err(error) => {
|
Err(error) => {
|
||||||
tracing::error!(?error, "Contract deployment transaction failed.");
|
tracing::error!(?error, "Contract deployment transaction failed.");
|
||||||
return Err(error);
|
return Err(error);
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
let Some(address) = receipt.contract_address else {
|
let Some(address) = receipt.contract_address else {
|
||||||
@@ -680,10 +645,9 @@ where
|
|||||||
.reporter
|
.reporter
|
||||||
.report_contract_deployed_event(contract_instance.clone(), address)?;
|
.report_contract_deployed_event(contract_instance.clone(), address)?;
|
||||||
|
|
||||||
self.execution_state.deployed_contracts.insert(
|
self.execution_state
|
||||||
contract_instance.clone(),
|
.deployed_contracts
|
||||||
(contract_ident, address, abi.clone()),
|
.insert(contract_instance.clone(), (contract_ident, address, abi.clone()));
|
||||||
);
|
|
||||||
|
|
||||||
Ok((address, abi, receipt))
|
Ok((address, abi, receipt))
|
||||||
}
|
}
|
||||||
@@ -696,9 +660,7 @@ 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
|
let Some(instance) = resolvable.strip_suffix(".address").map(ContractInstance::new)
|
||||||
.strip_suffix(".address")
|
|
||||||
.map(ContractInstance::new)
|
|
||||||
else {
|
else {
|
||||||
bail!("Not an address variable");
|
bail!("Not an address variable");
|
||||||
};
|
};
|
||||||
@@ -711,7 +673,7 @@ where
|
|||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.map(|v| v.0)
|
.map(|v| v.0)
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// endregion:Contract Deployment
|
// endregion:Contract Deployment
|
||||||
@@ -757,7 +719,7 @@ where
|
|||||||
Ok(receipt) => {
|
Ok(receipt) => {
|
||||||
info!("Polling succeeded, receipt found");
|
info!("Polling succeeded, receipt found");
|
||||||
Ok(ControlFlow::Break(receipt))
|
Ok(ControlFlow::Break(receipt))
|
||||||
}
|
},
|
||||||
Err(_) => Ok(ControlFlow::Continue(())),
|
Err(_) => Ok(ControlFlow::Continue(())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -96,13 +96,8 @@ 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
|
context.working_directory.as_path().join("compilation_cache"),
|
||||||
.working_directory
|
context.compilation_configuration.invalidate_compilation_cache,
|
||||||
.as_path()
|
|
||||||
.join("compilation_cache"),
|
|
||||||
context
|
|
||||||
.compilation_configuration
|
|
||||||
.invalidate_compilation_cache,
|
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.map(Arc::new)
|
.map(Arc::new)
|
||||||
@@ -161,9 +156,7 @@ 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
|
watcher_tx.send(WatcherEvent::AllTransactionsSubmitted).unwrap()
|
||||||
.send(WatcherEvent::AllTransactionsSubmitted)
|
|
||||||
.unwrap()
|
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
|
|||||||
@@ -27,11 +27,7 @@ impl ExecutionState {
|
|||||||
compiled_contracts: HashMap<PathBuf, HashMap<String, (String, JsonAbi)>>,
|
compiled_contracts: HashMap<PathBuf, HashMap<String, (String, JsonAbi)>>,
|
||||||
deployed_contracts: HashMap<ContractInstance, (ContractIdent, Address, JsonAbi)>,
|
deployed_contracts: HashMap<ContractInstance, (ContractIdent, Address, JsonAbi)>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self { compiled_contracts, deployed_contracts, variables: Default::default() }
|
||||||
compiled_contracts,
|
|
||||||
deployed_contracts,
|
|
||||||
variables: Default::default(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn empty() -> Self {
|
pub fn empty() -> Self {
|
||||||
|
|||||||
@@ -33,14 +33,7 @@ impl Watcher {
|
|||||||
blocks_stream: Pin<Box<dyn Stream<Item = MinedBlockInformation>>>,
|
blocks_stream: Pin<Box<dyn Stream<Item = MinedBlockInformation>>>,
|
||||||
) -> (Self, UnboundedSender<WatcherEvent>) {
|
) -> (Self, UnboundedSender<WatcherEvent>) {
|
||||||
let (tx, rx) = unbounded_channel::<WatcherEvent>();
|
let (tx, rx) = unbounded_channel::<WatcherEvent>();
|
||||||
(
|
(Self { platform_identifier, rx, blocks_stream }, tx)
|
||||||
Self {
|
|
||||||
platform_identifier,
|
|
||||||
rx,
|
|
||||||
blocks_stream,
|
|
||||||
},
|
|
||||||
tx,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[instrument(level = "info", skip_all)]
|
#[instrument(level = "info", skip_all)]
|
||||||
@@ -49,9 +42,8 @@ impl Watcher {
|
|||||||
// the watcher of the last block number that it should ignore and what the block number is
|
// the watcher of the last block number that it should ignore and what the block number is
|
||||||
// for the first important block that it should look for.
|
// for the first important block that it should look for.
|
||||||
let ignore_block_before = loop {
|
let ignore_block_before = loop {
|
||||||
let Some(WatcherEvent::RepetitionStartEvent {
|
let Some(WatcherEvent::RepetitionStartEvent { ignore_block_before }) =
|
||||||
ignore_block_before,
|
self.rx.recv().await
|
||||||
}) = self.rx.recv().await
|
|
||||||
else {
|
else {
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
@@ -80,19 +72,16 @@ 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 } => {
|
WatcherEvent::SubmittedTransaction { transaction_hash } => {
|
||||||
watch_for_transaction_hashes
|
watch_for_transaction_hashes.write().await.insert(transaction_hash);
|
||||||
.write()
|
},
|
||||||
.await
|
|
||||||
.insert(transaction_hash);
|
|
||||||
}
|
|
||||||
WatcherEvent::AllTransactionsSubmitted => {
|
WatcherEvent::AllTransactionsSubmitted => {
|
||||||
*all_transactions_submitted.write().await = true;
|
*all_transactions_submitted.write().await = true;
|
||||||
self.rx.close();
|
self.rx.close();
|
||||||
info!("Watcher's Events Watching Task Finished");
|
info!("Watcher's Events Watching Task Finished");
|
||||||
break;
|
break;
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -111,8 +100,8 @@ impl Watcher {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if *all_transactions_submitted.read().await
|
if *all_transactions_submitted.read().await &&
|
||||||
&& watch_for_transaction_hashes.read().await.is_empty()
|
watch_for_transaction_hashes.read().await.is_empty()
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -151,15 +140,8 @@ 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!(
|
writeln!(stderr, "Watcher information for {}", self.platform_identifier)?;
|
||||||
stderr,
|
writeln!(stderr, "block_number,block_timestamp,mined_gas,block_gas_limit,tx_count")?;
|
||||||
"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,
|
||||||
|
|||||||
@@ -112,9 +112,7 @@ 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
|
platform_drivers.into_values().map(|driver| driver.execute_all()),
|
||||||
.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")?;
|
||||||
@@ -252,11 +250,8 @@ where
|
|||||||
TransactionRequest::default().from(deployer_address),
|
TransactionRequest::default().from(deployer_address),
|
||||||
code,
|
code,
|
||||||
);
|
);
|
||||||
let receipt = platform_information
|
let receipt =
|
||||||
.node
|
platform_information.node.execute_transaction(tx).await.inspect_err(|err| {
|
||||||
.execute_transaction(tx)
|
|
||||||
.await
|
|
||||||
.inspect_err(|err| {
|
|
||||||
error!(
|
error!(
|
||||||
?err,
|
?err,
|
||||||
%library_instance,
|
%library_instance,
|
||||||
@@ -265,9 +260,7 @@ where
|
|||||||
)
|
)
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
let library_address = receipt
|
let library_address = receipt.contract_address.expect("Failed to deploy the library");
|
||||||
.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(),
|
||||||
@@ -295,10 +288,7 @@ where
|
|||||||
})
|
})
|
||||||
.context("Failed to compile the post-link contracts")?;
|
.context("Failed to compile the post-link contracts")?;
|
||||||
|
|
||||||
Ok(ExecutionState::new(
|
Ok(ExecutionState::new(compiler_output.contracts, deployed_libraries.unwrap_or_default()))
|
||||||
compiler_output.contracts,
|
|
||||||
deployed_libraries.unwrap_or_default(),
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
// endregion:Constructors & Initialization
|
// endregion:Constructors & Initialization
|
||||||
|
|
||||||
@@ -364,14 +354,31 @@ where
|
|||||||
_: &StepPath,
|
_: &StepPath,
|
||||||
step: &FunctionCallStep,
|
step: &FunctionCallStep,
|
||||||
) -> Result<usize> {
|
) -> Result<usize> {
|
||||||
|
// Check if this step expects an exception
|
||||||
|
let expects_exception = step.expected.as_ref().map_or(false, |expected| match expected {
|
||||||
|
Expected::Expected(exp) => exp.exception,
|
||||||
|
Expected::ExpectedMany(exps) => exps.iter().any(|exp| exp.exception),
|
||||||
|
Expected::Calldata(_) => false,
|
||||||
|
});
|
||||||
|
|
||||||
let deployment_receipts = self
|
let deployment_receipts = self
|
||||||
.handle_function_call_contract_deployment(step)
|
.handle_function_call_contract_deployment(step)
|
||||||
.await
|
.await
|
||||||
.context("Failed to deploy contracts for the function call step")?;
|
.context("Failed to deploy contracts for the function call step")?;
|
||||||
let execution_receipt = self
|
|
||||||
.handle_function_call_execution(step, deployment_receipts)
|
let execution_receipt =
|
||||||
.await
|
match self.handle_function_call_execution(step, deployment_receipts).await {
|
||||||
.context("Failed to handle the function call execution")?;
|
Ok(receipt) => Some(receipt),
|
||||||
|
Err(err) => {
|
||||||
|
if !expects_exception {
|
||||||
|
return Err(err).context("Failed to handle the function call execution");
|
||||||
|
}
|
||||||
|
tracing::info!("Transaction failed as expected");
|
||||||
|
None
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(execution_receipt) = execution_receipt {
|
||||||
let tracing_result = self
|
let tracing_result = self
|
||||||
.handle_function_call_call_frame_tracing(execution_receipt.transaction_hash)
|
.handle_function_call_call_frame_tracing(execution_receipt.transaction_hash)
|
||||||
.await
|
.await
|
||||||
@@ -382,6 +389,8 @@ where
|
|||||||
self.handle_function_call_assertions(step, &execution_receipt, &tracing_result)
|
self.handle_function_call_assertions(step, &execution_receipt, &tracing_result)
|
||||||
.await
|
.await
|
||||||
.context("Failed to handle function call assertions")?;
|
.context("Failed to handle function call assertions")?;
|
||||||
|
}
|
||||||
|
|
||||||
Ok(1)
|
Ok(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -392,11 +401,7 @@ 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
|
if !self.execution_state.deployed_contracts.contains_key(&instance) {
|
||||||
.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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -408,20 +413,13 @@ 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
|
let value = deploy_with_constructor_arguments.then_some(step.value).flatten();
|
||||||
.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
|
let resolved = step.caller.resolve_address(resolver.as_ref(), context).await?;
|
||||||
.caller
|
self.platform_information.node.resolve_signer_or_default(resolved)
|
||||||
.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)
|
||||||
@@ -456,20 +454,16 @@ where
|
|||||||
Ok(tx) => tx,
|
Ok(tx) => tx,
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
return Err(err);
|
return Err(err);
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
// 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(
|
tx.from = Some(self.platform_information.node.resolve_signer_or_default(from));
|
||||||
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
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -516,18 +510,13 @@ where
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Handling the return data variable assignments.
|
// Handling the return data variable assignments.
|
||||||
for (variable_name, output_word) in assignments.return_data.iter().zip(
|
for (variable_name, output_word) in assignments
|
||||||
tracing_result
|
.return_data
|
||||||
.output
|
.iter()
|
||||||
.as_ref()
|
.zip(tracing_result.output.as_ref().unwrap_or_default().to_vec().chunks(32))
|
||||||
.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
|
self.execution_state.variables.insert(variable_name.clone(), value);
|
||||||
.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>()),
|
||||||
@@ -547,18 +536,12 @@ where
|
|||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
// Resolving the `step.expected` into a series of expectations that we can then assert on.
|
// Resolving the `step.expected` into a series of expectations that we can then assert on.
|
||||||
let mut expectations = match step {
|
let mut expectations = match step {
|
||||||
FunctionCallStep {
|
FunctionCallStep { expected: Some(Expected::Calldata(calldata)), .. } =>
|
||||||
expected: Some(Expected::Calldata(calldata)),
|
vec![ExpectedOutput::new().with_calldata(calldata.clone())],
|
||||||
..
|
FunctionCallStep { expected: Some(Expected::Expected(expected)), .. } =>
|
||||||
} => vec![ExpectedOutput::new().with_calldata(calldata.clone())],
|
vec![expected.clone()],
|
||||||
FunctionCallStep {
|
FunctionCallStep { expected: Some(Expected::ExpectedMany(expected)), .. } =>
|
||||||
expected: Some(Expected::Expected(expected)),
|
expected.clone(),
|
||||||
..
|
|
||||||
} => vec![expected.clone()],
|
|
||||||
FunctionCallStep {
|
|
||||||
expected: Some(Expected::ExpectedMany(expected)),
|
|
||||||
..
|
|
||||||
} => expected.clone(),
|
|
||||||
FunctionCallStep { expected: None, .. } => vec![ExpectedOutput::new().with_success()],
|
FunctionCallStep { expected: None, .. } => vec![ExpectedOutput::new().with_success()],
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -677,11 +660,8 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Handling the topics assertion.
|
// Handling the topics assertion.
|
||||||
for (expected, actual) in expected_event
|
for (expected, actual) in
|
||||||
.topics
|
expected_event.topics.as_slice().iter().zip(actual_event.topics())
|
||||||
.as_slice()
|
|
||||||
.iter()
|
|
||||||
.zip(actual_event.topics())
|
|
||||||
{
|
{
|
||||||
let expected = Calldata::new_compound([expected]);
|
let expected = Calldata::new_compound([expected]);
|
||||||
if !expected
|
if !expected
|
||||||
@@ -851,9 +831,7 @@ 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
|
self.execution_state.variables.insert(variable_name.to_string(), variable);
|
||||||
.variables
|
|
||||||
.insert(variable_name.to_string(), variable);
|
|
||||||
|
|
||||||
Ok(1)
|
Ok(1)
|
||||||
}
|
}
|
||||||
@@ -876,10 +854,8 @@ 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)) = self
|
if let Some((_, address, abi)) =
|
||||||
.execution_state
|
self.execution_state.deployed_contracts.get(contract_instance)
|
||||||
.deployed_contracts
|
|
||||||
.get(contract_instance)
|
|
||||||
{
|
{
|
||||||
info!(
|
info!(
|
||||||
|
|
||||||
@@ -917,19 +893,10 @@ where
|
|||||||
calldata: Option<&Calldata>,
|
calldata: Option<&Calldata>,
|
||||||
value: Option<EtherValue>,
|
value: Option<EtherValue>,
|
||||||
) -> Result<(Address, JsonAbi, TransactionReceipt)> {
|
) -> Result<(Address, JsonAbi, TransactionReceipt)> {
|
||||||
let Some(ContractPathAndIdent {
|
let Some(ContractPathAndIdent { contract_source_path, contract_ident }) =
|
||||||
contract_source_path,
|
self.test_definition.metadata.contract_sources()?.remove(contract_instance)
|
||||||
contract_ident,
|
|
||||||
}) = self
|
|
||||||
.test_definition
|
|
||||||
.metadata
|
|
||||||
.contract_sources()?
|
|
||||||
.remove(contract_instance)
|
|
||||||
else {
|
else {
|
||||||
anyhow::bail!(
|
anyhow::bail!("Contract source not found for instance {:?}", contract_instance)
|
||||||
"Contract source not found for instance {:?}",
|
|
||||||
contract_instance
|
|
||||||
)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let Some((code, abi)) = self
|
let Some((code, abi)) = self
|
||||||
@@ -939,10 +906,7 @@ 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!(
|
anyhow::bail!("Failed to find information for contract {:?}", contract_instance)
|
||||||
"Failed to find information for contract {:?}",
|
|
||||||
contract_instance
|
|
||||||
)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut code = match alloy::hex::decode(&code) {
|
let mut code = match alloy::hex::decode(&code) {
|
||||||
@@ -955,22 +919,18 @@ where
|
|||||||
"Failed to hex-decode byte code - This could possibly mean that the bytecode requires linking"
|
"Failed to hex-decode byte code - This could possibly mean that the bytecode requires linking"
|
||||||
);
|
);
|
||||||
anyhow::bail!("Failed to hex-decode the byte code {}", error)
|
anyhow::bail!("Failed to hex-decode the byte code {}", error)
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
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 = calldata
|
let calldata =
|
||||||
.calldata(resolver.as_ref(), self.default_resolution_context())
|
calldata.calldata(resolver.as_ref(), self.default_resolution_context()).await?;
|
||||||
.await?;
|
|
||||||
code.extend(calldata);
|
code.extend(calldata);
|
||||||
}
|
}
|
||||||
|
|
||||||
let tx = {
|
let tx = {
|
||||||
let deployer = self
|
let deployer = self.platform_information.node.resolve_signer_or_default(deployer);
|
||||||
.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()),
|
||||||
@@ -984,7 +944,7 @@ where
|
|||||||
Err(error) => {
|
Err(error) => {
|
||||||
tracing::error!(?error, "Contract deployment transaction failed.");
|
tracing::error!(?error, "Contract deployment transaction failed.");
|
||||||
return Err(error);
|
return Err(error);
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
let Some(address) = receipt.contract_address else {
|
let Some(address) = receipt.contract_address else {
|
||||||
@@ -999,10 +959,9 @@ where
|
|||||||
.reporter
|
.reporter
|
||||||
.report_contract_deployed_event(contract_instance.clone(), address)?;
|
.report_contract_deployed_event(contract_instance.clone(), address)?;
|
||||||
|
|
||||||
self.execution_state.deployed_contracts.insert(
|
self.execution_state
|
||||||
contract_instance.clone(),
|
.deployed_contracts
|
||||||
(contract_ident, address, abi.clone()),
|
.insert(contract_instance.clone(), (contract_ident, address, abi.clone()));
|
||||||
);
|
|
||||||
|
|
||||||
Ok((address, abi, receipt))
|
Ok((address, abi, receipt))
|
||||||
}
|
}
|
||||||
@@ -1015,9 +974,7 @@ 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
|
let Some(instance) = resolvable.strip_suffix(".address").map(ContractInstance::new)
|
||||||
.strip_suffix(".address")
|
|
||||||
.map(ContractInstance::new)
|
|
||||||
else {
|
else {
|
||||||
bail!("Not an address variable");
|
bail!("Not an address variable");
|
||||||
};
|
};
|
||||||
@@ -1030,7 +987,7 @@ where
|
|||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.map(|v| v.0)
|
.map(|v| v.0)
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// endregion:Contract Deployment
|
// endregion:Contract Deployment
|
||||||
|
|||||||
@@ -85,13 +85,8 @@ 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
|
context.working_directory.as_path().join("compilation_cache"),
|
||||||
.working_directory
|
context.compilation_configuration.invalidate_compilation_cache,
|
||||||
.as_path()
|
|
||||||
.join("compilation_cache"),
|
|
||||||
context
|
|
||||||
.compilation_configuration
|
|
||||||
.invalidate_compilation_cache,
|
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.map(Arc::new)
|
.map(Arc::new)
|
||||||
@@ -146,7 +141,7 @@ pub async fn handle_differential_tests(
|
|||||||
drop(permit);
|
drop(permit);
|
||||||
running_task_list.write().await.remove(&test_id);
|
running_task_list.write().await.remove(&test_id);
|
||||||
return;
|
return;
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
info!("Created the driver for the test case");
|
info!("Created the driver for the test case");
|
||||||
|
|
||||||
@@ -161,7 +156,7 @@ pub async fn handle_differential_tests(
|
|||||||
.report_test_failed_event(format!("{error:#}"))
|
.report_test_failed_event(format!("{error:#}"))
|
||||||
.expect("Can't fail");
|
.expect("Can't fail");
|
||||||
error!("Test Case Failed");
|
error!("Test Case Failed");
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
info!("Finished the execution of the test case");
|
info!("Finished the execution of the test case");
|
||||||
drop(permit);
|
drop(permit);
|
||||||
@@ -172,20 +167,14 @@ pub async fn handle_differential_tests(
|
|||||||
))
|
))
|
||||||
.inspect(|_| {
|
.inspect(|_| {
|
||||||
info!("Finished executing all test cases");
|
info!("Finished executing all test cases");
|
||||||
reporter_clone
|
reporter_clone.report_completion_event().expect("Can't fail")
|
||||||
.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!(
|
info!(count = remaining_tasks.len(), ?remaining_tasks, "Remaining Tests");
|
||||||
count = remaining_tasks.len(),
|
|
||||||
?remaining_tasks,
|
|
||||||
"Remaining Tests"
|
|
||||||
);
|
|
||||||
tokio::time::sleep(Duration::from_secs(10)).await
|
tokio::time::sleep(Duration::from_secs(10)).await
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -234,7 +223,7 @@ async fn start_cli_reporting_task(reporter: Reporter) {
|
|||||||
"{}{}Case Succeeded{} - Steps Executed: {}{}",
|
"{}{}Case Succeeded{} - Steps Executed: {}{}",
|
||||||
GREEN, BOLD, BOLD_RESET, steps_executed, COLOR_RESET
|
GREEN, BOLD, BOLD_RESET, steps_executed, COLOR_RESET
|
||||||
)
|
)
|
||||||
}
|
},
|
||||||
TestCaseStatus::Failed { reason } => {
|
TestCaseStatus::Failed { reason } => {
|
||||||
number_of_failures += 1;
|
number_of_failures += 1;
|
||||||
writeln!(
|
writeln!(
|
||||||
@@ -246,7 +235,7 @@ async fn start_cli_reporting_task(reporter: Reporter) {
|
|||||||
reason.trim(),
|
reason.trim(),
|
||||||
COLOR_RESET,
|
COLOR_RESET,
|
||||||
)
|
)
|
||||||
}
|
},
|
||||||
TestCaseStatus::Ignored { reason, .. } => writeln!(
|
TestCaseStatus::Ignored { reason, .. } => writeln!(
|
||||||
buf,
|
buf,
|
||||||
"{}{}Case Ignored{} - Reason: {}{}",
|
"{}{}Case Ignored{} - Reason: {}{}",
|
||||||
|
|||||||
@@ -27,10 +27,6 @@ impl ExecutionState {
|
|||||||
compiled_contracts: HashMap<PathBuf, HashMap<String, (String, JsonAbi)>>,
|
compiled_contracts: HashMap<PathBuf, HashMap<String, (String, JsonAbi)>>,
|
||||||
deployed_contracts: HashMap<ContractInstance, (ContractIdent, Address, JsonAbi)>,
|
deployed_contracts: HashMap<ContractInstance, (ContractIdent, Address, JsonAbi)>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self { compiled_contracts, deployed_contracts, variables: Default::default() }
|
||||||
compiled_contracts,
|
|
||||||
deployed_contracts,
|
|
||||||
variables: Default::default(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,10 +41,7 @@ impl<'a> CachedCompiler<'a> {
|
|||||||
.await
|
.await
|
||||||
.context("Failed to invalidate compilation cache directory")?;
|
.context("Failed to invalidate compilation cache directory")?;
|
||||||
}
|
}
|
||||||
Ok(Self {
|
Ok(Self { artifacts_cache: cache, cache_key_lock: Default::default() })
|
||||||
artifacts_cache: cache,
|
|
||||||
cache_key_lock: Default::default(),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Compiles or gets the compilation artifacts from the cache.
|
/// Compiles or gets the compilation artifacts from the cache.
|
||||||
@@ -112,7 +109,7 @@ impl<'a> CachedCompiler<'a> {
|
|||||||
.await
|
.await
|
||||||
.context("Compilation callback for deployed libraries failed")?
|
.context("Compilation callback for deployed libraries failed")?
|
||||||
.compiler_output
|
.compiler_output
|
||||||
}
|
},
|
||||||
// If no deployed libraries are specified then we can follow the cached flow and attempt
|
// If no deployed libraries are specified then we can follow the cached flow and attempt
|
||||||
// to lookup the compilation artifacts in the cache.
|
// to lookup the compilation artifacts in the cache.
|
||||||
None => {
|
None => {
|
||||||
@@ -126,7 +123,7 @@ impl<'a> CachedCompiler<'a> {
|
|||||||
Some(value) => {
|
Some(value) => {
|
||||||
drop(read_guard);
|
drop(read_guard);
|
||||||
value
|
value
|
||||||
}
|
},
|
||||||
None => {
|
None => {
|
||||||
drop(read_guard);
|
drop(read_guard);
|
||||||
self.cache_key_lock
|
self.cache_key_lock
|
||||||
@@ -135,7 +132,7 @@ impl<'a> CachedCompiler<'a> {
|
|||||||
.entry(cache_key.clone())
|
.entry(cache_key.clone())
|
||||||
.or_default()
|
.or_default()
|
||||||
.clone()
|
.clone()
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
let _guard = mutex.lock().await;
|
let _guard = mutex.lock().await;
|
||||||
|
|
||||||
@@ -163,7 +160,7 @@ impl<'a> CachedCompiler<'a> {
|
|||||||
.expect("Can't happen");
|
.expect("Can't happen");
|
||||||
}
|
}
|
||||||
cache_value.compiler_output
|
cache_value.compiler_output
|
||||||
}
|
},
|
||||||
None => {
|
None => {
|
||||||
let compiler_output = compilation_callback()
|
let compiler_output = compilation_callback()
|
||||||
.await
|
.await
|
||||||
@@ -172,18 +169,16 @@ impl<'a> CachedCompiler<'a> {
|
|||||||
self.artifacts_cache
|
self.artifacts_cache
|
||||||
.insert(
|
.insert(
|
||||||
&cache_key,
|
&cache_key,
|
||||||
&CacheValue {
|
&CacheValue { compiler_output: compiler_output.clone() },
|
||||||
compiler_output: compiler_output.clone(),
|
|
||||||
},
|
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.context(
|
.context(
|
||||||
"Failed to write the cached value of the compilation artifacts",
|
"Failed to write the cached value of the compilation artifacts",
|
||||||
)?;
|
)?;
|
||||||
compiler_output
|
compiler_output
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(compiled_contracts)
|
Ok(compiled_contracts)
|
||||||
@@ -225,9 +220,7 @@ 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
|
all_sources_in_dir.iter().map(move |path| (ident, address, path))
|
||||||
.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)
|
||||||
@@ -248,7 +241,7 @@ async fn compile_contracts(
|
|||||||
output.clone(),
|
output.clone(),
|
||||||
)
|
)
|
||||||
.expect("Can't happen");
|
.expect("Can't happen");
|
||||||
}
|
},
|
||||||
(Ok(output), false) => {
|
(Ok(output), false) => {
|
||||||
reporter
|
reporter
|
||||||
.report_pre_link_contracts_compilation_succeeded_event(
|
.report_pre_link_contracts_compilation_succeeded_event(
|
||||||
@@ -259,7 +252,7 @@ async fn compile_contracts(
|
|||||||
output.clone(),
|
output.clone(),
|
||||||
)
|
)
|
||||||
.expect("Can't happen");
|
.expect("Can't happen");
|
||||||
}
|
},
|
||||||
(Err(err), true) => {
|
(Err(err), true) => {
|
||||||
reporter
|
reporter
|
||||||
.report_post_link_contracts_compilation_failed_event(
|
.report_post_link_contracts_compilation_failed_event(
|
||||||
@@ -269,7 +262,7 @@ async fn compile_contracts(
|
|||||||
format!("{err:#}"),
|
format!("{err:#}"),
|
||||||
)
|
)
|
||||||
.expect("Can't happen");
|
.expect("Can't happen");
|
||||||
}
|
},
|
||||||
(Err(err), false) => {
|
(Err(err), false) => {
|
||||||
reporter
|
reporter
|
||||||
.report_pre_link_contracts_compilation_failed_event(
|
.report_pre_link_contracts_compilation_failed_event(
|
||||||
@@ -279,7 +272,7 @@ async fn compile_contracts(
|
|||||||
format!("{err:#}"),
|
format!("{err:#}"),
|
||||||
)
|
)
|
||||||
.expect("Can't happen");
|
.expect("Can't happen");
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
output
|
output
|
||||||
@@ -291,9 +284,7 @@ struct ArtifactsCache {
|
|||||||
|
|
||||||
impl ArtifactsCache {
|
impl ArtifactsCache {
|
||||||
pub fn new(path: impl AsRef<Path>) -> Self {
|
pub fn new(path: impl AsRef<Path>) -> Self {
|
||||||
Self {
|
Self { path: path.as_ref().to_path_buf() }
|
||||||
path: path.as_ref().to_path_buf(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[instrument(level = "debug", skip_all, err)]
|
#[instrument(level = "debug", skip_all, err)]
|
||||||
@@ -319,9 +310,7 @@ impl ArtifactsCache {
|
|||||||
|
|
||||||
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())
|
let value = cacache::read(self.path.as_path(), key.encode_hex()).await.ok()?;
|
||||||
.await
|
|
||||||
.ok()?;
|
|
||||||
let value = bson::from_slice::<CacheValue>(&value).ok()?;
|
let value = bson::from_slice::<CacheValue>(&value).ok()?;
|
||||||
Some(value)
|
Some(value)
|
||||||
}
|
}
|
||||||
@@ -336,13 +325,13 @@ impl ArtifactsCache {
|
|||||||
Some(value) => {
|
Some(value) => {
|
||||||
debug!("Cache hit");
|
debug!("Cache hit");
|
||||||
Ok(value)
|
Ok(value)
|
||||||
}
|
},
|
||||||
None => {
|
None => {
|
||||||
debug!("Cache miss");
|
debug!("Cache miss");
|
||||||
let value = callback().await?;
|
let value = callback().await?;
|
||||||
self.insert(key, &value).await?;
|
self.insert(key, &value).await?;
|
||||||
Ok(value)
|
Ok(value)
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -37,18 +37,13 @@ impl NodePool {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let pre_transactions_tasks = nodes
|
let pre_transactions_tasks =
|
||||||
.iter_mut()
|
nodes.iter_mut().map(|node| node.pre_transactions()).collect::<Vec<_>>();
|
||||||
.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")?;
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self { nodes, next: Default::default() })
|
||||||
nodes,
|
|
||||||
next: Default::default(),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get a handle to the next node.
|
/// Get a handle to the next node.
|
||||||
|
|||||||
@@ -66,15 +66,12 @@ pub async fn create_test_definitions_stream<'a>(
|
|||||||
// Inform the reporter of each one of the test cases that were discovered which we
|
// Inform the reporter of each one of the test cases that were discovered which we
|
||||||
// expect to run.
|
// expect to run.
|
||||||
.inspect(|(_, _, _, _, reporter)| {
|
.inspect(|(_, _, _, _, reporter)| {
|
||||||
reporter
|
reporter.report_test_case_discovery_event().expect("Can't fail");
|
||||||
.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(
|
.filter_map(move |(metadata_file, case_idx, case, mode, reporter)| async move {
|
||||||
move |(metadata_file, case_idx, case, mode, reporter)| async move {
|
|
||||||
let mut platforms = BTreeMap::new();
|
let mut platforms = BTreeMap::new();
|
||||||
for (platform, node_pool) in platforms_and_nodes.values() {
|
for (platform, node_pool) in platforms_and_nodes.values() {
|
||||||
let node = node_pool.round_robbin();
|
let node = node_pool.round_robbin();
|
||||||
@@ -103,12 +100,7 @@ pub async fn create_test_definitions_stream<'a>(
|
|||||||
|
|
||||||
platforms.insert(
|
platforms.insert(
|
||||||
platform.platform_identifier(),
|
platform.platform_identifier(),
|
||||||
TestPlatformInformation {
|
TestPlatformInformation { platform: *platform, node, compiler, reporter },
|
||||||
platform: *platform,
|
|
||||||
node,
|
|
||||||
compiler,
|
|
||||||
reporter,
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -130,8 +122,7 @@ pub async fn create_test_definitions_stream<'a>(
|
|||||||
/* Reporter */
|
/* Reporter */
|
||||||
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() {
|
||||||
@@ -156,7 +147,7 @@ pub async fn create_test_definitions_stream<'a>(
|
|||||||
)
|
)
|
||||||
.expect("Can't fail");
|
.expect("Can't fail");
|
||||||
None
|
None
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.inspect(|test| {
|
.inspect(|test| {
|
||||||
@@ -230,9 +221,8 @@ impl<'a> TestDefinition<'a> {
|
|||||||
for (_, platform_information) in self.platforms.iter() {
|
for (_, platform_information) in self.platforms.iter() {
|
||||||
let is_allowed_for_platform = match self.metadata.targets.as_ref() {
|
let is_allowed_for_platform = match self.metadata.targets.as_ref() {
|
||||||
None => true,
|
None => true,
|
||||||
Some(required_vm_identifiers) => {
|
Some(required_vm_identifiers) =>
|
||||||
required_vm_identifiers.contains(&platform_information.platform.vm_identifier())
|
required_vm_identifiers.contains(&platform_information.platform.vm_identifier()),
|
||||||
}
|
|
||||||
};
|
};
|
||||||
is_allowed &= is_allowed_for_platform;
|
is_allowed &= is_allowed_for_platform;
|
||||||
error_map.insert(
|
error_map.insert(
|
||||||
@@ -274,10 +264,7 @@ impl<'a> TestDefinition<'a> {
|
|||||||
if is_allowed {
|
if is_allowed {
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
Err((
|
Err(("EVM version is incompatible for the platforms specified", error_map))
|
||||||
"EVM version is incompatible for the platforms specified",
|
|
||||||
error_map,
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+38
-71
@@ -37,11 +37,7 @@ 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.
|
||||||
@@ -183,9 +179,7 @@ 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)
|
let kitchensink_path = AsRef::<KitchensinkConfiguration>::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(
|
||||||
@@ -235,9 +229,7 @@ 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)
|
let kitchensink_path = AsRef::<KitchensinkConfiguration>::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(
|
||||||
@@ -287,9 +279,8 @@ 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 = AsRef::<ReviveDevNodeConfiguration>::as_ref(&context)
|
let revive_dev_node_path =
|
||||||
.path
|
AsRef::<ReviveDevNodeConfiguration>::as_ref(&context).path.clone();
|
||||||
.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(
|
||||||
@@ -339,9 +330,8 @@ 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 = AsRef::<ReviveDevNodeConfiguration>::as_ref(&context)
|
let revive_dev_node_path =
|
||||||
.path
|
AsRef::<ReviveDevNodeConfiguration>::as_ref(&context).path.clone();
|
||||||
.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(
|
||||||
@@ -391,9 +381,8 @@ 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 = AsRef::<PolkadotParachainConfiguration>::as_ref(&context)
|
let polkadot_parachain_path =
|
||||||
.path
|
AsRef::<PolkadotParachainConfiguration>::as_ref(&context).path.clone();
|
||||||
.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);
|
||||||
@@ -439,9 +428,8 @@ 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 = AsRef::<PolkadotParachainConfiguration>::as_ref(&context)
|
let polkadot_parachain_path =
|
||||||
.path
|
AsRef::<PolkadotParachainConfiguration>::as_ref(&context).path.clone();
|
||||||
.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);
|
||||||
@@ -466,24 +454,18 @@ impl From<PlatformIdentifier> for Box<dyn Platform> {
|
|||||||
fn from(value: PlatformIdentifier) -> Self {
|
fn from(value: PlatformIdentifier) -> Self {
|
||||||
match value {
|
match value {
|
||||||
PlatformIdentifier::GethEvmSolc => Box::new(GethEvmSolcPlatform) as Box<_>,
|
PlatformIdentifier::GethEvmSolc => Box::new(GethEvmSolcPlatform) as Box<_>,
|
||||||
PlatformIdentifier::LighthouseGethEvmSolc => {
|
PlatformIdentifier::LighthouseGethEvmSolc =>
|
||||||
Box::new(LighthouseGethEvmSolcPlatform) as Box<_>
|
Box::new(LighthouseGethEvmSolcPlatform) as Box<_>,
|
||||||
}
|
PlatformIdentifier::KitchensinkPolkavmResolc =>
|
||||||
PlatformIdentifier::KitchensinkPolkavmResolc => {
|
Box::new(KitchensinkPolkavmResolcPlatform) as Box<_>,
|
||||||
Box::new(KitchensinkPolkavmResolcPlatform) as Box<_>
|
PlatformIdentifier::KitchensinkRevmSolc =>
|
||||||
}
|
Box::new(KitchensinkRevmSolcPlatform) as Box<_>,
|
||||||
PlatformIdentifier::KitchensinkRevmSolc => {
|
PlatformIdentifier::ReviveDevNodePolkavmResolc =>
|
||||||
Box::new(KitchensinkRevmSolcPlatform) as Box<_>
|
Box::new(ReviveDevNodePolkavmResolcPlatform) as Box<_>,
|
||||||
}
|
PlatformIdentifier::ReviveDevNodeRevmSolc =>
|
||||||
PlatformIdentifier::ReviveDevNodePolkavmResolc => {
|
Box::new(ReviveDevNodeRevmSolcPlatform) as Box<_>,
|
||||||
Box::new(ReviveDevNodePolkavmResolcPlatform) as Box<_>
|
PlatformIdentifier::ZombienetPolkavmResolc =>
|
||||||
}
|
Box::new(ZombienetPolkavmResolcPlatform) as Box<_>,
|
||||||
PlatformIdentifier::ReviveDevNodeRevmSolc => {
|
|
||||||
Box::new(ReviveDevNodeRevmSolcPlatform) as Box<_>
|
|
||||||
}
|
|
||||||
PlatformIdentifier::ZombienetPolkavmResolc => {
|
|
||||||
Box::new(ZombienetPolkavmResolcPlatform) as Box<_>
|
|
||||||
}
|
|
||||||
PlatformIdentifier::ZombienetRevmSolc => Box::new(ZombienetRevmSolcPlatform) as Box<_>,
|
PlatformIdentifier::ZombienetRevmSolc => Box::new(ZombienetRevmSolcPlatform) as Box<_>,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -493,24 +475,18 @@ impl From<PlatformIdentifier> for &dyn Platform {
|
|||||||
fn from(value: PlatformIdentifier) -> Self {
|
fn from(value: PlatformIdentifier) -> Self {
|
||||||
match value {
|
match value {
|
||||||
PlatformIdentifier::GethEvmSolc => &GethEvmSolcPlatform as &dyn Platform,
|
PlatformIdentifier::GethEvmSolc => &GethEvmSolcPlatform as &dyn Platform,
|
||||||
PlatformIdentifier::LighthouseGethEvmSolc => {
|
PlatformIdentifier::LighthouseGethEvmSolc =>
|
||||||
&LighthouseGethEvmSolcPlatform as &dyn Platform
|
&LighthouseGethEvmSolcPlatform as &dyn Platform,
|
||||||
}
|
PlatformIdentifier::KitchensinkPolkavmResolc =>
|
||||||
PlatformIdentifier::KitchensinkPolkavmResolc => {
|
&KitchensinkPolkavmResolcPlatform as &dyn Platform,
|
||||||
&KitchensinkPolkavmResolcPlatform as &dyn Platform
|
PlatformIdentifier::KitchensinkRevmSolc =>
|
||||||
}
|
&KitchensinkRevmSolcPlatform as &dyn Platform,
|
||||||
PlatformIdentifier::KitchensinkRevmSolc => {
|
PlatformIdentifier::ReviveDevNodePolkavmResolc =>
|
||||||
&KitchensinkRevmSolcPlatform as &dyn Platform
|
&ReviveDevNodePolkavmResolcPlatform as &dyn Platform,
|
||||||
}
|
PlatformIdentifier::ReviveDevNodeRevmSolc =>
|
||||||
PlatformIdentifier::ReviveDevNodePolkavmResolc => {
|
&ReviveDevNodeRevmSolcPlatform as &dyn Platform,
|
||||||
&ReviveDevNodePolkavmResolcPlatform as &dyn Platform
|
PlatformIdentifier::ZombienetPolkavmResolc =>
|
||||||
}
|
&ZombienetPolkavmResolcPlatform as &dyn Platform,
|
||||||
PlatformIdentifier::ReviveDevNodeRevmSolc => {
|
|
||||||
&ReviveDevNodeRevmSolcPlatform as &dyn Platform
|
|
||||||
}
|
|
||||||
PlatformIdentifier::ZombienetPolkavmResolc => {
|
|
||||||
&ZombienetPolkavmResolcPlatform as &dyn Platform
|
|
||||||
}
|
|
||||||
PlatformIdentifier::ZombienetRevmSolc => &ZombienetRevmSolcPlatform as &dyn Platform,
|
PlatformIdentifier::ZombienetRevmSolc => &ZombienetRevmSolcPlatform as &dyn Platform,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -520,17 +496,8 @@ 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!(
|
info!(id = node.id(), connection_string = node.connection_string(), "Spawning node");
|
||||||
id = node.id(),
|
node.spawn(genesis).context("Failed to spawn node process")?;
|
||||||
connection_string = node.connection_string(),
|
info!(id = node.id(), connection_string = node.connection_string(), "Spawned node");
|
||||||
"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)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -76,6 +76,6 @@ fn main() -> anyhow::Result<()> {
|
|||||||
let schema = schema_for!(Metadata);
|
let schema = schema_for!(Metadata);
|
||||||
println!("{}", serde_json::to_string_pretty(&schema).unwrap());
|
println!("{}", serde_json::to_string_pretty(&schema).unwrap());
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,11 +54,7 @@ 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
|
self.steps.clone().into_iter().enumerate().map(move |(idx, mut step)| {
|
||||||
.clone()
|
|
||||||
.into_iter()
|
|
||||||
.enumerate()
|
|
||||||
.map(move |(idx, mut step)| {
|
|
||||||
let Step::FunctionCall(ref mut input) = step else {
|
let Step::FunctionCall(ref mut input) = step else {
|
||||||
return step;
|
return step;
|
||||||
};
|
};
|
||||||
@@ -84,9 +80,7 @@ impl Case {
|
|||||||
&self,
|
&self,
|
||||||
default_repeat_count: usize,
|
default_repeat_count: usize,
|
||||||
) -> Box<dyn Iterator<Item = Step> + '_> {
|
) -> Box<dyn Iterator<Item = Step> + '_> {
|
||||||
let contains_repeat = self
|
let contains_repeat = self.steps_iterator().any(|step| matches!(&step, Step::Repeat(..)));
|
||||||
.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 {
|
||||||
|
|||||||
@@ -86,11 +86,7 @@ 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!(
|
info!(len = tests.len(), corpus_name = self.name(), "Found tests in Corpus");
|
||||||
len = tests.len(),
|
|
||||||
corpus_name = self.name(),
|
|
||||||
"Found tests in Corpus"
|
|
||||||
);
|
|
||||||
tests
|
tests
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -102,23 +98,19 @@ impl Corpus {
|
|||||||
|
|
||||||
pub fn paths_iter(&self) -> impl Iterator<Item = &Path> {
|
pub fn paths_iter(&self) -> impl Iterator<Item = &Path> {
|
||||||
match self {
|
match self {
|
||||||
Corpus::SinglePath { path, .. } => {
|
Corpus::SinglePath { 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 { paths, .. } => {
|
Box::new(paths.iter().map(|path| path.as_path())) as Box<dyn Iterator<Item = _>>,
|
||||||
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 { path, .. } => {
|
Corpus::SinglePath { 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 { paths, .. } => {
|
Box::new(paths.iter_mut()) as Box<dyn Iterator<Item = _>>,
|
||||||
Box::new(paths.iter_mut()) as Box<dyn Iterator<Item = _>>
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -44,9 +44,7 @@ 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
|
self.metadata_file_path.strip_prefix(&self.corpus_file_path).unwrap()
|
||||||
.strip_prefix(&self.corpus_file_path)
|
|
||||||
.unwrap()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -159,19 +157,10 @@ impl Metadata {
|
|||||||
return Ok(sources);
|
return Ok(sources);
|
||||||
};
|
};
|
||||||
|
|
||||||
for (
|
for (alias, ContractPathAndIdent { contract_source_path, contract_ident }) in contracts {
|
||||||
alias,
|
|
||||||
ContractPathAndIdent {
|
|
||||||
contract_source_path,
|
|
||||||
contract_ident,
|
|
||||||
},
|
|
||||||
) in contracts
|
|
||||||
{
|
|
||||||
let alias = alias.clone();
|
let alias = alias.clone();
|
||||||
let absolute_path = directory
|
let absolute_path =
|
||||||
.join(contract_source_path)
|
directory.join(contract_source_path).canonicalize().map_err(|error| {
|
||||||
.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()
|
||||||
@@ -181,10 +170,7 @@ impl Metadata {
|
|||||||
|
|
||||||
sources.insert(
|
sources.insert(
|
||||||
alias,
|
alias,
|
||||||
ContractPathAndIdent {
|
ContractPathAndIdent { contract_source_path: absolute_path, contract_ident },
|
||||||
contract_source_path: absolute_path,
|
|
||||||
contract_ident,
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -222,11 +208,11 @@ impl Metadata {
|
|||||||
Ok(mut metadata) => {
|
Ok(mut metadata) => {
|
||||||
metadata.file_path = Some(path.to_path_buf());
|
metadata.file_path = Some(path.to_path_buf());
|
||||||
Some(metadata)
|
Some(metadata)
|
||||||
}
|
},
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
error!(path = %path.display(), %err, "Deserialization of metadata failed");
|
error!(path = %path.display(), %err, "Deserialization of metadata failed");
|
||||||
None
|
None
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -259,11 +245,11 @@ impl Metadata {
|
|||||||
.into(),
|
.into(),
|
||||||
);
|
);
|
||||||
Some(metadata)
|
Some(metadata)
|
||||||
}
|
},
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
error!(path = %path.display(), %err, "Failed to deserialize metadata");
|
error!(path = %path.display(), %err, "Failed to deserialize metadata");
|
||||||
None
|
None
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -337,12 +323,7 @@ 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!(
|
write!(f, "{}:{}", self.contract_source_path.display(), self.contract_ident.as_ref())
|
||||||
f,
|
|
||||||
"{}:{}",
|
|
||||||
self.contract_source_path.display(),
|
|
||||||
self.contract_ident.as_ref()
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -362,7 +343,7 @@ impl FromStr for ContractPathAndIdent {
|
|||||||
Some(ref mut path) => {
|
Some(ref mut path) => {
|
||||||
path.push(':');
|
path.push(':');
|
||||||
path.push_str(next_item);
|
path.push_str(next_item);
|
||||||
}
|
},
|
||||||
None => path = Some(next_item.to_owned()),
|
None => path = Some(next_item.to_owned()),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -382,7 +363,7 @@ impl FromStr for ContractPathAndIdent {
|
|||||||
contract_source_path: PathBuf::from(path),
|
contract_source_path: PathBuf::from(path),
|
||||||
contract_ident: ContractIdent::new(identifier),
|
contract_ident: ContractIdent::new(identifier),
|
||||||
})
|
})
|
||||||
}
|
},
|
||||||
(None, None) => anyhow::bail!("Failed to find the path and identifier"),
|
(None, None) => anyhow::bail!("Failed to find the path and identifier"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -420,43 +401,23 @@ pub struct EvmVersionRequirement {
|
|||||||
|
|
||||||
impl EvmVersionRequirement {
|
impl EvmVersionRequirement {
|
||||||
pub fn new_greater_than_or_equals(version: EVMVersion) -> Self {
|
pub fn new_greater_than_or_equals(version: EVMVersion) -> Self {
|
||||||
Self {
|
Self { ordering: Ordering::Greater, or_equal: true, evm_version: version }
|
||||||
ordering: Ordering::Greater,
|
|
||||||
or_equal: true,
|
|
||||||
evm_version: version,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_greater_than(version: EVMVersion) -> Self {
|
pub fn new_greater_than(version: EVMVersion) -> Self {
|
||||||
Self {
|
Self { ordering: Ordering::Greater, or_equal: false, evm_version: version }
|
||||||
ordering: Ordering::Greater,
|
|
||||||
or_equal: false,
|
|
||||||
evm_version: version,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_equals(version: EVMVersion) -> Self {
|
pub fn new_equals(version: EVMVersion) -> Self {
|
||||||
Self {
|
Self { ordering: Ordering::Equal, or_equal: false, evm_version: version }
|
||||||
ordering: Ordering::Equal,
|
|
||||||
or_equal: false,
|
|
||||||
evm_version: version,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_less_than(version: EVMVersion) -> Self {
|
pub fn new_less_than(version: EVMVersion) -> Self {
|
||||||
Self {
|
Self { ordering: Ordering::Less, or_equal: false, evm_version: version }
|
||||||
ordering: Ordering::Less,
|
|
||||||
or_equal: false,
|
|
||||||
evm_version: version,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_less_than_or_equals(version: EVMVersion) -> Self {
|
pub fn new_less_than_or_equals(version: EVMVersion) -> Self {
|
||||||
Self {
|
Self { ordering: Ordering::Less, or_equal: true, evm_version: version }
|
||||||
ordering: Ordering::Less,
|
|
||||||
or_equal: true,
|
|
||||||
evm_version: version,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn matches(&self, other: &EVMVersion) -> bool {
|
pub fn matches(&self, other: &EVMVersion) -> bool {
|
||||||
@@ -467,11 +428,7 @@ impl EvmVersionRequirement {
|
|||||||
|
|
||||||
impl Display for EvmVersionRequirement {
|
impl Display for EvmVersionRequirement {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
let Self {
|
let Self { ordering, or_equal, evm_version } = self;
|
||||||
ordering,
|
|
||||||
or_equal,
|
|
||||||
evm_version,
|
|
||||||
} = self;
|
|
||||||
match ordering {
|
match ordering {
|
||||||
Ordering::Less => write!(f, "<")?,
|
Ordering::Less => write!(f, "<")?,
|
||||||
Ordering::Equal => write!(f, "=")?,
|
Ordering::Equal => write!(f, "=")?,
|
||||||
@@ -598,10 +555,7 @@ mod test {
|
|||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
let identifier = identifier.expect("Failed to parse");
|
let identifier = identifier.expect("Failed to parse");
|
||||||
assert_eq!(
|
assert_eq!(identifier.contract_source_path.display().to_string(), "ERC20/ERC20.sol");
|
||||||
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
|
||||||
|
|||||||
@@ -77,12 +77,7 @@ impl FromStr for ParsedMode {
|
|||||||
None => None,
|
None => None,
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(ParsedMode {
|
Ok(ParsedMode { pipeline, optimize_flag, optimize_setting, version })
|
||||||
pipeline,
|
|
||||||
optimize_flag,
|
|
||||||
optimize_setting,
|
|
||||||
version,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -138,13 +133,9 @@ impl ParsedMode {
|
|||||||
|p| EitherIter::B(std::iter::once(*p)),
|
|p| EitherIter::B(std::iter::once(*p)),
|
||||||
);
|
);
|
||||||
|
|
||||||
let optimize_flag_setting = self.optimize_flag.map(|flag| {
|
let optimize_flag_setting = self
|
||||||
if flag {
|
.optimize_flag
|
||||||
ModeOptimizerSetting::M3
|
.map(|flag| if flag { ModeOptimizerSetting::M3 } else { ModeOptimizerSetting::M0 });
|
||||||
} else {
|
|
||||||
ModeOptimizerSetting::M0
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
let optimize_flag_iter = match optimize_flag_setting {
|
let optimize_flag_iter = match optimize_flag_setting {
|
||||||
Some(setting) => EitherIter::A(std::iter::once(setting)),
|
Some(setting) => EitherIter::A(std::iter::once(setting)),
|
||||||
@@ -157,9 +148,7 @@ impl ParsedMode {
|
|||||||
);
|
);
|
||||||
|
|
||||||
pipeline_iter.flat_map(move |pipeline| {
|
pipeline_iter.flat_map(move |pipeline| {
|
||||||
optimize_settings_iter
|
optimize_settings_iter.clone().map(move |optimize_setting| Mode {
|
||||||
.clone()
|
|
||||||
.map(move |optimize_setting| Mode {
|
|
||||||
pipeline,
|
pipeline,
|
||||||
optimize_setting,
|
optimize_setting,
|
||||||
version: self.version.clone(),
|
version: self.version.clone(),
|
||||||
@@ -235,10 +224,7 @@ 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 {
|
||||||
|
|||||||
+32
-106
@@ -78,12 +78,7 @@ 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
|
self.0.iter().map(|idx| idx.to_string()).collect::<Vec<_>>().join(".").fmt(f)
|
||||||
.iter()
|
|
||||||
.map(|idx| idx.to_string())
|
|
||||||
.collect::<Vec<_>>()
|
|
||||||
.join(".")
|
|
||||||
.fmt(f)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -456,9 +451,7 @@ impl StepAddress {
|
|||||||
|
|
||||||
impl FunctionCallStep {
|
impl FunctionCallStep {
|
||||||
pub const fn default_caller_address() -> Address {
|
pub const fn default_caller_address() -> Address {
|
||||||
Address(FixedBytes(alloy::hex!(
|
Address(FixedBytes(alloy::hex!("0x90F8bf6A479f320ead074411a4B0e7944Ea8c9C1")))
|
||||||
"0x90F8bf6A479f320ead074411a4B0e7944Ea8c9C1"
|
|
||||||
)))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const fn default_caller() -> StepAddress {
|
pub const fn default_caller() -> StepAddress {
|
||||||
@@ -483,7 +476,7 @@ impl FunctionCallStep {
|
|||||||
.context("Failed to produce calldata for deployer/fallback method")?;
|
.context("Failed to produce calldata for deployer/fallback method")?;
|
||||||
|
|
||||||
Ok(calldata.into())
|
Ok(calldata.into())
|
||||||
}
|
},
|
||||||
Method::FunctionName(ref function_name) => {
|
Method::FunctionName(ref function_name) => {
|
||||||
let Some(abi) = context.deployed_contract_abi(&self.instance) else {
|
let Some(abi) = context.deployed_contract_abi(&self.instance) else {
|
||||||
anyhow::bail!("ABI for instance '{}' not found", self.instance.as_ref());
|
anyhow::bail!("ABI for instance '{}' not found", self.instance.as_ref());
|
||||||
@@ -534,7 +527,7 @@ impl FunctionCallStep {
|
|||||||
.context("Failed to append encoded argument to calldata buffer")?;
|
.context("Failed to append encoded argument to calldata buffer")?;
|
||||||
|
|
||||||
Ok(calldata.into())
|
Ok(calldata.into())
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -549,11 +542,9 @@ 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().from(caller).value(
|
let transaction_request = TransactionRequest::default()
|
||||||
self.value
|
.from(caller)
|
||||||
.map(|value| value.into_inner())
|
.value(self.value.map(|value| value.into_inner()).unwrap_or_default());
|
||||||
.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
|
||||||
@@ -635,8 +626,7 @@ 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)
|
self.calldata_into_slice(&mut buffer, resolver, context).await?;
|
||||||
.await?;
|
|
||||||
Ok(buffer)
|
Ok(buffer)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -649,7 +639,7 @@ impl Calldata {
|
|||||||
match self {
|
match self {
|
||||||
Calldata::Single(bytes) => {
|
Calldata::Single(bytes) => {
|
||||||
buffer.extend_from_slice(bytes);
|
buffer.extend_from_slice(bytes);
|
||||||
}
|
},
|
||||||
Calldata::Compound(items) => {
|
Calldata::Compound(items) => {
|
||||||
let resolved = stream::iter(items.iter().enumerate())
|
let resolved = stream::iter(items.iter().enumerate())
|
||||||
.map(|(arg_idx, arg)| async move {
|
.map(|(arg_idx, arg)| async move {
|
||||||
@@ -664,7 +654,7 @@ impl Calldata {
|
|||||||
.context("Failed to resolve one or more calldata arguments")?;
|
.context("Failed to resolve one or more calldata arguments")?;
|
||||||
|
|
||||||
buffer.extend(resolved.into_iter().flatten());
|
buffer.extend(resolved.into_iter().flatten());
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -713,7 +703,7 @@ impl Calldata {
|
|||||||
.all(|v| async move { v.is_ok_and(|v| v) })
|
.all(|v| async move { v.is_ok_and(|v| v) })
|
||||||
.map(Ok)
|
.map(Ok)
|
||||||
.await
|
.await
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -727,10 +717,7 @@ 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
|
for token in self.calldata_tokens().map(|token| token.resolve(resolver, context)) {
|
||||||
.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,
|
||||||
@@ -752,17 +739,15 @@ impl CalldataItem {
|
|||||||
Operation::BitwiseAnd => Some(left_operand & right_operand),
|
Operation::BitwiseAnd => Some(left_operand & right_operand),
|
||||||
Operation::BitwiseOr => Some(left_operand | right_operand),
|
Operation::BitwiseOr => Some(left_operand | right_operand),
|
||||||
Operation::BitwiseXor => Some(left_operand ^ right_operand),
|
Operation::BitwiseXor => Some(left_operand ^ right_operand),
|
||||||
Operation::ShiftLeft => {
|
Operation::ShiftLeft =>
|
||||||
Some(left_operand << usize::try_from(right_operand)?)
|
Some(left_operand << usize::try_from(right_operand)?),
|
||||||
}
|
Operation::ShiftRight =>
|
||||||
Operation::ShiftRight => {
|
Some(left_operand >> usize::try_from(right_operand)?),
|
||||||
Some(left_operand >> usize::try_from(right_operand)?)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
.context("Invalid calldata arithmetic operation - Invalid operation")?;
|
.context("Invalid calldata arithmetic operation - Invalid operation")?;
|
||||||
|
|
||||||
CalldataToken::Item(result)
|
CalldataToken::Item(result)
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
stack.push(new_token)
|
stack.push(new_token)
|
||||||
}
|
}
|
||||||
@@ -771,9 +756,7 @@ 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!(
|
_ => Err(anyhow::anyhow!("Invalid calldata arithmetic operation - Invalid stack")),
|
||||||
"Invalid calldata arithmetic operation - Invalid stack"
|
|
||||||
)),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -917,16 +900,13 @@ 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
|
context.variable(variable_name).context("Variable lookup failed").copied()
|
||||||
.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))
|
||||||
};
|
};
|
||||||
value.map(CalldataToken::Item)
|
value.map(CalldataToken::Item)
|
||||||
}
|
},
|
||||||
Self::Operation(operation) => Ok(CalldataToken::Operation(operation)),
|
Self::Operation(operation) => Ok(CalldataToken::Operation(operation)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1050,13 +1030,7 @@ 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
|
let selector = parsed_abi.function("store").unwrap().first().unwrap().selector().0;
|
||||||
.function("store")
|
|
||||||
.unwrap()
|
|
||||||
.first()
|
|
||||||
.unwrap()
|
|
||||||
.selector()
|
|
||||||
.0;
|
|
||||||
|
|
||||||
let input = FunctionCallStep {
|
let input = FunctionCallStep {
|
||||||
instance: ContractInstance::new("Contract"),
|
instance: ContractInstance::new("Contract"),
|
||||||
@@ -1094,13 +1068,7 @@ 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
|
let selector = parsed_abi.function("send").unwrap().first().unwrap().selector().0;
|
||||||
.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(),
|
||||||
@@ -1122,10 +1090,7 @@ 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!(
|
assert_eq!(decoded.0, address!("0x1000000000000000000000000000000000000001"));
|
||||||
decoded.0,
|
|
||||||
address!("0x1000000000000000000000000000000000000001")
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -1141,13 +1106,7 @@ 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
|
let selector = parsed_abi.function("send").unwrap().first().unwrap().selector().0;
|
||||||
.function("send")
|
|
||||||
.unwrap()
|
|
||||||
.first()
|
|
||||||
.unwrap()
|
|
||||||
.selector()
|
|
||||||
.0;
|
|
||||||
|
|
||||||
let input: FunctionCallStep = FunctionCallStep {
|
let input: FunctionCallStep = FunctionCallStep {
|
||||||
instance: ContractInstance::new("Contract"),
|
instance: ContractInstance::new("Contract"),
|
||||||
@@ -1169,10 +1128,7 @@ 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!(
|
assert_eq!(decoded.0, address!("0x1000000000000000000000000000000000000001"));
|
||||||
decoded.0,
|
|
||||||
address!("0x1000000000000000000000000000000000000001")
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn resolve_calldata_item(
|
async fn resolve_calldata_item(
|
||||||
@@ -1209,12 +1165,7 @@ 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(
|
U256::from(MockResolver.block_gas_limit(Default::default()).await.unwrap())
|
||||||
MockResolver
|
|
||||||
.block_gas_limit(Default::default())
|
|
||||||
.await
|
|
||||||
.unwrap()
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1231,11 +1182,7 @@ mod tests {
|
|||||||
assert_eq!(
|
assert_eq!(
|
||||||
resolved,
|
resolved,
|
||||||
U256::from_be_slice(
|
U256::from_be_slice(
|
||||||
MockResolver
|
MockResolver.block_coinbase(Default::default()).await.unwrap().as_ref()
|
||||||
.block_coinbase(Default::default())
|
|
||||||
.await
|
|
||||||
.unwrap()
|
|
||||||
.as_ref()
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -1250,13 +1197,7 @@ mod tests {
|
|||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
let resolved = resolved.expect("Failed to resolve argument");
|
let resolved = resolved.expect("Failed to resolve argument");
|
||||||
assert_eq!(
|
assert_eq!(resolved, MockResolver.block_difficulty(Default::default()).await.unwrap())
|
||||||
resolved,
|
|
||||||
MockResolver
|
|
||||||
.block_difficulty(Default::default())
|
|
||||||
.await
|
|
||||||
.unwrap()
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -1271,11 +1212,7 @@ 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
|
MockResolver.block_base_fee(Default::default()).await.map(U256::from).unwrap()
|
||||||
.block_base_fee(Default::default())
|
|
||||||
.await
|
|
||||||
.map(U256::from)
|
|
||||||
.unwrap()
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1305,10 +1242,7 @@ mod tests {
|
|||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
let resolved = resolved.expect("Failed to resolve argument");
|
let resolved = resolved.expect("Failed to resolve argument");
|
||||||
assert_eq!(
|
assert_eq!(resolved, U256::from(MockResolver.last_block_number().await.unwrap()))
|
||||||
resolved,
|
|
||||||
U256::from(MockResolver.last_block_number().await.unwrap())
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -1323,12 +1257,7 @@ 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(
|
U256::from(MockResolver.block_timestamp(Default::default()).await.unwrap())
|
||||||
MockResolver
|
|
||||||
.block_timestamp(Default::default())
|
|
||||||
.await
|
|
||||||
.unwrap()
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1406,10 +1335,7 @@ mod tests {
|
|||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
let resolved = resolved.expect("Failed to resolve argument");
|
let resolved = resolved.expect("Failed to resolve argument");
|
||||||
assert_eq!(
|
assert_eq!(resolved, U256::from(MockResolver.last_block_number().await.unwrap() + 10));
|
||||||
resolved,
|
|
||||||
U256::from(MockResolver.last_block_number().await.unwrap() + 10)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
|
|||||||
@@ -135,11 +135,11 @@ impl<'a> ResolutionContext<'a> {
|
|||||||
match self.block_number {
|
match self.block_number {
|
||||||
Some(block_number) => match number {
|
Some(block_number) => match number {
|
||||||
BlockNumberOrTag::Latest => BlockNumberOrTag::Number(*block_number),
|
BlockNumberOrTag::Latest => BlockNumberOrTag::Number(*block_number),
|
||||||
n @ (BlockNumberOrTag::Finalized
|
n @ (BlockNumberOrTag::Finalized |
|
||||||
| BlockNumberOrTag::Safe
|
BlockNumberOrTag::Safe |
|
||||||
| BlockNumberOrTag::Earliest
|
BlockNumberOrTag::Earliest |
|
||||||
| BlockNumberOrTag::Pending
|
BlockNumberOrTag::Pending |
|
||||||
| BlockNumberOrTag::Number(_)) => n,
|
BlockNumberOrTag::Number(_)) => n,
|
||||||
},
|
},
|
||||||
None => number,
|
None => number,
|
||||||
}
|
}
|
||||||
@@ -162,8 +162,7 @@ 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
|
self.variables.and_then(|variables| variables.get(name.as_ref()))
|
||||||
.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> {
|
||||||
|
|||||||
+237
-139
@@ -21,7 +21,7 @@ use std::{
|
|||||||
io::{BufRead, BufReader, BufWriter, Write},
|
io::{BufRead, BufReader, BufWriter, Write},
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
sync::Arc,
|
sync::Arc,
|
||||||
time::Instant,
|
time::{Duration, Instant},
|
||||||
};
|
};
|
||||||
use temp_dir::TempDir;
|
use temp_dir::TempDir;
|
||||||
use tokio::sync::Mutex;
|
use tokio::sync::Mutex;
|
||||||
@@ -40,6 +40,10 @@ struct MlTestRunnerArgs {
|
|||||||
#[arg(long = "cached-passed")]
|
#[arg(long = "cached-passed")]
|
||||||
cached_passed: Option<PathBuf>,
|
cached_passed: Option<PathBuf>,
|
||||||
|
|
||||||
|
/// File to store tests that have failed (defaults to .<platform>-failed)
|
||||||
|
#[arg(long = "cached-failed")]
|
||||||
|
cached_failed: Option<PathBuf>,
|
||||||
|
|
||||||
/// Stop after the first file failure
|
/// Stop after the first file failure
|
||||||
#[arg(long = "bail")]
|
#[arg(long = "bail")]
|
||||||
bail: bool,
|
bail: bool,
|
||||||
@@ -62,16 +66,24 @@ struct MlTestRunnerArgs {
|
|||||||
/// RPC port to connect to when using existing node
|
/// RPC port to connect to when using existing node
|
||||||
#[arg(long = "rpc-port", default_value = "8545")]
|
#[arg(long = "rpc-port", default_value = "8545")]
|
||||||
rpc_port: u16,
|
rpc_port: u16,
|
||||||
|
|
||||||
|
/// Show verbose output including cached tests and detailed error messages
|
||||||
|
#[arg(long = "verbose", short = 'v')]
|
||||||
|
verbose: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() -> anyhow::Result<()> {
|
fn main() -> anyhow::Result<()> {
|
||||||
|
let args = MlTestRunnerArgs::parse();
|
||||||
|
|
||||||
|
// Only set up tracing if RUST_LOG is explicitly set or --verbose is passed
|
||||||
|
if std::env::var("RUST_LOG").is_ok() || args.verbose {
|
||||||
let subscriber = FmtSubscriber::builder()
|
let subscriber = FmtSubscriber::builder()
|
||||||
.with_env_filter(EnvFilter::from_default_env())
|
.with_env_filter(EnvFilter::from_default_env())
|
||||||
.with_writer(std::io::stderr)
|
.with_writer(std::io::stderr)
|
||||||
.finish();
|
.finish();
|
||||||
tracing::subscriber::set_global_default(subscriber).expect("Failed to set tracing subscriber");
|
tracing::subscriber::set_global_default(subscriber)
|
||||||
|
.expect("Failed to set tracing subscriber");
|
||||||
let args = MlTestRunnerArgs::parse();
|
}
|
||||||
|
|
||||||
info!("ML test runner starting");
|
info!("ML test runner starting");
|
||||||
info!("Platform: {:?}", args.platform);
|
info!("Platform: {:?}", args.platform);
|
||||||
@@ -84,6 +96,40 @@ fn main() -> anyhow::Result<()> {
|
|||||||
.block_on(run(args))
|
.block_on(run(args))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Wait for HTTP server to be ready by attempting to connect to the specified port
|
||||||
|
async fn wait_for_http_server(port: u16) -> anyhow::Result<()> {
|
||||||
|
const MAX_RETRIES: u32 = 60;
|
||||||
|
const RETRY_DELAY: Duration = Duration::from_secs(1);
|
||||||
|
|
||||||
|
for attempt in 1..=MAX_RETRIES {
|
||||||
|
match tokio::net::TcpStream::connect(format!("127.0.0.1:{}", port)).await {
|
||||||
|
Ok(_) => {
|
||||||
|
info!("Successfully connected to HTTP server on port {} (attempt {})", port, attempt);
|
||||||
|
return Ok(());
|
||||||
|
},
|
||||||
|
Err(e) => {
|
||||||
|
if attempt == MAX_RETRIES {
|
||||||
|
anyhow::bail!(
|
||||||
|
"Failed to connect to HTTP server on port {} after {} attempts: {}",
|
||||||
|
port,
|
||||||
|
MAX_RETRIES,
|
||||||
|
e
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if attempt % 10 == 0 {
|
||||||
|
info!(
|
||||||
|
"Still waiting for HTTP server on port {} (attempt {}/{})",
|
||||||
|
port, attempt, MAX_RETRIES
|
||||||
|
);
|
||||||
|
}
|
||||||
|
tokio::time::sleep(RETRY_DELAY).await;
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
|
||||||
async fn run(args: MlTestRunnerArgs) -> anyhow::Result<()> {
|
async fn run(args: MlTestRunnerArgs) -> anyhow::Result<()> {
|
||||||
let start_time = Instant::now();
|
let start_time = Instant::now();
|
||||||
|
|
||||||
@@ -101,6 +147,84 @@ async fn run(args: MlTestRunnerArgs) -> anyhow::Result<()> {
|
|||||||
|
|
||||||
let cached_passed = Arc::new(Mutex::new(cached_passed));
|
let cached_passed = Arc::new(Mutex::new(cached_passed));
|
||||||
|
|
||||||
|
// Set up cached-failed file (defaults to .<platform>-failed)
|
||||||
|
let cached_failed_path = args
|
||||||
|
.cached_failed
|
||||||
|
.clone()
|
||||||
|
.unwrap_or_else(|| PathBuf::from(format!(".{:?}-failed", args.platform)));
|
||||||
|
|
||||||
|
let cached_failed = Arc::new(Mutex::new(HashSet::<String>::new()));
|
||||||
|
|
||||||
|
// Get the platform based on CLI args
|
||||||
|
let platform: &dyn Platform = match args.platform {
|
||||||
|
PlatformIdentifier::GethEvmSolc => &revive_dt_core::GethEvmSolcPlatform,
|
||||||
|
PlatformIdentifier::LighthouseGethEvmSolc => &revive_dt_core::LighthouseGethEvmSolcPlatform,
|
||||||
|
PlatformIdentifier::KitchensinkPolkavmResolc =>
|
||||||
|
&revive_dt_core::KitchensinkPolkavmResolcPlatform,
|
||||||
|
PlatformIdentifier::KitchensinkRevmSolc => &revive_dt_core::KitchensinkRevmSolcPlatform,
|
||||||
|
PlatformIdentifier::ReviveDevNodePolkavmResolc =>
|
||||||
|
&revive_dt_core::ReviveDevNodePolkavmResolcPlatform,
|
||||||
|
PlatformIdentifier::ReviveDevNodeRevmSolc => &revive_dt_core::ReviveDevNodeRevmSolcPlatform,
|
||||||
|
PlatformIdentifier::ZombienetPolkavmResolc =>
|
||||||
|
&revive_dt_core::ZombienetPolkavmResolcPlatform,
|
||||||
|
PlatformIdentifier::ZombienetRevmSolc => &revive_dt_core::ZombienetRevmSolcPlatform,
|
||||||
|
};
|
||||||
|
|
||||||
|
let test_context = TestExecutionContext::default();
|
||||||
|
let context = revive_dt_config::Context::Test(Box::new(test_context));
|
||||||
|
|
||||||
|
let node: &'static dyn revive_dt_node_interaction::EthereumNode = if args.start_platform {
|
||||||
|
info!("Starting blockchain node...");
|
||||||
|
let node_handle =
|
||||||
|
platform.new_node(context.clone()).context("Failed to spawn node thread")?;
|
||||||
|
|
||||||
|
info!("Waiting for node to start...");
|
||||||
|
let node = node_handle
|
||||||
|
.join()
|
||||||
|
.map_err(|e| anyhow::anyhow!("Node thread panicked: {:?}", e))?
|
||||||
|
.context("Failed to start node")?;
|
||||||
|
|
||||||
|
info!("Node started with ID: {}, connection: {}", node.id(), node.connection_string());
|
||||||
|
let node = Box::leak(node);
|
||||||
|
|
||||||
|
info!("Running pre-transactions...");
|
||||||
|
node.pre_transactions().await.context("Failed to run pre-transactions")?;
|
||||||
|
info!("Pre-transactions completed");
|
||||||
|
|
||||||
|
node
|
||||||
|
} else {
|
||||||
|
info!("Using existing node at port {}", args.rpc_port);
|
||||||
|
|
||||||
|
// Wait for the HTTP server to be ready
|
||||||
|
info!("Waiting for HTTP server to be ready on port {}...", args.rpc_port);
|
||||||
|
wait_for_http_server(args.rpc_port).await?;
|
||||||
|
info!("HTTP server is ready");
|
||||||
|
|
||||||
|
let existing_node: Box<dyn revive_dt_node_interaction::EthereumNode> = match args.platform {
|
||||||
|
PlatformIdentifier::GethEvmSolc | PlatformIdentifier::LighthouseGethEvmSolc =>
|
||||||
|
Box::new(
|
||||||
|
revive_dt_node::node_implementations::geth::GethNode::new_existing(
|
||||||
|
&args.private_key,
|
||||||
|
args.rpc_port,
|
||||||
|
)
|
||||||
|
.await?,
|
||||||
|
),
|
||||||
|
PlatformIdentifier::KitchensinkPolkavmResolc |
|
||||||
|
PlatformIdentifier::KitchensinkRevmSolc |
|
||||||
|
PlatformIdentifier::ReviveDevNodePolkavmResolc |
|
||||||
|
PlatformIdentifier::ReviveDevNodeRevmSolc |
|
||||||
|
PlatformIdentifier::ZombienetPolkavmResolc |
|
||||||
|
PlatformIdentifier::ZombienetRevmSolc => Box::new(
|
||||||
|
revive_dt_node::node_implementations::substrate::SubstrateNode::new_existing(
|
||||||
|
&args.private_key,
|
||||||
|
args.rpc_port,
|
||||||
|
)
|
||||||
|
.await?,
|
||||||
|
),
|
||||||
|
};
|
||||||
|
Box::leak(existing_node)
|
||||||
|
};
|
||||||
|
|
||||||
let mut passed_files = 0;
|
let mut passed_files = 0;
|
||||||
let mut failed_files = 0;
|
let mut failed_files = 0;
|
||||||
let mut skipped_files = 0;
|
let mut skipped_files = 0;
|
||||||
@@ -116,11 +240,14 @@ async fn run(args: MlTestRunnerArgs) -> anyhow::Result<()> {
|
|||||||
for test_file in test_files {
|
for test_file in test_files {
|
||||||
let file_display = test_file.display().to_string();
|
let file_display = test_file.display().to_string();
|
||||||
|
|
||||||
|
info!("\n\n == Executing test file: {file_display} == \n\n");
|
||||||
// Check if already passed
|
// Check if already passed
|
||||||
{
|
{
|
||||||
let cache = cached_passed.lock().await;
|
let cache = cached_passed.lock().await;
|
||||||
if cache.contains(&file_display) {
|
if cache.contains(&file_display) {
|
||||||
println!("test {} ... {YELLOW}cached{COLOUR_RESET}", file_display);
|
if args.verbose {
|
||||||
|
println!("test {file_display} ... {YELLOW}cached{COLOUR_RESET}");
|
||||||
|
}
|
||||||
skipped_files += 1;
|
skipped_files += 1;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -131,56 +258,68 @@ async fn run(args: MlTestRunnerArgs) -> anyhow::Result<()> {
|
|||||||
Ok(mf) => {
|
Ok(mf) => {
|
||||||
info!("Loaded metadata with {} case(s)", mf.cases.len());
|
info!("Loaded metadata with {} case(s)", mf.cases.len());
|
||||||
mf
|
mf
|
||||||
}
|
},
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
println!("test {} ... {RED}FAILED{COLOUR_RESET}", file_display);
|
// Skip files without metadata instead of treating them as failures
|
||||||
println!(" Error loading metadata: {}", e);
|
info!("Skipping {} (no metadata): {}", file_display, e);
|
||||||
failed_files += 1;
|
skipped_files += 1;
|
||||||
failures.push((
|
|
||||||
file_display.clone(),
|
|
||||||
format!("Error loading metadata: {}", e),
|
|
||||||
));
|
|
||||||
if args.bail {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
continue;
|
continue;
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
info!("Executing test file: {}", file_display);
|
// Execute test with 10 second timeout
|
||||||
match execute_test_file(&args, &metadata_file).await {
|
let test_result = tokio::time::timeout(
|
||||||
|
Duration::from_secs(20),
|
||||||
|
execute_test_file(&metadata_file, platform, node, &context),
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
let result = match test_result {
|
||||||
|
Ok(Ok(_)) => Ok(()),
|
||||||
|
Ok(Err(e)) => Err(e),
|
||||||
|
Err(_) => Err(anyhow::anyhow!("Test timed out after 20 seconds")),
|
||||||
|
};
|
||||||
|
|
||||||
|
match result {
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
println!("test {} ... {GREEN}ok{COLOUR_RESET}", file_display);
|
println!("test {file_display} ... {GREEN}ok{COLOUR_RESET}");
|
||||||
info!("Test file passed: {}", file_display);
|
|
||||||
passed_files += 1;
|
passed_files += 1;
|
||||||
|
|
||||||
{
|
// Update cache
|
||||||
|
if let Some(cache_file) = &args.cached_passed {
|
||||||
let mut cache = cached_passed.lock().await;
|
let mut cache = cached_passed.lock().await;
|
||||||
cache.insert(file_display);
|
cache.insert(file_display);
|
||||||
|
if let Err(e) = save_cached_passed(cache_file, &cache) {
|
||||||
|
info!("Failed to save cache: {}", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
println!("test {} ... {RED}FAILED{COLOUR_RESET}", file_display);
|
println!("test {file_display} ... {RED}FAILED{COLOUR_RESET}");
|
||||||
failed_files += 1;
|
failed_files += 1;
|
||||||
failures.push((file_display, format!("{:?}", e)));
|
let error_detail = if args.verbose { format!("{:?}", e) } else { format!("{}", e) };
|
||||||
|
failures.push((file_display.clone(), error_detail));
|
||||||
|
|
||||||
|
// Update cached-failed
|
||||||
|
{
|
||||||
|
let mut cache = cached_failed.lock().await;
|
||||||
|
cache.insert(file_display);
|
||||||
|
if let Err(e) = save_cached_failed(&cached_failed_path, &cache) {
|
||||||
|
info!("Failed to save cached-failed: {}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if args.bail {
|
if args.bail {
|
||||||
info!("Bailing after first failure");
|
info!("Bailing after first failure");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(cache_file) = &args.cached_passed {
|
|
||||||
let cache = cached_passed.lock().await;
|
|
||||||
info!("Saving {} cached passed test(s)", cache.len());
|
|
||||||
save_cached_passed(cache_file, &cache)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Print summary
|
// Print summary
|
||||||
println!();
|
println!();
|
||||||
if !failures.is_empty() {
|
if !failures.is_empty() && args.verbose {
|
||||||
println!("{BOLD}failures:{BOLD_RESET}");
|
println!("{BOLD}failures:{BOLD_RESET}");
|
||||||
println!();
|
println!();
|
||||||
for (file, error) in &failures {
|
for (file, error) in &failures {
|
||||||
@@ -226,7 +365,7 @@ fn discover_test_files(path: &Path) -> anyhow::Result<Vec<PathBuf>> {
|
|||||||
"sol" => {
|
"sol" => {
|
||||||
// Single .sol file
|
// Single .sol file
|
||||||
files.push(path.to_path_buf());
|
files.push(path.to_path_buf());
|
||||||
}
|
},
|
||||||
"json" => {
|
"json" => {
|
||||||
// Corpus file - enumerate its tests
|
// Corpus file - enumerate its tests
|
||||||
let corpus = Corpus::try_from_path(path)?;
|
let corpus = Corpus::try_from_path(path)?;
|
||||||
@@ -234,19 +373,47 @@ fn discover_test_files(path: &Path) -> anyhow::Result<Vec<PathBuf>> {
|
|||||||
for metadata in metadata_files {
|
for metadata in metadata_files {
|
||||||
files.push(metadata.metadata_file_path);
|
files.push(metadata.metadata_file_path);
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
_ => anyhow::bail!(
|
_ => anyhow::bail!("Unsupported file extension: {}. Expected .sol or .json", extension),
|
||||||
"Unsupported file extension: {}. Expected .sol or .json",
|
|
||||||
extension
|
|
||||||
),
|
|
||||||
}
|
}
|
||||||
} else if path.is_dir() {
|
} else if path.is_dir() {
|
||||||
// Walk directory recursively for .sol files
|
// First, find all test.json files
|
||||||
for entry in FilesWithExtensionIterator::new(path)
|
let mut test_json_dirs = HashSet::new();
|
||||||
|
for json_file in FilesWithExtensionIterator::new(path)
|
||||||
|
.with_allowed_extension("json")
|
||||||
|
.with_use_cached_fs(true)
|
||||||
|
{
|
||||||
|
if json_file.file_name().and_then(|s| s.to_str()) == Some("test.json") {
|
||||||
|
if let Some(parent) = json_file.parent() {
|
||||||
|
test_json_dirs.insert(parent.to_path_buf());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to parse as corpus file first, then as metadata file
|
||||||
|
if let Ok(corpus) = Corpus::try_from_path(&json_file) {
|
||||||
|
// It's a corpus file - enumerate its tests
|
||||||
|
let metadata_files = corpus.enumerate_tests();
|
||||||
|
for metadata in metadata_files {
|
||||||
|
files.push(metadata.metadata_file_path);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// It's a metadata file - use it directly
|
||||||
|
files.push(json_file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Then, find .sol files that are NOT in directories with test.json
|
||||||
|
for sol_file in FilesWithExtensionIterator::new(path)
|
||||||
.with_allowed_extension("sol")
|
.with_allowed_extension("sol")
|
||||||
.with_use_cached_fs(true)
|
.with_use_cached_fs(true)
|
||||||
{
|
{
|
||||||
files.push(entry);
|
if let Some(parent) = sol_file.parent() {
|
||||||
|
if !test_json_dirs.contains(parent) {
|
||||||
|
files.push(sol_file);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
files.push(sol_file);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
anyhow::bail!("Path is neither a file nor a directory: {}", path.display());
|
anyhow::bail!("Path is neither a file nor a directory: {}", path.display());
|
||||||
@@ -269,8 +436,10 @@ fn load_metadata_file(path: &Path) -> anyhow::Result<MetadataFile> {
|
|||||||
|
|
||||||
/// Execute all test cases in a metadata file
|
/// Execute all test cases in a metadata file
|
||||||
async fn execute_test_file(
|
async fn execute_test_file(
|
||||||
args: &MlTestRunnerArgs,
|
|
||||||
metadata_file: &MetadataFile,
|
metadata_file: &MetadataFile,
|
||||||
|
platform: &dyn Platform,
|
||||||
|
node: &'static dyn revive_dt_node_interaction::EthereumNode,
|
||||||
|
context: &revive_dt_config::Context,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
if metadata_file.cases.is_empty() {
|
if metadata_file.cases.is_empty() {
|
||||||
anyhow::bail!("No test cases found in file");
|
anyhow::bail!("No test cases found in file");
|
||||||
@@ -278,103 +447,24 @@ async fn execute_test_file(
|
|||||||
|
|
||||||
info!("Processing {} test case(s)", metadata_file.cases.len());
|
info!("Processing {} test case(s)", metadata_file.cases.len());
|
||||||
|
|
||||||
// Get the platform based on CLI args
|
|
||||||
let platform: &dyn Platform = match args.platform {
|
|
||||||
PlatformIdentifier::GethEvmSolc => &revive_dt_core::GethEvmSolcPlatform,
|
|
||||||
PlatformIdentifier::LighthouseGethEvmSolc => &revive_dt_core::LighthouseGethEvmSolcPlatform,
|
|
||||||
PlatformIdentifier::KitchensinkPolkavmResolc => {
|
|
||||||
&revive_dt_core::KitchensinkPolkavmResolcPlatform
|
|
||||||
}
|
|
||||||
PlatformIdentifier::KitchensinkRevmSolc => &revive_dt_core::KitchensinkRevmSolcPlatform,
|
|
||||||
PlatformIdentifier::ReviveDevNodePolkavmResolc => {
|
|
||||||
&revive_dt_core::ReviveDevNodePolkavmResolcPlatform
|
|
||||||
}
|
|
||||||
PlatformIdentifier::ReviveDevNodeRevmSolc => &revive_dt_core::ReviveDevNodeRevmSolcPlatform,
|
|
||||||
PlatformIdentifier::ZombienetPolkavmResolc => {
|
|
||||||
&revive_dt_core::ZombienetPolkavmResolcPlatform
|
|
||||||
}
|
|
||||||
PlatformIdentifier::ZombienetRevmSolc => &revive_dt_core::ZombienetRevmSolcPlatform,
|
|
||||||
};
|
|
||||||
|
|
||||||
let temp_dir = TempDir::new()?;
|
let temp_dir = TempDir::new()?;
|
||||||
info!("Created temporary directory: {}", temp_dir.path().display());
|
info!("Created temporary directory: {}", temp_dir.path().display());
|
||||||
|
|
||||||
let test_context = TestExecutionContext::default();
|
|
||||||
let context = revive_dt_config::Context::Test(Box::new(test_context));
|
|
||||||
|
|
||||||
let node: &'static dyn revive_dt_node_interaction::EthereumNode = if args.start_platform {
|
|
||||||
info!("Starting blockchain node...");
|
|
||||||
let node_handle = platform
|
|
||||||
.new_node(context.clone())
|
|
||||||
.context("Failed to spawn node thread")?;
|
|
||||||
|
|
||||||
info!("Waiting for node to start...");
|
|
||||||
let node = node_handle
|
|
||||||
.join()
|
|
||||||
.map_err(|e| anyhow::anyhow!("Node thread panicked: {:?}", e))?
|
|
||||||
.context("Failed to start node")?;
|
|
||||||
|
|
||||||
info!(
|
|
||||||
"Node started with ID: {}, connection: {}",
|
|
||||||
node.id(),
|
|
||||||
node.connection_string()
|
|
||||||
);
|
|
||||||
let node = Box::leak(node);
|
|
||||||
|
|
||||||
info!("Running pre-transactions...");
|
|
||||||
node.pre_transactions()
|
|
||||||
.await
|
|
||||||
.context("Failed to run pre-transactions")?;
|
|
||||||
info!("Pre-transactions completed");
|
|
||||||
|
|
||||||
node
|
|
||||||
} else {
|
|
||||||
info!("Using existing node");
|
|
||||||
let existing_node: Box<dyn revive_dt_node_interaction::EthereumNode> = match args.platform {
|
|
||||||
PlatformIdentifier::GethEvmSolc | PlatformIdentifier::LighthouseGethEvmSolc => {
|
|
||||||
Box::new(
|
|
||||||
revive_dt_node::node_implementations::geth::GethNode::new_existing(
|
|
||||||
&args.private_key,
|
|
||||||
args.rpc_port,
|
|
||||||
)
|
|
||||||
.await?,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
PlatformIdentifier::KitchensinkPolkavmResolc
|
|
||||||
| PlatformIdentifier::KitchensinkRevmSolc
|
|
||||||
| PlatformIdentifier::ReviveDevNodePolkavmResolc
|
|
||||||
| PlatformIdentifier::ReviveDevNodeRevmSolc
|
|
||||||
| PlatformIdentifier::ZombienetPolkavmResolc
|
|
||||||
| PlatformIdentifier::ZombienetRevmSolc => Box::new(
|
|
||||||
revive_dt_node::node_implementations::substrate::SubstrateNode::new_existing(
|
|
||||||
&args.private_key,
|
|
||||||
args.rpc_port,
|
|
||||||
)
|
|
||||||
.await?,
|
|
||||||
),
|
|
||||||
};
|
|
||||||
Box::leak(existing_node)
|
|
||||||
};
|
|
||||||
|
|
||||||
info!("Initializing cached compiler");
|
info!("Initializing cached compiler");
|
||||||
let cached_compiler = CachedCompiler::new(temp_dir.path().join("compilation_cache"), false)
|
let cached_compiler = CachedCompiler::new(temp_dir.path().join("compilation_cache"), false)
|
||||||
.await
|
.await
|
||||||
.map(Arc::new)
|
.map(Arc::new)
|
||||||
.context("Failed to create cached compiler")?;
|
.context("Failed to create cached compiler")?;
|
||||||
|
|
||||||
let private_key_allocator = Arc::new(Mutex::new(PrivateKeyAllocator::new(
|
let private_key_allocator =
|
||||||
alloy::primitives::U256::from(100),
|
Arc::new(Mutex::new(PrivateKeyAllocator::new(alloy::primitives::U256::from(100))));
|
||||||
)));
|
|
||||||
|
|
||||||
let (reporter, report_task) =
|
let (reporter, report_task) =
|
||||||
revive_dt_report::ReportAggregator::new(context.clone()).into_task();
|
revive_dt_report::ReportAggregator::new(context.clone()).into_task();
|
||||||
|
|
||||||
tokio::spawn(report_task);
|
tokio::spawn(report_task);
|
||||||
|
|
||||||
info!(
|
info!("Building test definitions for {} case(s)", metadata_file.cases.len());
|
||||||
"Building test definitions for {} case(s)",
|
|
||||||
metadata_file.cases.len()
|
|
||||||
);
|
|
||||||
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() {
|
||||||
info!("Building test definition for case {}", case_idx);
|
info!("Building test definition for case {}", case_idx);
|
||||||
@@ -421,20 +511,17 @@ 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.execute_all().await.context(format!(
|
let steps_executed = driver
|
||||||
"Failed to execute case {}",
|
.execute_all()
|
||||||
test_definition.case_idx
|
.await
|
||||||
))?;
|
.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!(
|
info!("All {} test case(s) executed successfully", test_definitions.len());
|
||||||
"All {} test case(s) executed successfully",
|
|
||||||
test_definitions.len()
|
|
||||||
);
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -477,12 +564,7 @@ async fn build_test_definition<'a>(
|
|||||||
let mut platforms = BTreeMap::new();
|
let mut platforms = BTreeMap::new();
|
||||||
platforms.insert(
|
platforms.insert(
|
||||||
platform.platform_identifier(),
|
platform.platform_identifier(),
|
||||||
TestPlatformInformation {
|
TestPlatformInformation { platform, node, compiler, reporter: execution_reporter },
|
||||||
platform,
|
|
||||||
node,
|
|
||||||
compiler,
|
|
||||||
reporter: execution_reporter,
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
|
|
||||||
let test_definition = TestDefinition {
|
let test_definition = TestDefinition {
|
||||||
@@ -496,7 +578,7 @@ async fn build_test_definition<'a>(
|
|||||||
};
|
};
|
||||||
|
|
||||||
if let Err((reason, _)) = test_definition.check_compatibility() {
|
if let Err((reason, _)) = test_definition.check_compatibility() {
|
||||||
println!(" Skipping case {}: {}", case_idx, reason);
|
info!("Skipping case {}: {}", case_idx, reason);
|
||||||
return Ok(None);
|
return Ok(None);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -539,3 +621,19 @@ fn save_cached_passed(path: &Path, cache: &HashSet<String>) -> anyhow::Result<()
|
|||||||
writer.flush()?;
|
writer.flush()?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Save cached failed tests to file
|
||||||
|
fn save_cached_failed(path: &Path, cache: &HashSet<String>) -> anyhow::Result<()> {
|
||||||
|
let file = File::create(path).context("Failed to create cached-failed file")?;
|
||||||
|
let mut writer = BufWriter::new(file);
|
||||||
|
|
||||||
|
let mut entries: Vec<_> = cache.iter().collect();
|
||||||
|
entries.sort();
|
||||||
|
|
||||||
|
for entry in entries {
|
||||||
|
writeln!(writer, "{}", entry)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
writer.flush()?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|||||||
@@ -33,10 +33,7 @@ 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) => (
|
Some(prefix) => (format!("{prefix}_stdout.log"), format!("{prefix}_stderr.log")),
|
||||||
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()),
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -57,23 +54,19 @@ 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 = stdout_logs_file
|
let stdout_logs_file =
|
||||||
.try_clone()
|
stdout_logs_file.try_clone().context("Failed to clone the stdout logs file")?;
|
||||||
.context("Failed to clone the stdout logs file")?;
|
let stderr_logs_file =
|
||||||
let stderr_logs_file = stderr_logs_file
|
stderr_logs_file.try_clone().context("Failed to clone the 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
|
let mut child = command.spawn().context("Failed to spawn the built command")?;
|
||||||
.spawn()
|
|
||||||
.context("Failed to spawn the built command")?;
|
|
||||||
|
|
||||||
match process_readiness_wait_behavior {
|
match process_readiness_wait_behavior {
|
||||||
ProcessReadinessWaitBehavior::NoStartupWait => {}
|
ProcessReadinessWaitBehavior::NoStartupWait => {},
|
||||||
ProcessReadinessWaitBehavior::WaitDuration(duration) => std::thread::sleep(duration),
|
ProcessReadinessWaitBehavior::WaitDuration(duration) => std::thread::sleep(duration),
|
||||||
ProcessReadinessWaitBehavior::TimeBoundedWaitFunction {
|
ProcessReadinessWaitBehavior::TimeBoundedWaitFunction {
|
||||||
max_wait_duration,
|
max_wait_duration,
|
||||||
@@ -126,35 +119,23 @@ impl Process {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
ProcessReadinessWaitBehavior::WaitForCommandToExit => {
|
ProcessReadinessWaitBehavior::WaitForCommandToExit => {
|
||||||
if !child
|
if !child.wait().context("Failed waiting for process to finish")?.success() {
|
||||||
.wait()
|
|
||||||
.context("Failed waiting for process to finish")?
|
|
||||||
.success()
|
|
||||||
{
|
|
||||||
anyhow::bail!("Failed to spawn command");
|
anyhow::bail!("Failed to spawn command");
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self { child, stdout_logs_file, stderr_logs_file })
|
||||||
child,
|
|
||||||
stdout_logs_file,
|
|
||||||
stderr_logs_file,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
self.stdout_logs_file.flush().expect("Failed to flush the stdout logs file");
|
||||||
.flush()
|
self.stderr_logs_file.flush().expect("Failed to flush the stderr logs file");
|
||||||
.expect("Failed to flush the stdout logs file");
|
|
||||||
self.stderr_logs_file
|
|
||||||
.flush()
|
|
||||||
.expect("Failed to flush the stderr logs file");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -94,8 +94,8 @@ impl GethNode {
|
|||||||
const TRANSACTION_INDEXING_ERROR: &str = "transaction indexing is in progress";
|
const TRANSACTION_INDEXING_ERROR: &str = "transaction indexing is in progress";
|
||||||
const TRANSACTION_TRACING_ERROR: &str = "historical state not available in path scheme yet";
|
const TRANSACTION_TRACING_ERROR: &str = "historical state not available in path scheme yet";
|
||||||
|
|
||||||
const RECEIPT_POLLING_DURATION: Duration = Duration::from_secs(5 * 60);
|
const RECEIPT_POLLING_DURATION: Duration = Duration::from_secs(10);
|
||||||
const TRACE_POLLING_DURATION: Duration = Duration::from_secs(60);
|
const TRACE_POLLING_DURATION: Duration = Duration::from_secs(10);
|
||||||
|
|
||||||
pub fn new(
|
pub fn new(
|
||||||
context: impl AsRef<WorkingDirectoryConfiguration>
|
context: impl AsRef<WorkingDirectoryConfiguration>
|
||||||
@@ -108,9 +108,7 @@ 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
|
let geth_directory = working_directory_configuration.as_path().join(Self::BASE_DIRECTORY);
|
||||||
.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());
|
||||||
|
|
||||||
@@ -139,10 +137,7 @@ impl GethNode {
|
|||||||
signers::local::PrivateKeySigner,
|
signers::local::PrivateKeySigner,
|
||||||
};
|
};
|
||||||
|
|
||||||
let key_str = private_key
|
let key_str = private_key.trim().strip_prefix("0x").unwrap_or(private_key.trim());
|
||||||
.trim()
|
|
||||||
.strip_prefix("0x")
|
|
||||||
.unwrap_or(private_key.trim());
|
|
||||||
let key_bytes = alloy::hex::decode(key_str)
|
let key_bytes = alloy::hex::decode(key_str)
|
||||||
.map_err(|e| anyhow::anyhow!("Failed to decode private key hex: {}", e))?;
|
.map_err(|e| anyhow::anyhow!("Failed to decode private key hex: {}", e))?;
|
||||||
|
|
||||||
@@ -336,15 +331,14 @@ impl GethNode {
|
|||||||
ProcessReadinessWaitBehavior::TimeBoundedWaitFunction {
|
ProcessReadinessWaitBehavior::TimeBoundedWaitFunction {
|
||||||
max_wait_duration: self.start_timeout,
|
max_wait_duration: self.start_timeout,
|
||||||
check_function: Box::new(|_, stderr_line| match stderr_line {
|
check_function: Box::new(|_, stderr_line| match stderr_line {
|
||||||
Some(line) => {
|
Some(line) =>
|
||||||
if line.contains(Self::ERROR_MARKER) {
|
if line.contains(Self::ERROR_MARKER) {
|
||||||
anyhow::bail!("Failed to start geth {line}");
|
anyhow::bail!("Failed to start geth {line}");
|
||||||
} else if line.contains(Self::READY_MARKER) {
|
} else if line.contains(Self::READY_MARKER) {
|
||||||
Ok(true)
|
Ok(true)
|
||||||
} else {
|
} else {
|
||||||
Ok(false)
|
Ok(false)
|
||||||
}
|
},
|
||||||
}
|
|
||||||
None => Ok(false),
|
None => Ok(false),
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
@@ -357,7 +351,7 @@ impl GethNode {
|
|||||||
self.shutdown()
|
self.shutdown()
|
||||||
.context("Failed to gracefully shutdown after geth start error")?;
|
.context("Failed to gracefully shutdown after geth start error")?;
|
||||||
return Err(err);
|
return Err(err);
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(self)
|
Ok(self)
|
||||||
@@ -497,15 +491,12 @@ impl EthereumNode for GethNode {
|
|||||||
true => Ok(ControlFlow::Continue(())),
|
true => Ok(ControlFlow::Continue(())),
|
||||||
false => Err(error.into()),
|
false => Err(error.into()),
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
.instrument(tracing::info_span!(
|
.instrument(tracing::info_span!("Awaiting transaction receipt", ?transaction_hash))
|
||||||
"Awaiting transaction receipt",
|
|
||||||
?transaction_hash
|
|
||||||
))
|
|
||||||
.await
|
.await
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -517,10 +508,8 @@ 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 = self
|
let provider =
|
||||||
.provider()
|
self.provider().await.context("Failed to create provider for tracing")?;
|
||||||
.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)),
|
||||||
@@ -528,10 +517,7 @@ 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
|
match provider.debug_trace_transaction(tx_hash, trace_options).await {
|
||||||
.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();
|
||||||
@@ -539,7 +525,7 @@ impl EthereumNode for GethNode {
|
|||||||
true => Ok(ControlFlow::Continue(())),
|
true => Ok(ControlFlow::Continue(())),
|
||||||
false => Err(error.into()),
|
false => Err(error.into()),
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -754,10 +740,7 @@ 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
|
block.header.base_fee_per_gas.context("Failed to get the base fee per gas")
|
||||||
.header
|
|
||||||
.base_fee_per_gas
|
|
||||||
.context("Failed to get the base fee per gas")
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -874,11 +857,7 @@ mod tests {
|
|||||||
// Arrange
|
// Arrange
|
||||||
let (context, node) = shared_state();
|
let (context, node) = shared_state();
|
||||||
|
|
||||||
let account_address = context
|
let account_address = context.wallet_configuration.wallet().default_signer().address();
|
||||||
.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));
|
||||||
@@ -901,10 +880,7 @@ mod tests {
|
|||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
let version = version.expect("Failed to get the version");
|
let version = version.expect("Failed to get the version");
|
||||||
assert!(
|
assert!(version.starts_with("geth version"), "expected version string, got: '{version}'");
|
||||||
version.starts_with("geth version"),
|
|
||||||
"expected version string, got: '{version}'"
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -928,12 +904,8 @@ mod tests {
|
|||||||
let node = shared_node();
|
let node = shared_node();
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
let gas_limit = node
|
let gas_limit =
|
||||||
.resolver()
|
node.resolver().await.unwrap().block_gas_limit(BlockNumberOrTag::Latest).await;
|
||||||
.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");
|
||||||
@@ -946,12 +918,8 @@ mod tests {
|
|||||||
let node = shared_node();
|
let node = shared_node();
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
let coinbase = node
|
let coinbase =
|
||||||
.resolver()
|
node.resolver().await.unwrap().block_coinbase(BlockNumberOrTag::Latest).await;
|
||||||
.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");
|
||||||
@@ -964,12 +932,8 @@ mod tests {
|
|||||||
let node = shared_node();
|
let node = shared_node();
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
let block_difficulty = node
|
let block_difficulty =
|
||||||
.resolver()
|
node.resolver().await.unwrap().block_difficulty(BlockNumberOrTag::Latest).await;
|
||||||
.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");
|
||||||
@@ -982,12 +946,7 @@ mod tests {
|
|||||||
let node = shared_node();
|
let node = shared_node();
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
let block_hash = node
|
let block_hash = node.resolver().await.unwrap().block_hash(BlockNumberOrTag::Latest).await;
|
||||||
.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");
|
||||||
@@ -1000,12 +959,8 @@ mod tests {
|
|||||||
let node = shared_node();
|
let node = shared_node();
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
let block_timestamp = node
|
let block_timestamp =
|
||||||
.resolver()
|
node.resolver().await.unwrap().block_timestamp(BlockNumberOrTag::Latest).await;
|
||||||
.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");
|
||||||
|
|||||||
@@ -116,7 +116,7 @@ impl LighthouseGethNode {
|
|||||||
const TRANSACTION_INDEXING_ERROR: &str = "transaction indexing is in progress";
|
const TRANSACTION_INDEXING_ERROR: &str = "transaction indexing is in progress";
|
||||||
const TRANSACTION_TRACING_ERROR: &str = "historical state not available in path scheme yet";
|
const TRANSACTION_TRACING_ERROR: &str = "historical state not available in path scheme yet";
|
||||||
|
|
||||||
const RECEIPT_POLLING_DURATION: Duration = Duration::from_secs(5 * 60);
|
const RECEIPT_POLLING_DURATION: Duration = Duration::from_secs(30);
|
||||||
const TRACE_POLLING_DURATION: Duration = Duration::from_secs(60);
|
const TRACE_POLLING_DURATION: Duration = Duration::from_secs(60);
|
||||||
|
|
||||||
const VALIDATOR_MNEMONIC: &str = "giant issue aisle success illegal bike spike question tent bar rely arctic volcano long crawl hungry vocal artwork sniff fantasy very lucky have athlete";
|
const VALIDATOR_MNEMONIC: &str = "giant issue aisle success illegal bike spike question tent bar rely arctic volcano long crawl hungry vocal artwork sniff fantasy very lucky have athlete";
|
||||||
@@ -132,9 +132,7 @@ 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
|
let geth_directory = working_directory_configuration.as_path().join(Self::BASE_DIRECTORY);
|
||||||
.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());
|
||||||
|
|
||||||
@@ -147,10 +145,7 @@ impl LighthouseGethNode {
|
|||||||
http_connection_string: String::default(),
|
http_connection_string: String::default(),
|
||||||
enclave_name: format!(
|
enclave_name: format!(
|
||||||
"enclave-{}-{}",
|
"enclave-{}-{}",
|
||||||
SystemTime::now()
|
SystemTime::now().duration_since(UNIX_EPOCH).expect("Must not fail").as_nanos(),
|
||||||
.duration_since(UNIX_EPOCH)
|
|
||||||
.expect("Must not fail")
|
|
||||||
.as_nanos(),
|
|
||||||
id
|
id
|
||||||
),
|
),
|
||||||
|
|
||||||
@@ -526,15 +521,12 @@ impl LighthouseGethNode {
|
|||||||
true => Ok(ControlFlow::Continue(())),
|
true => Ok(ControlFlow::Continue(())),
|
||||||
false => Err(error.into()),
|
false => Err(error.into()),
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
.instrument(tracing::info_span!(
|
.instrument(tracing::info_span!("Awaiting transaction receipt", ?transaction_hash))
|
||||||
"Awaiting transaction receipt",
|
|
||||||
?transaction_hash
|
|
||||||
))
|
|
||||||
.await
|
.await
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -623,9 +615,7 @@ 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()
|
self.http_provider().await.context("Failed to create provider for tracing")?,
|
||||||
.await
|
|
||||||
.context("Failed to create provider for tracing")?,
|
|
||||||
);
|
);
|
||||||
poll(
|
poll(
|
||||||
Self::TRACE_POLLING_DURATION,
|
Self::TRACE_POLLING_DURATION,
|
||||||
@@ -634,10 +624,7 @@ 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
|
match provider.debug_trace_transaction(tx_hash, trace_options).await {
|
||||||
.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();
|
||||||
@@ -645,7 +632,7 @@ impl EthereumNode for LighthouseGethNode {
|
|||||||
true => Ok(ControlFlow::Continue(())),
|
true => Ok(ControlFlow::Continue(())),
|
||||||
false => Err(error.into()),
|
false => Err(error.into()),
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -859,10 +846,7 @@ 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
|
block.header.base_fee_per_gas.context("Failed to get the base fee per gas")
|
||||||
.header
|
|
||||||
.base_fee_per_gas
|
|
||||||
.context("Failed to get the base fee per gas")
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -916,11 +900,7 @@ impl Node for LighthouseGethNode {
|
|||||||
.spawn()
|
.spawn()
|
||||||
.expect("Failed to spawn the enclave kill command");
|
.expect("Failed to spawn the enclave kill command");
|
||||||
|
|
||||||
if !child
|
if !child.wait().expect("Failed to wait for the enclave kill command").success() {
|
||||||
.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
|
||||||
@@ -1146,11 +1126,7 @@ 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
|
let account_address = context.wallet_configuration.wallet().default_signer().address();
|
||||||
.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));
|
||||||
@@ -1173,10 +1149,7 @@ mod tests {
|
|||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
let version = version.expect("Failed to get the version");
|
let version = version.expect("Failed to get the version");
|
||||||
assert!(
|
assert!(version.starts_with("CLI Version"), "expected version string, got: '{version}'");
|
||||||
version.starts_with("CLI Version"),
|
|
||||||
"expected version string, got: '{version}'"
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
@@ -1200,12 +1173,8 @@ mod tests {
|
|||||||
let (_context, node) = new_node();
|
let (_context, node) = new_node();
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
let gas_limit = node
|
let gas_limit =
|
||||||
.resolver()
|
node.resolver().await.unwrap().block_gas_limit(BlockNumberOrTag::Latest).await;
|
||||||
.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");
|
||||||
@@ -1218,12 +1187,8 @@ mod tests {
|
|||||||
let (_context, node) = new_node();
|
let (_context, node) = new_node();
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
let coinbase = node
|
let coinbase =
|
||||||
.resolver()
|
node.resolver().await.unwrap().block_coinbase(BlockNumberOrTag::Latest).await;
|
||||||
.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");
|
||||||
@@ -1236,12 +1201,8 @@ mod tests {
|
|||||||
let (_context, node) = new_node();
|
let (_context, node) = new_node();
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
let block_difficulty = node
|
let block_difficulty =
|
||||||
.resolver()
|
node.resolver().await.unwrap().block_difficulty(BlockNumberOrTag::Latest).await;
|
||||||
.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");
|
||||||
@@ -1254,12 +1215,7 @@ mod tests {
|
|||||||
let (_context, node) = new_node();
|
let (_context, node) = new_node();
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
let block_hash = node
|
let block_hash = node.resolver().await.unwrap().block_hash(BlockNumberOrTag::Latest).await;
|
||||||
.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");
|
||||||
@@ -1272,12 +1228,8 @@ mod tests {
|
|||||||
let (_context, node) = new_node();
|
let (_context, node) = new_node();
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
let block_timestamp = node
|
let block_timestamp =
|
||||||
.resolver()
|
node.resolver().await.unwrap().block_timestamp(BlockNumberOrTag::Latest).await;
|
||||||
.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");
|
||||||
|
|||||||
@@ -109,9 +109,7 @@ 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)
|
let eth_rpc_path = AsRef::<EthRpcConfiguration>::as_ref(&context).path.as_path();
|
||||||
.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);
|
||||||
@@ -143,10 +141,7 @@ impl SubstrateNode {
|
|||||||
signers::local::PrivateKeySigner,
|
signers::local::PrivateKeySigner,
|
||||||
};
|
};
|
||||||
|
|
||||||
let key_str = private_key
|
let key_str = private_key.trim().strip_prefix("0x").unwrap_or(private_key.trim());
|
||||||
.trim()
|
|
||||||
.strip_prefix("0x")
|
|
||||||
.unwrap_or(private_key.trim());
|
|
||||||
let key_bytes = alloy::hex::decode(key_str)
|
let key_bytes = alloy::hex::decode(key_str)
|
||||||
.map_err(|e| anyhow::anyhow!("Failed to decode private key hex: {}", e))?;
|
.map_err(|e| anyhow::anyhow!("Failed to decode private key hex: {}", e))?;
|
||||||
|
|
||||||
@@ -320,7 +315,7 @@ impl SubstrateNode {
|
|||||||
self.shutdown()
|
self.shutdown()
|
||||||
.context("Failed to gracefully shutdown after substrate start error")?;
|
.context("Failed to gracefully shutdown after substrate start error")?;
|
||||||
return Err(err);
|
return Err(err);
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
let eth_proxy_process = Process::new(
|
let eth_proxy_process = Process::new(
|
||||||
@@ -355,7 +350,7 @@ impl SubstrateNode {
|
|||||||
self.shutdown()
|
self.shutdown()
|
||||||
.context("Failed to gracefully shutdown after eth proxy start error")?;
|
.context("Failed to gracefully shutdown after eth proxy start error")?;
|
||||||
return Err(err);
|
return Err(err);
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -365,10 +360,7 @@ impl SubstrateNode {
|
|||||||
&self,
|
&self,
|
||||||
genesis: &Genesis,
|
genesis: &Genesis,
|
||||||
) -> anyhow::Result<Vec<(String, u128)>> {
|
) -> anyhow::Result<Vec<(String, u128)>> {
|
||||||
genesis
|
genesis.alloc.iter().try_fold(Vec::new(), |mut vec, (address, acc)| {
|
||||||
.alloc
|
|
||||||
.iter()
|
|
||||||
.try_fold(Vec::new(), |mut vec, (address, acc)| {
|
|
||||||
let substrate_address = Self::eth_to_substrate_address(address);
|
let substrate_address = Self::eth_to_substrate_address(address);
|
||||||
let balance = acc.balance.try_into()?;
|
let balance = acc.balance.try_into()?;
|
||||||
vec.push((substrate_address, balance));
|
vec.push((substrate_address, balance));
|
||||||
@@ -468,10 +460,7 @@ 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
|
let provider = self.provider().await.context("Failed to create the provider")?;
|
||||||
.provider()
|
|
||||||
.await
|
|
||||||
.context("Failed to create the provider")?;
|
|
||||||
execute_transaction(provider, transaction).await
|
execute_transaction(provider, transaction).await
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -693,10 +682,7 @@ 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
|
block.header.base_fee_per_gas.context("Failed to get the base fee per gas")
|
||||||
.header
|
|
||||||
.base_fee_per_gas
|
|
||||||
.context("Failed to get the base fee per gas")
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -975,33 +961,27 @@ 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 { request, error }) => {
|
Err(UnbuiltTransactionError { request, error }) =>
|
||||||
Err(UnbuiltTransactionError::<ReviveNetwork> {
|
Err(UnbuiltTransactionError::<ReviveNetwork> {
|
||||||
request,
|
request,
|
||||||
error: match error {
|
error: match error {
|
||||||
TransactionBuilderError::InvalidTransactionRequest(tx_type, items) => {
|
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::Custom(error) =>
|
||||||
TransactionBuilderError::Signer(error)
|
TransactionBuilderError::Custom(error),
|
||||||
}
|
|
||||||
TransactionBuilderError::Custom(error) => {
|
|
||||||
TransactionBuilderError::Custom(error)
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
})
|
}),
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn build<W: alloy::network::NetworkWallet<ReviveNetwork>>(
|
async fn build<W: alloy::network::NetworkWallet<ReviveNetwork>>(
|
||||||
self,
|
self,
|
||||||
wallet: &W,
|
wallet: &W,
|
||||||
) -> Result<<ReviveNetwork as Network>::TxEnvelope, TransactionBuilderError<ReviveNetwork>>
|
) -> Result<<ReviveNetwork as Network>::TxEnvelope, TransactionBuilderError<ReviveNetwork>> {
|
||||||
{
|
|
||||||
Ok(wallet.sign_request(self).await?)
|
Ok(wallet.sign_request(self).await?)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1261,11 +1241,7 @@ 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
|
let account_address = context.wallet_configuration.wallet().default_signer().address();
|
||||||
.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));
|
||||||
@@ -1310,9 +1286,8 @@ mod tests {
|
|||||||
.expect("init failed");
|
.expect("init failed");
|
||||||
|
|
||||||
// Check that the patched chainspec file was generated
|
// Check that the patched chainspec file was generated
|
||||||
let final_chainspec_path = dummy_node
|
let final_chainspec_path =
|
||||||
.base_directory
|
dummy_node.base_directory.join(SubstrateNode::CHAIN_SPEC_JSON_FILE);
|
||||||
.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");
|
||||||
@@ -1418,10 +1393,7 @@ 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!(
|
assert_eq!(result, expected_ss58, "Mismatch for Ethereum address {eth_addr}");
|
||||||
result, expected_ss58,
|
|
||||||
"Mismatch for Ethereum address {eth_addr}"
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1472,12 +1444,8 @@ mod tests {
|
|||||||
let node = shared_node();
|
let node = shared_node();
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
let gas_limit = node
|
let gas_limit =
|
||||||
.resolver()
|
node.resolver().await.unwrap().block_gas_limit(BlockNumberOrTag::Latest).await;
|
||||||
.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");
|
||||||
@@ -1490,12 +1458,8 @@ mod tests {
|
|||||||
let node = shared_node();
|
let node = shared_node();
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
let coinbase = node
|
let coinbase =
|
||||||
.resolver()
|
node.resolver().await.unwrap().block_coinbase(BlockNumberOrTag::Latest).await;
|
||||||
.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");
|
||||||
@@ -1508,12 +1472,8 @@ mod tests {
|
|||||||
let node = shared_node();
|
let node = shared_node();
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
let block_difficulty = node
|
let block_difficulty =
|
||||||
.resolver()
|
node.resolver().await.unwrap().block_difficulty(BlockNumberOrTag::Latest).await;
|
||||||
.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");
|
||||||
@@ -1526,12 +1486,7 @@ mod tests {
|
|||||||
let node = shared_node();
|
let node = shared_node();
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
let block_hash = node
|
let block_hash = node.resolver().await.unwrap().block_hash(BlockNumberOrTag::Latest).await;
|
||||||
.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");
|
||||||
@@ -1544,12 +1499,8 @@ mod tests {
|
|||||||
let node = shared_node();
|
let node = shared_node();
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
let block_timestamp = node
|
let block_timestamp =
|
||||||
.resolver()
|
node.resolver().await.unwrap().block_timestamp(BlockNumberOrTag::Latest).await;
|
||||||
.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");
|
||||||
|
|||||||
@@ -122,14 +122,10 @@ impl ZombieNode {
|
|||||||
+ AsRef<EthRpcConfiguration>
|
+ AsRef<EthRpcConfiguration>
|
||||||
+ AsRef<WalletConfiguration>,
|
+ AsRef<WalletConfiguration>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let eth_proxy_binary = AsRef::<EthRpcConfiguration>::as_ref(&context)
|
let eth_proxy_binary = AsRef::<EthRpcConfiguration>::as_ref(&context).path.to_owned();
|
||||||
.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
|
let base_directory = working_directory_path.join(Self::BASE_DIRECTORY).join(id.to_string());
|
||||||
.join(Self::BASE_DIRECTORY)
|
|
||||||
.join(id.to_string());
|
|
||||||
let base_directory = base_directory.canonicalize().unwrap_or(base_directory);
|
let base_directory = base_directory.canonicalize().unwrap_or(base_directory);
|
||||||
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();
|
||||||
@@ -197,10 +193,8 @@ impl ZombieNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn spawn_process(&mut self) -> anyhow::Result<()> {
|
fn spawn_process(&mut self) -> anyhow::Result<()> {
|
||||||
let network_config = self
|
let network_config =
|
||||||
.network_config
|
self.network_config.clone().context("Node not initialized, call init() first")?;
|
||||||
.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 {
|
||||||
@@ -248,7 +242,7 @@ impl ZombieNode {
|
|||||||
self.shutdown()
|
self.shutdown()
|
||||||
.context("Failed to gracefully shutdown after eth proxy start error")?;
|
.context("Failed to gracefully shutdown after eth proxy start error")?;
|
||||||
return Err(err);
|
return Err(err);
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
tracing::debug!("eth-rpc is up");
|
tracing::debug!("eth-rpc is up");
|
||||||
@@ -272,10 +266,7 @@ impl ZombieNode {
|
|||||||
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!(
|
anyhow::bail!("Build chain-spec failed: {}", String::from_utf8_lossy(&output.stderr));
|
||||||
"Build chain-spec failed: {}",
|
|
||||||
String::from_utf8_lossy(&output.stderr)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let content = String::from_utf8(output.stdout)
|
let content = String::from_utf8(output.stdout)
|
||||||
@@ -336,10 +327,7 @@ impl ZombieNode {
|
|||||||
&self,
|
&self,
|
||||||
genesis: &Genesis,
|
genesis: &Genesis,
|
||||||
) -> anyhow::Result<Vec<(String, u128)>> {
|
) -> anyhow::Result<Vec<(String, u128)>> {
|
||||||
genesis
|
genesis.alloc.iter().try_fold(Vec::new(), |mut vec, (address, acc)| {
|
||||||
.alloc
|
|
||||||
.iter()
|
|
||||||
.try_fold(Vec::new(), |mut vec, (address, acc)| {
|
|
||||||
let polkadot_address = Self::eth_to_polkadot_address(address);
|
let polkadot_address = Self::eth_to_polkadot_address(address);
|
||||||
let balance = acc.balance.try_into()?;
|
let balance = acc.balance.try_into()?;
|
||||||
vec.push((polkadot_address, balance));
|
vec.push((polkadot_address, balance));
|
||||||
@@ -440,16 +428,20 @@ impl EthereumNode for ZombieNode {
|
|||||||
transaction: alloy::rpc::types::TransactionRequest,
|
transaction: alloy::rpc::types::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 receipt = self
|
let pending = self
|
||||||
.provider()
|
.provider()
|
||||||
.await
|
.await
|
||||||
.context("Failed to create provider for transaction submission")?
|
.context("Failed to create provider for transaction submission")?
|
||||||
.send_transaction(transaction)
|
.send_transaction(transaction)
|
||||||
.await
|
.await
|
||||||
.context("Failed to submit transaction to proxy")?
|
.context("Failed to submit transaction to proxy")?;
|
||||||
.get_receipt()
|
|
||||||
|
let receipt =
|
||||||
|
tokio::time::timeout(std::time::Duration::from_secs(120), pending.get_receipt())
|
||||||
.await
|
.await
|
||||||
|
.context("Timeout waiting for transaction receipt")?
|
||||||
.context("Failed to fetch transaction receipt from proxy")?;
|
.context("Failed to fetch transaction receipt from proxy")?;
|
||||||
|
|
||||||
Ok(receipt)
|
Ok(receipt)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -675,10 +667,7 @@ 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
|
block.header.base_fee_per_gas.context("Failed to get the base fee per gas")
|
||||||
.header
|
|
||||||
.base_fee_per_gas
|
|
||||||
.context("Failed to get the base fee per gas")
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -790,10 +779,8 @@ 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 = ZombieNode::new(
|
let mut node =
|
||||||
context.polkadot_parachain_configuration.path.clone(),
|
ZombieNode::new(context.polkadot_parachain_configuration.path.clone(), &context);
|
||||||
&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();
|
||||||
|
|
||||||
@@ -858,14 +845,11 @@ mod tests {
|
|||||||
"#;
|
"#;
|
||||||
|
|
||||||
let context = test_config();
|
let context = test_config();
|
||||||
let mut node = ZombieNode::new(
|
let mut node =
|
||||||
context.polkadot_parachain_configuration.path.clone(),
|
ZombieNode::new(context.polkadot_parachain_configuration.path.clone(), &context);
|
||||||
&context,
|
|
||||||
);
|
|
||||||
|
|
||||||
// Call `init()`
|
// Call `init()`
|
||||||
node.init(serde_json::from_str(genesis_content).unwrap())
|
node.init(serde_json::from_str(genesis_content).unwrap()).expect("init failed");
|
||||||
.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);
|
||||||
@@ -906,10 +890,7 @@ mod tests {
|
|||||||
"#;
|
"#;
|
||||||
|
|
||||||
let context = test_config();
|
let context = test_config();
|
||||||
let node = ZombieNode::new(
|
let node = ZombieNode::new(context.polkadot_parachain_configuration.path.clone(), &context);
|
||||||
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())
|
||||||
@@ -971,10 +952,7 @@ 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!(
|
assert_eq!(result, expected_ss58, "Mismatch for Ethereum address {eth_addr}");
|
||||||
result, expected_ss58,
|
|
||||||
"Mismatch for Ethereum address {eth_addr}"
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -982,10 +960,7 @@ 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(
|
let node = ZombieNode::new(context.polkadot_parachain_configuration.path.clone(), &context);
|
||||||
context.polkadot_parachain_configuration.path.clone(),
|
|
||||||
&context,
|
|
||||||
);
|
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
let version = node.eth_rpc_version().unwrap();
|
let version = node.eth_rpc_version().unwrap();
|
||||||
@@ -1001,10 +976,7 @@ mod tests {
|
|||||||
fn version_works() {
|
fn version_works() {
|
||||||
// Arrange
|
// Arrange
|
||||||
let context = test_config();
|
let context = test_config();
|
||||||
let node = ZombieNode::new(
|
let node = ZombieNode::new(context.polkadot_parachain_configuration.path.clone(), &context);
|
||||||
context.polkadot_parachain_configuration.path.clone(),
|
|
||||||
&context,
|
|
||||||
);
|
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
let version = node.version().unwrap();
|
let version = node.version().unwrap();
|
||||||
@@ -1042,12 +1014,8 @@ mod tests {
|
|||||||
let node = shared_node().await;
|
let node = shared_node().await;
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
let gas_limit = node
|
let gas_limit =
|
||||||
.resolver()
|
node.resolver().await.unwrap().block_gas_limit(BlockNumberOrTag::Latest).await;
|
||||||
.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");
|
||||||
@@ -1060,12 +1028,8 @@ mod tests {
|
|||||||
let node = shared_node().await;
|
let node = shared_node().await;
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
let coinbase = node
|
let coinbase =
|
||||||
.resolver()
|
node.resolver().await.unwrap().block_coinbase(BlockNumberOrTag::Latest).await;
|
||||||
.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");
|
||||||
@@ -1078,12 +1042,8 @@ mod tests {
|
|||||||
let node = shared_node().await;
|
let node = shared_node().await;
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
let block_difficulty = node
|
let block_difficulty =
|
||||||
.resolver()
|
node.resolver().await.unwrap().block_difficulty(BlockNumberOrTag::Latest).await;
|
||||||
.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");
|
||||||
@@ -1096,12 +1056,7 @@ mod tests {
|
|||||||
let node = shared_node().await;
|
let node = shared_node().await;
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
let block_hash = node
|
let block_hash = node.resolver().await.unwrap().block_hash(BlockNumberOrTag::Latest).await;
|
||||||
.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");
|
||||||
@@ -1114,12 +1069,8 @@ mod tests {
|
|||||||
let node = shared_node().await;
|
let node = shared_node().await;
|
||||||
|
|
||||||
// Act
|
// Act
|
||||||
let block_timestamp = node
|
let block_timestamp =
|
||||||
.resolver()
|
node.resolver().await.unwrap().block_timestamp(BlockNumberOrTag::Latest).await;
|
||||||
.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");
|
||||||
|
|||||||
@@ -11,9 +11,7 @@ pub struct ConcurrencyLimiterLayer {
|
|||||||
|
|
||||||
impl ConcurrencyLimiterLayer {
|
impl ConcurrencyLimiterLayer {
|
||||||
pub fn new(permit_count: usize) -> Self {
|
pub fn new(permit_count: usize) -> Self {
|
||||||
Self {
|
Self { semaphore: Arc::new(Semaphore::new(permit_count)) }
|
||||||
semaphore: Arc::new(Semaphore::new(permit_count)),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -21,10 +19,7 @@ impl<S> Layer<S> for ConcurrencyLimiterLayer {
|
|||||||
type Service = ConcurrencyLimiterService<S>;
|
type Service = ConcurrencyLimiterService<S>;
|
||||||
|
|
||||||
fn layer(&self, inner: S) -> Self::Service {
|
fn layer(&self, inner: S) -> Self::Service {
|
||||||
ConcurrencyLimiterService {
|
ConcurrencyLimiterService { service: inner, semaphore: self.semaphore.clone() }
|
||||||
service: inner,
|
|
||||||
semaphore: self.semaphore.clone(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -55,10 +50,7 @@ where
|
|||||||
let future = self.service.call(req);
|
let future = self.service.call(req);
|
||||||
|
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
let _permit = semaphore
|
let _permit = semaphore.acquire().await.expect("Semaphore has been closed");
|
||||||
.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"
|
||||||
|
|||||||
@@ -21,18 +21,13 @@ impl FallbackGasFiller {
|
|||||||
default_max_fee_per_gas: u128,
|
default_max_fee_per_gas: u128,
|
||||||
default_priority_fee: u128,
|
default_priority_fee: u128,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self { inner: GasFiller, default_gas_limit, default_max_fee_per_gas, default_priority_fee }
|
||||||
inner: GasFiller,
|
|
||||||
default_gas_limit,
|
|
||||||
default_max_fee_per_gas,
|
|
||||||
default_priority_fee,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for FallbackGasFiller {
|
impl Default for FallbackGasFiller {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
FallbackGasFiller::new(25_000_000, 1_000_000_000, 1_000_000_000)
|
FallbackGasFiller::new(10_000_000, 1_000_000_000, 1_000_000_000)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -56,12 +51,9 @@ where
|
|||||||
provider: &P,
|
provider: &P,
|
||||||
tx: &<N as Network>::TransactionRequest,
|
tx: &<N as Network>::TransactionRequest,
|
||||||
) -> TransportResult<Self::Fillable> {
|
) -> TransportResult<Self::Fillable> {
|
||||||
// Try to fetch GasFiller’s “fillable” (gas_price, base_fee, estimate_gas, …)
|
// Try to fetch GasFiller's "fillable" (gas_price, base_fee, estimate_gas, …)
|
||||||
// If it errors (i.e. tx would revert under eth_estimateGas), swallow it.
|
// Propagate errors so caller can handle them appropriately
|
||||||
match self.inner.prepare(provider, tx).await {
|
self.inner.prepare(provider, tx).await.map(Some)
|
||||||
Ok(fill) => Ok(Some(fill)),
|
|
||||||
Err(_) => Ok(None),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn fill(
|
async fn fill(
|
||||||
|
|||||||
@@ -80,10 +80,8 @@ where
|
|||||||
NonceFiller: TxFiller<N>,
|
NonceFiller: TxFiller<N>,
|
||||||
WalletFiller<W>: TxFiller<N>,
|
WalletFiller<W>: TxFiller<N>,
|
||||||
{
|
{
|
||||||
let sendable_transaction = provider
|
let sendable_transaction =
|
||||||
.fill(transaction)
|
provider.fill(transaction).await.context("Failed to fill transaction")?;
|
||||||
.await
|
|
||||||
.context("Failed to fill transaction")?;
|
|
||||||
|
|
||||||
let transaction_envelope = sendable_transaction
|
let transaction_envelope = sendable_transaction
|
||||||
.try_into_envelope()
|
.try_into_envelope()
|
||||||
@@ -100,29 +98,27 @@ where
|
|||||||
} else {
|
} else {
|
||||||
return Err(error).context(format!("Failed to submit transaction {tx_hash}"));
|
return Err(error).context(format!("Failed to submit transaction {tx_hash}"));
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
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.watch().await.context(format!(
|
let tx_hash = pending_transaction
|
||||||
"Transaction inclusion watching timeout for {tx_hash}"
|
.watch()
|
||||||
))?;
|
.await
|
||||||
|
.context(format!("Transaction inclusion watching timeout for {tx_hash}"))?;
|
||||||
|
|
||||||
poll(
|
debug!(%tx_hash, "Transaction included, polling for receipt");
|
||||||
Duration::from_secs(60),
|
|
||||||
PollingWaitBehavior::Constant(Duration::from_secs(3)),
|
poll(Duration::from_secs(30), PollingWaitBehavior::Constant(Duration::from_secs(3)), || {
|
||||||
|| {
|
|
||||||
let provider = provider.clone();
|
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 timed out for {tx_hash}"))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -66,50 +66,45 @@ impl ReportAggregator {
|
|||||||
match event {
|
match event {
|
||||||
RunnerEvent::SubscribeToEvents(event) => {
|
RunnerEvent::SubscribeToEvents(event) => {
|
||||||
self.handle_subscribe_to_events_event(*event);
|
self.handle_subscribe_to_events_event(*event);
|
||||||
}
|
},
|
||||||
RunnerEvent::CorpusFileDiscovery(event) => {
|
RunnerEvent::CorpusFileDiscovery(event) =>
|
||||||
self.handle_corpus_file_discovered_event(*event)
|
self.handle_corpus_file_discovered_event(*event),
|
||||||
}
|
|
||||||
RunnerEvent::MetadataFileDiscovery(event) => {
|
RunnerEvent::MetadataFileDiscovery(event) => {
|
||||||
self.handle_metadata_file_discovery_event(*event);
|
self.handle_metadata_file_discovery_event(*event);
|
||||||
}
|
},
|
||||||
RunnerEvent::TestCaseDiscovery(event) => {
|
RunnerEvent::TestCaseDiscovery(event) => {
|
||||||
self.handle_test_case_discovery(*event);
|
self.handle_test_case_discovery(*event);
|
||||||
}
|
},
|
||||||
RunnerEvent::TestSucceeded(event) => {
|
RunnerEvent::TestSucceeded(event) => {
|
||||||
self.handle_test_succeeded_event(*event);
|
self.handle_test_succeeded_event(*event);
|
||||||
}
|
},
|
||||||
RunnerEvent::TestFailed(event) => {
|
RunnerEvent::TestFailed(event) => {
|
||||||
self.handle_test_failed_event(*event);
|
self.handle_test_failed_event(*event);
|
||||||
}
|
},
|
||||||
RunnerEvent::TestIgnored(event) => {
|
RunnerEvent::TestIgnored(event) => {
|
||||||
self.handle_test_ignored_event(*event);
|
self.handle_test_ignored_event(*event);
|
||||||
}
|
},
|
||||||
RunnerEvent::NodeAssigned(event) => {
|
RunnerEvent::NodeAssigned(event) => {
|
||||||
self.handle_node_assigned_event(*event);
|
self.handle_node_assigned_event(*event);
|
||||||
}
|
},
|
||||||
RunnerEvent::PreLinkContractsCompilationSucceeded(event) => {
|
RunnerEvent::PreLinkContractsCompilationSucceeded(event) =>
|
||||||
self.handle_pre_link_contracts_compilation_succeeded_event(*event)
|
self.handle_pre_link_contracts_compilation_succeeded_event(*event),
|
||||||
}
|
RunnerEvent::PostLinkContractsCompilationSucceeded(event) =>
|
||||||
RunnerEvent::PostLinkContractsCompilationSucceeded(event) => {
|
self.handle_post_link_contracts_compilation_succeeded_event(*event),
|
||||||
self.handle_post_link_contracts_compilation_succeeded_event(*event)
|
RunnerEvent::PreLinkContractsCompilationFailed(event) =>
|
||||||
}
|
self.handle_pre_link_contracts_compilation_failed_event(*event),
|
||||||
RunnerEvent::PreLinkContractsCompilationFailed(event) => {
|
RunnerEvent::PostLinkContractsCompilationFailed(event) =>
|
||||||
self.handle_pre_link_contracts_compilation_failed_event(*event)
|
self.handle_post_link_contracts_compilation_failed_event(*event),
|
||||||
}
|
|
||||||
RunnerEvent::PostLinkContractsCompilationFailed(event) => {
|
|
||||||
self.handle_post_link_contracts_compilation_failed_event(*event)
|
|
||||||
}
|
|
||||||
RunnerEvent::LibrariesDeployed(event) => {
|
RunnerEvent::LibrariesDeployed(event) => {
|
||||||
self.handle_libraries_deployed_event(*event);
|
self.handle_libraries_deployed_event(*event);
|
||||||
}
|
},
|
||||||
RunnerEvent::ContractDeployed(event) => {
|
RunnerEvent::ContractDeployed(event) => {
|
||||||
self.handle_contract_deployed_event(*event);
|
self.handle_contract_deployed_event(*event);
|
||||||
}
|
},
|
||||||
RunnerEvent::Completion(event) => {
|
RunnerEvent::Completion(event) => {
|
||||||
self.handle_completion(*event);
|
self.handle_completion(*event);
|
||||||
break;
|
break;
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
debug!("Report aggregation completed");
|
debug!("Report aggregation completed");
|
||||||
@@ -123,12 +118,8 @@ impl ReportAggregator {
|
|||||||
file_name.push_str(".json");
|
file_name.push_str(".json");
|
||||||
file_name
|
file_name
|
||||||
};
|
};
|
||||||
let file_path = self
|
let file_path =
|
||||||
.report
|
self.report.context.working_directory_configuration().as_path().join(file_name);
|
||||||
.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)
|
||||||
@@ -136,10 +127,7 @@ impl ReportAggregator {
|
|||||||
.read(false)
|
.read(false)
|
||||||
.open(&file_path)
|
.open(&file_path)
|
||||||
.with_context(|| {
|
.with_context(|| {
|
||||||
format!(
|
format!("Failed to open report file for writing: {}", file_path.display())
|
||||||
"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())
|
||||||
@@ -180,9 +168,8 @@ impl ReportAggregator {
|
|||||||
|
|
||||||
// Add information on the fact that the case was ignored to the report.
|
// Add information on the fact that the case was ignored to the report.
|
||||||
let test_case_report = self.test_case_report(&event.test_specifier);
|
let test_case_report = self.test_case_report(&event.test_specifier);
|
||||||
test_case_report.status = Some(TestCaseStatus::Succeeded {
|
test_case_report.status =
|
||||||
steps_executed: event.steps_executed,
|
Some(TestCaseStatus::Succeeded { steps_executed: event.steps_executed });
|
||||||
});
|
|
||||||
self.handle_post_test_case_status_update(&event.test_specifier);
|
self.handle_post_test_case_status_update(&event.test_specifier);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -197,9 +184,7 @@ impl ReportAggregator {
|
|||||||
|
|
||||||
// Add information on the fact that the case was ignored to the report.
|
// Add information on the fact that the case was ignored to the report.
|
||||||
let test_case_report = self.test_case_report(&event.test_specifier);
|
let test_case_report = self.test_case_report(&event.test_specifier);
|
||||||
test_case_report.status = Some(TestCaseStatus::Failed {
|
test_case_report.status = Some(TestCaseStatus::Failed { reason: event.reason });
|
||||||
reason: event.reason,
|
|
||||||
});
|
|
||||||
self.handle_post_test_case_status_update(&event.test_specifier);
|
self.handle_post_test_case_status_update(&event.test_specifier);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -241,10 +226,7 @@ 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 {
|
||||||
@@ -276,29 +258,13 @@ impl ReportAggregator {
|
|||||||
&mut self,
|
&mut self,
|
||||||
event: PreLinkContractsCompilationSucceededEvent,
|
event: PreLinkContractsCompilationSucceededEvent,
|
||||||
) {
|
) {
|
||||||
let include_input = self
|
let include_input = self.report.context.report_configuration().include_compiler_input;
|
||||||
.report
|
let include_output = self.report.context.report_configuration().include_compiler_output;
|
||||||
.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);
|
||||||
|
|
||||||
let compiler_input = if include_input {
|
let compiler_input = if include_input { event.compiler_input } else { None };
|
||||||
event.compiler_input
|
let compiler_output = if include_output { Some(event.compiler_output) } else { None };
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
let compiler_output = if include_output {
|
|
||||||
Some(event.compiler_output)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
execution_information.pre_link_compilation_status = Some(CompilationStatus::Success {
|
execution_information.pre_link_compilation_status = Some(CompilationStatus::Success {
|
||||||
is_cached: event.is_cached,
|
is_cached: event.is_cached,
|
||||||
@@ -313,29 +279,13 @@ impl ReportAggregator {
|
|||||||
&mut self,
|
&mut self,
|
||||||
event: PostLinkContractsCompilationSucceededEvent,
|
event: PostLinkContractsCompilationSucceededEvent,
|
||||||
) {
|
) {
|
||||||
let include_input = self
|
let include_input = self.report.context.report_configuration().include_compiler_input;
|
||||||
.report
|
let include_output = self.report.context.report_configuration().include_compiler_output;
|
||||||
.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);
|
||||||
|
|
||||||
let compiler_input = if include_input {
|
let compiler_input = if include_input { event.compiler_input } else { None };
|
||||||
event.compiler_input
|
let compiler_output = if include_output { Some(event.compiler_output) } else { None };
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
let compiler_output = if include_output {
|
|
||||||
Some(event.compiler_output)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
execution_information.post_link_compilation_status = Some(CompilationStatus::Success {
|
execution_information.post_link_compilation_status = Some(CompilationStatus::Success {
|
||||||
is_cached: event.is_cached,
|
is_cached: event.is_cached,
|
||||||
@@ -375,8 +325,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)
|
self.execution_information(&event.execution_specifier).deployed_libraries =
|
||||||
.deployed_libraries = Some(event.libraries);
|
Some(event.libraries);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_contract_deployed_event(&mut self, event: ContractDeployedEvent) {
|
fn handle_contract_deployed_event(&mut self, event: ContractDeployedEvent) {
|
||||||
|
|||||||
@@ -34,19 +34,11 @@ pub(crate) async fn get_or_download(
|
|||||||
}
|
}
|
||||||
|
|
||||||
create_dir_all(&target_directory).with_context(|| {
|
create_dir_all(&target_directory).with_context(|| {
|
||||||
format!(
|
format!("Failed to create solc cache directory: {}", target_directory.display())
|
||||||
"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(|| {
|
.with_context(|| format!("Failed to write downloaded solc to {}", target_file.display()))?;
|
||||||
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))
|
||||||
@@ -70,12 +62,7 @@ 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(
|
file.write_all(&downloader.download().await.context("Failed to download solc binary bytes")?)
|
||||||
&downloader
|
|
||||||
.download()
|
|
||||||
.await
|
|
||||||
.context("Failed to download solc binary bytes")?,
|
|
||||||
)
|
|
||||||
.with_context(|| format!("Failed to write solc binary to {}", path.display()))?;
|
.with_context(|| format!("Failed to write solc binary to {}", path.display()))?;
|
||||||
file.flush()
|
file.flush()
|
||||||
.with_context(|| format!("Failed to flush file {}", path.display()))?;
|
.with_context(|| format!("Failed to flush file {}", path.display()))?;
|
||||||
@@ -91,17 +78,11 @@ 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!(
|
format!("Failed to spawn xattr to remove quarantine attribute on {}", path.display())
|
||||||
"Failed to spawn xattr to remove quarantine attribute on {}",
|
|
||||||
path.display()
|
|
||||||
)
|
|
||||||
})?
|
})?
|
||||||
.wait()
|
.wait()
|
||||||
.with_context(|| {
|
.with_context(|| {
|
||||||
format!(
|
format!("Failed waiting for xattr operation to complete on {}", path.display())
|
||||||
"Failed waiting for xattr operation to complete on {}",
|
|
||||||
path.display()
|
|
||||||
)
|
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
@@ -67,11 +67,7 @@ impl SolcDownloader {
|
|||||||
) -> anyhow::Result<Self> {
|
) -> anyhow::Result<Self> {
|
||||||
let version_or_requirement = version.into();
|
let version_or_requirement = version.into();
|
||||||
match version_or_requirement {
|
match version_or_requirement {
|
||||||
VersionOrRequirement::Version(version) => Ok(Self {
|
VersionOrRequirement::Version(version) => Ok(Self { version, target, list }),
|
||||||
version,
|
|
||||||
target,
|
|
||||||
list,
|
|
||||||
}),
|
|
||||||
VersionOrRequirement::Requirement(requirement) => {
|
VersionOrRequirement::Requirement(requirement) => {
|
||||||
let Some(version) = List::download(list)
|
let Some(version) = List::download(list)
|
||||||
.await
|
.await
|
||||||
@@ -84,12 +80,8 @@ impl SolcDownloader {
|
|||||||
else {
|
else {
|
||||||
anyhow::bail!("Failed to find a version that satisfies {requirement:?}");
|
anyhow::bail!("Failed to find a version that satisfies {requirement:?}");
|
||||||
};
|
};
|
||||||
Ok(Self {
|
Ok(Self { version, target, list })
|
||||||
version,
|
},
|
||||||
target,
|
|
||||||
list,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -130,11 +122,7 @@ impl SolcDownloader {
|
|||||||
})?;
|
})?;
|
||||||
|
|
||||||
let path = build.path.clone();
|
let path = build.path.clone();
|
||||||
let expected_digest = build
|
let expected_digest = build.sha256.strip_prefix("0x").unwrap_or(&build.sha256).to_string();
|
||||||
.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)
|
||||||
@@ -159,54 +147,25 @@ mod tests {
|
|||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn try_get_windows() {
|
async fn try_get_windows() {
|
||||||
let version = List::download(List::WINDOWS_URL)
|
let version = List::download(List::WINDOWS_URL).await.unwrap().latest_release;
|
||||||
.await
|
SolcDownloader::windows(version).await.unwrap().download().await.unwrap();
|
||||||
.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)
|
let version = List::download(List::MACOSX_URL).await.unwrap().latest_release;
|
||||||
.await
|
SolcDownloader::macosx(version).await.unwrap().download().await.unwrap();
|
||||||
.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)
|
let version = List::download(List::LINUX_URL).await.unwrap().latest_release;
|
||||||
.await
|
SolcDownloader::linux(version).await.unwrap().download().await.unwrap();
|
||||||
.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)
|
SolcDownloader::wasm(version).await.unwrap().download().await.unwrap();
|
||||||
.await
|
|
||||||
.unwrap()
|
|
||||||
.download()
|
|
||||||
.await
|
|
||||||
.unwrap();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user