Use tracing for logging. (#29)

This commit updates how logging is done in the differential testing
harness to use `tracing` instead of using the `log` crate. This allows
us to be able to better associate logs with the cases being executed
which makes it easier to debug and understand what the harness is doing.
This commit is contained in:
Omar
2025-07-10 10:28:16 +03:00
committed by GitHub
parent de7c7d6703
commit 0513a4befb
23 changed files with 238 additions and 210 deletions
Generated
+21 -70
View File
@@ -2071,29 +2071,6 @@ dependencies = [
"syn 2.0.101", "syn 2.0.101",
] ]
[[package]]
name = "env_filter"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "186e05a59d4c50738528153b83b0b0194d3a29507dfec16eccd4b342903397d0"
dependencies = [
"log",
"regex",
]
[[package]]
name = "env_logger"
version = "0.11.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13c863f0904021b108aa8b2f55046443e6b1ebde8fd4a15c399893aae4fa069f"
dependencies = [
"anstream",
"anstyle",
"env_filter",
"jiff",
"log",
]
[[package]] [[package]]
name = "environmental" name = "environmental"
version = "1.1.4" version = "1.1.4"
@@ -2962,30 +2939,6 @@ version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
[[package]]
name = "jiff"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a194df1107f33c79f4f93d02c80798520551949d59dfad22b6157048a88cca93"
dependencies = [
"jiff-static",
"log",
"portable-atomic",
"portable-atomic-util",
"serde",
]
[[package]]
name = "jiff-static"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6c6e1db7ed32c6c71b759497fae34bf7933636f75a251b9e736555da426f6442"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.101",
]
[[package]] [[package]]
name = "js-sys" name = "js-sys"
version = "0.3.77" version = "0.3.77"
@@ -3597,21 +3550,6 @@ dependencies = [
"syn 2.0.101", "syn 2.0.101",
] ]
[[package]]
name = "portable-atomic"
version = "1.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "350e9b48cbc6b0e028b0473b114454c6316e57336ee184ceab6e53f72c178b3e"
[[package]]
name = "portable-atomic-util"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d8a2f0d8d040d7848a709caf78912debcc3f33ee4b3cac47d73d1e1069e83507"
dependencies = [
"portable-atomic",
]
[[package]] [[package]]
name = "potential_utf" name = "potential_utf"
version = "0.1.2" version = "0.1.2"
@@ -3997,13 +3935,13 @@ name = "revive-dt-compiler"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"log",
"revive-common", "revive-common",
"revive-dt-config", "revive-dt-config",
"revive-dt-solc-binaries", "revive-dt-solc-binaries",
"revive-solc-json-interface", "revive-solc-json-interface",
"semver 1.0.26", "semver 1.0.26",
"serde_json", "serde_json",
"tracing",
] ]
[[package]] [[package]]
@@ -4024,8 +3962,6 @@ dependencies = [
"alloy", "alloy",
"anyhow", "anyhow",
"clap", "clap",
"env_logger",
"log",
"rayon", "rayon",
"revive-dt-compiler", "revive-dt-compiler",
"revive-dt-config", "revive-dt-config",
@@ -4036,6 +3972,8 @@ dependencies = [
"revive-solc-json-interface", "revive-solc-json-interface",
"serde_json", "serde_json",
"temp-dir", "temp-dir",
"tracing",
"tracing-subscriber",
] ]
[[package]] [[package]]
@@ -4046,10 +3984,10 @@ dependencies = [
"alloy-primitives", "alloy-primitives",
"alloy-sol-types", "alloy-sol-types",
"anyhow", "anyhow",
"log",
"semver 1.0.26", "semver 1.0.26",
"serde", "serde",
"serde_json", "serde_json",
"tracing",
] ]
[[package]] [[package]]
@@ -4058,13 +3996,13 @@ version = "0.1.0"
dependencies = [ dependencies = [
"alloy", "alloy",
"anyhow", "anyhow",
"log",
"revive-dt-config", "revive-dt-config",
"revive-dt-node-interaction", "revive-dt-node-interaction",
"serde_json", "serde_json",
"sp-core", "sp-core",
"sp-runtime", "sp-runtime",
"temp-dir", "temp-dir",
"tracing",
] ]
[[package]] [[package]]
@@ -4073,9 +4011,9 @@ version = "0.1.0"
dependencies = [ dependencies = [
"alloy", "alloy",
"anyhow", "anyhow",
"log",
"once_cell", "once_cell",
"tokio", "tokio",
"tracing",
] ]
[[package]] [[package]]
@@ -4083,12 +4021,12 @@ name = "revive-dt-report"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"log",
"revive-dt-config", "revive-dt-config",
"revive-dt-format", "revive-dt-format",
"revive-solc-json-interface", "revive-solc-json-interface",
"serde", "serde",
"serde_json", "serde_json",
"tracing",
] ]
[[package]] [[package]]
@@ -4097,11 +4035,11 @@ version = "0.1.0"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"hex", "hex",
"log",
"reqwest", "reqwest",
"semver 1.0.26", "semver 1.0.26",
"serde", "serde",
"sha2 0.10.9", "sha2 0.10.9",
"tracing",
] ]
[[package]] [[package]]
@@ -5569,6 +5507,16 @@ dependencies = [
"tracing-core", "tracing-core",
] ]
[[package]]
name = "tracing-serde"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "704b1aeb7be0d0a84fc9828cae51dab5970fee5088f83d1dd7ee6f6246fc6ff1"
dependencies = [
"serde",
"tracing-core",
]
[[package]] [[package]]
name = "tracing-subscriber" name = "tracing-subscriber"
version = "0.3.19" version = "0.3.19"
@@ -5579,6 +5527,8 @@ dependencies = [
"nu-ansi-term", "nu-ansi-term",
"once_cell", "once_cell",
"regex", "regex",
"serde",
"serde_json",
"sharded-slab", "sharded-slab",
"smallvec", "smallvec",
"thread_local", "thread_local",
@@ -5586,6 +5536,7 @@ dependencies = [
"tracing", "tracing",
"tracing-core", "tracing-core",
"tracing-log", "tracing-log",
"tracing-serde",
] ]
[[package]] [[package]]
+14 -7
View File
@@ -4,9 +4,7 @@ members = ["crates/*"]
[workspace.package] [workspace.package]
version = "0.1.0" version = "0.1.0"
authors = [ authors = ["Parity Technologies <admin@parity.io>"]
"Parity Technologies <admin@parity.io>",
]
license = "MIT/Apache-2.0" license = "MIT/Apache-2.0"
edition = "2024" edition = "2024"
repository = "https://github.com/paritytech/revive-differential-testing.git" repository = "https://github.com/paritytech/revive-differential-testing.git"
@@ -27,22 +25,31 @@ alloy-primitives = "1.2.1"
alloy-sol-types = "1.2.1" alloy-sol-types = "1.2.1"
anyhow = "1.0" anyhow = "1.0"
clap = { version = "4", features = ["derive"] } clap = { version = "4", features = ["derive"] }
env_logger = "0.11.8"
hex = "0.4.3" hex = "0.4.3"
reqwest = { version = "0.12.15", features = ["blocking", "json"] } reqwest = { version = "0.12.15", features = ["blocking", "json"] }
log = "0.4.27"
once_cell = "1.21" once_cell = "1.21"
rayon = { version = "1.10" } rayon = { version = "1.10" }
semver = { version = "1.0", features = ["serde"] } semver = { version = "1.0", features = ["serde"] }
serde = { version = "1.0", default-features = false, features = ["derive"] } serde = { version = "1.0", default-features = false, features = ["derive"] }
serde_json = { version = "1.0", default-features = false, features = ["arbitrary_precision", "std"] } serde_json = { version = "1.0", default-features = false, features = [
"arbitrary_precision",
"std",
] }
sha2 = { version = "0.10.9" } sha2 = { version = "0.10.9" }
sp-core = "36.1.0" sp-core = "36.1.0"
sp-runtime = "41.1.0" sp-runtime = "41.1.0"
temp-dir = { version = "0.1.16" } temp-dir = { version = "0.1.16" }
tempfile = "3.3" tempfile = "3.3"
tokio = { version = "1", default-features = false, features = ["rt-multi-thread"] } tokio = { version = "1", default-features = false, features = [
"rt-multi-thread",
] }
uuid = { version = "1.8", features = ["v4"] } uuid = { version = "1.8", features = ["v4"] }
tracing = "0.1.41"
tracing-subscriber = { version = "0.3.19", default-features = false, features = [
"fmt",
"json",
"env-filter",
] }
# revive compiler # revive compiler
revive-solc-json-interface = { git = "https://github.com/paritytech/revive", rev = "3389865af7c3ff6f29a586d82157e8bc573c1a8e" } revive-solc-json-interface = { git = "https://github.com/paritytech/revive", rev = "3389865af7c3ff6f29a586d82157e8bc573c1a8e" }
+1 -1
View File
@@ -16,4 +16,4 @@ revive-dt-solc-binaries = { workspace = true }
revive-common = { workspace = true } revive-common = { workspace = true }
semver = { workspace = true } semver = { workspace = true }
serde_json = { workspace = true } serde_json = { workspace = true }
log = { workspace = true } tracing = { workspace = true }
+1 -1
View File
@@ -42,7 +42,7 @@ impl SolidityCompiler for Resolc {
if !output.status.success() { if !output.status.success() {
let message = String::from_utf8_lossy(&stderr); let message = String::from_utf8_lossy(&stderr);
log::error!( tracing::error!(
"resolc failed exit={} stderr={} JSON-in={} ", "resolc failed exit={} stderr={} JSON-in={} ",
output.status, output.status,
&message, &message,
+1 -1
View File
@@ -34,7 +34,7 @@ impl SolidityCompiler for Solc {
if !output.status.success() { if !output.status.success() {
let message = String::from_utf8_lossy(&output.stderr); let message = String::from_utf8_lossy(&output.stderr);
log::error!("solc failed exit={} stderr={}", output.status, &message); tracing::error!("solc failed exit={} stderr={}", output.status, &message);
return Ok(CompilerOutput { return Ok(CompilerOutput {
input, input,
output: Default::default(), output: Default::default(),
+2 -2
View File
@@ -23,8 +23,8 @@ revive-dt-report = { workspace = true }
alloy = { workspace = true } alloy = { workspace = true }
anyhow = { workspace = true } anyhow = { workspace = true }
clap = { workspace = true } clap = { workspace = true }
log = { workspace = true } tracing = { workspace = true }
env_logger = { workspace = true } tracing-subscriber = { workspace = true }
rayon = { workspace = true } rayon = { workspace = true }
revive-solc-json-interface = { workspace = true } revive-solc-json-interface = { workspace = true }
serde_json = { workspace = true } serde_json = { workspace = true }
+79 -62
View File
@@ -19,6 +19,7 @@ use revive_dt_report::reporter::{CompilationTask, Report, Span};
use revive_solc_json_interface::SolcStandardJsonOutput; use revive_solc_json_interface::SolcStandardJsonOutput;
use serde_json::Value; use serde_json::Value;
use std::collections::HashMap as StdHashMap; use std::collections::HashMap as StdHashMap;
use tracing::Level;
use crate::Platform; use crate::Platform;
@@ -73,7 +74,7 @@ where
.solc_optimizer(mode.solc_optimize()); .solc_optimizer(mode.solc_optimize());
for (file, _contract) in metadata.contract_sources()?.values() { for (file, _contract) in metadata.contract_sources()?.values() {
log::debug!("contract source {}", file.display()); tracing::debug!("contract source {}", file.display());
compiler = compiler.with_source(file)?; compiler = compiler.with_source(file)?;
} }
@@ -96,11 +97,13 @@ where
if let Some(contracts) = &last_output.contracts { if let Some(contracts) = &last_output.contracts {
for (file, contracts_map) in contracts { for (file, contracts_map) in contracts {
for contract_name in contracts_map.keys() { for contract_name in contracts_map.keys() {
log::debug!("Compiled contract: {contract_name} from file: {file}"); tracing::debug!(
"Compiled contract: {contract_name} from file: {file}"
);
} }
} }
} else { } else {
log::warn!("Compiled contracts field is None"); tracing::warn!("Compiled contracts field is None");
} }
} }
@@ -108,7 +111,7 @@ where
Ok(()) Ok(())
} }
Err(error) => { Err(error) => {
log::error!("Failed to compile contract: {:?}", error.to_string()); tracing::error!("Failed to compile contract: {:?}", error.to_string());
task.error = Some(error.to_string()); task.error = Some(error.to_string());
Err(error) Err(error)
} }
@@ -120,11 +123,11 @@ where
input: &Input, input: &Input,
node: &T::Blockchain, node: &T::Blockchain,
) -> anyhow::Result<(TransactionReceipt, GethTrace, DiffMode)> { ) -> anyhow::Result<(TransactionReceipt, GethTrace, DiffMode)> {
log::trace!("Calling execute_input for input: {input:?}"); tracing::trace!("Calling execute_input for input: {input:?}");
let nonce = node.fetch_add_nonce(input.caller)?; let nonce = node.fetch_add_nonce(input.caller)?;
log::debug!( tracing::debug!(
"Nonce calculated on the execute contract, calculated nonce {}, for contract {}, having address {} on node: {}", "Nonce calculated on the execute contract, calculated nonce {}, for contract {}, having address {} on node: {}",
&nonce, &nonce,
&input.instance, &input.instance,
@@ -139,21 +142,21 @@ where
&self.deployed_abis, &self.deployed_abis,
) { ) {
Ok(tx) => { Ok(tx) => {
log::debug!("Legacy transaction data: {tx:#?}"); tracing::debug!("Legacy transaction data: {tx:#?}");
tx tx
} }
Err(err) => { Err(err) => {
log::error!("Failed to construct legacy transaction: {err:?}"); tracing::error!("Failed to construct legacy transaction: {err:?}");
return Err(err); return Err(err);
} }
}; };
log::trace!("Executing transaction for input: {input:?}"); tracing::trace!("Executing transaction for input: {input:?}");
let receipt = match node.execute_transaction(tx) { let receipt = match node.execute_transaction(tx) {
Ok(receipt) => receipt, Ok(receipt) => receipt,
Err(err) => { Err(err) => {
log::error!( tracing::error!(
"Failed to execute transaction when executing the contract: {}, {:?}", "Failed to execute transaction when executing the contract: {}, {:?}",
&input.instance, &input.instance,
err err
@@ -162,14 +165,14 @@ where
} }
}; };
log::trace!( tracing::trace!(
"Transaction receipt for executed contract: {} - {:?}", "Transaction receipt for executed contract: {} - {:?}",
&input.instance, &input.instance,
receipt, receipt,
); );
let trace = node.trace_transaction(receipt.clone())?; let trace = node.trace_transaction(receipt.clone())?;
log::trace!( tracing::trace!(
"Trace result for contract: {} - {:?}", "Trace result for contract: {} - {:?}",
&input.instance, &input.instance,
trace trace
@@ -181,7 +184,7 @@ where
} }
pub fn deploy_contracts(&mut self, input: &Input, node: &T::Blockchain) -> anyhow::Result<()> { pub fn deploy_contracts(&mut self, input: &Input, node: &T::Blockchain) -> anyhow::Result<()> {
log::debug!( tracing::debug!(
"Deploying contracts {}, having address {} on node: {}", "Deploying contracts {}, having address {} on node: {}",
&input.instance, &input.instance,
&input.caller, &input.caller,
@@ -189,7 +192,7 @@ where
); );
for output in self.contracts.values() { for output in self.contracts.values() {
let Some(contract_map) = &output.contracts else { let Some(contract_map) = &output.contracts else {
log::debug!( tracing::debug!(
"No contracts in output — skipping deployment for this input {}", "No contracts in output — skipping deployment for this input {}",
&input.instance &input.instance
); );
@@ -198,7 +201,7 @@ where
for contracts in contract_map.values() { for contracts in contract_map.values() {
for (contract_name, contract) in contracts { for (contract_name, contract) in contracts {
log::debug!( tracing::debug!(
"Contract name is: {:?} and the input name is: {:?}", "Contract name is: {:?} and the input name is: {:?}",
&contract_name, &contract_name,
&input.instance &input.instance
@@ -211,13 +214,13 @@ where
.map(|b| b.object.clone()); .map(|b| b.object.clone());
let Some(code) = bytecode else { let Some(code) = bytecode else {
log::error!("no bytecode for contract {contract_name}"); tracing::error!("no bytecode for contract {contract_name}");
continue; continue;
}; };
let nonce = node.fetch_add_nonce(input.caller)?; let nonce = node.fetch_add_nonce(input.caller)?;
log::debug!( tracing::debug!(
"Calculated nonce {}, for contract {}, having address {} on node: {}", "Calculated nonce {}, for contract {}, having address {} on node: {}",
&nonce, &nonce,
&input.instance, &input.instance,
@@ -239,7 +242,7 @@ where
let receipt = match node.execute_transaction(tx) { let receipt = match node.execute_transaction(tx) {
Ok(receipt) => receipt, Ok(receipt) => receipt,
Err(err) => { Err(err) => {
log::error!( tracing::error!(
"Failed to execute transaction when deploying the contract on node : {:?}, {:?}, {:?}", "Failed to execute transaction when deploying the contract on node : {:?}, {:?}, {:?}",
std::any::type_name::<T>(), std::any::type_name::<T>(),
&contract_name, &contract_name,
@@ -249,7 +252,7 @@ where
} }
}; };
log::debug!( tracing::debug!(
"Deployment tx sent for {} with nonce {} → tx hash: {:?}, on node: {:?}", "Deployment tx sent for {} with nonce {} → tx hash: {:?}, on node: {:?}",
contract_name, contract_name,
nonce, nonce,
@@ -257,7 +260,7 @@ where
std::any::type_name::<T>(), std::any::type_name::<T>(),
); );
log::trace!( tracing::trace!(
"Deployed transaction receipt for contract: {} - {:?}, on node: {:?}", "Deployed transaction receipt for contract: {} - {:?}, on node: {:?}",
&contract_name, &contract_name,
receipt, receipt,
@@ -265,7 +268,7 @@ where
); );
let Some(address) = receipt.contract_address else { let Some(address) = receipt.contract_address else {
log::error!( tracing::error!(
"contract {contract_name} deployment did not return an address" "contract {contract_name} deployment did not return an address"
); );
continue; continue;
@@ -273,7 +276,7 @@ where
self.deployed_contracts self.deployed_contracts
.insert(contract_name.clone(), address); .insert(contract_name.clone(), address);
log::trace!( tracing::trace!(
"deployed contract `{}` at {:?}, on node {:?}", "deployed contract `{}` at {:?}, on node {:?}",
contract_name, contract_name,
address, address,
@@ -281,7 +284,7 @@ where
); );
if let Some(Value::String(metadata_json_str)) = &contract.metadata { if let Some(Value::String(metadata_json_str)) = &contract.metadata {
log::trace!( tracing::trace!(
"metadata found for contract {contract_name}, {metadata_json_str}" "metadata found for contract {contract_name}, {metadata_json_str}"
); );
@@ -292,7 +295,7 @@ where
{ {
match serde_json::from_value::<JsonAbi>(abi_value.clone()) { match serde_json::from_value::<JsonAbi>(abi_value.clone()) {
Ok(parsed_abi) => { Ok(parsed_abi) => {
log::trace!( tracing::trace!(
"ABI found in metadata for contract {}", "ABI found in metadata for contract {}",
&contract_name &contract_name
); );
@@ -329,7 +332,7 @@ where
} }
} }
log::debug!("Available contracts: {:?}", self.deployed_contracts.keys()); tracing::debug!("Available contracts: {:?}", self.deployed_contracts.keys());
Ok(()) Ok(())
} }
@@ -362,28 +365,28 @@ where
} }
pub fn trace_diff_mode(label: &str, diff: &DiffMode) { pub fn trace_diff_mode(label: &str, diff: &DiffMode) {
log::trace!("{label} - PRE STATE:"); tracing::trace!("{label} - PRE STATE:");
for (addr, state) in &diff.pre { for (addr, state) in &diff.pre {
Self::trace_account_state(" [pre]", addr, state); Self::trace_account_state(" [pre]", addr, state);
} }
log::trace!("{label} - POST STATE:"); tracing::trace!("{label} - POST STATE:");
for (addr, state) in &diff.post { for (addr, state) in &diff.post {
Self::trace_account_state(" [post]", addr, state); Self::trace_account_state(" [post]", addr, state);
} }
} }
fn trace_account_state(prefix: &str, addr: &Address, state: &AccountState) { fn trace_account_state(prefix: &str, addr: &Address, state: &AccountState) {
log::trace!("{prefix} 0x{addr:x}"); tracing::trace!("{prefix} 0x{addr:x}");
if let Some(balance) = &state.balance { if let Some(balance) = &state.balance {
log::trace!("{prefix} balance: {balance}"); tracing::trace!("{prefix} balance: {balance}");
} }
if let Some(nonce) = &state.nonce { if let Some(nonce) = &state.nonce {
log::trace!("{prefix} nonce: {nonce}"); tracing::trace!("{prefix} nonce: {nonce}");
} }
if let Some(code) = &state.code { if let Some(code) = &state.code {
log::trace!("{prefix} code: {code}"); tracing::trace!("{prefix} code: {code}");
} }
} }
@@ -395,61 +398,75 @@ where
let mut follower_state = State::<F>::new(self.config, span); let mut follower_state = State::<F>::new(self.config, span);
follower_state.build_contracts(&mode, self.metadata)?; follower_state.build_contracts(&mode, self.metadata)?;
for case in &self.metadata.cases { for (case_idx, case) in self.metadata.cases.iter().enumerate() {
// Creating a tracing span to know which case within the metadata is being executed
// and which one we're getting logs for.
let tracing_span = tracing::span!(
Level::INFO,
"Executing case",
case = case.name,
case_idx = case_idx
);
let _guard = tracing_span.enter();
for input in &case.inputs { for input in &case.inputs {
log::debug!("Starting deploying contract {}", &input.instance); tracing::debug!("Starting deploying contract {}", &input.instance);
if let Err(err) = leader_state.deploy_contracts(input, self.leader_node) { if let Err(err) = leader_state.deploy_contracts(input, self.leader_node) {
log::error!("Leader deployment failed for {}: {err}", input.instance); tracing::error!("Leader deployment failed for {}: {err}", input.instance);
continue; continue;
} else { } else {
log::debug!("Leader deployment succeeded for {}", &input.instance); tracing::debug!("Leader deployment succeeded for {}", &input.instance);
} }
if let Err(err) = follower_state.deploy_contracts(input, self.follower_node) { if let Err(err) = follower_state.deploy_contracts(input, self.follower_node) {
log::error!("Follower deployment failed for {}: {err}", input.instance); tracing::error!("Follower deployment failed for {}: {err}", input.instance);
continue; continue;
} else { } else {
log::debug!("Follower deployment succeeded for {}", &input.instance); tracing::debug!("Follower deployment succeeded for {}", &input.instance);
} }
log::debug!("Starting executing contract {}", &input.instance); tracing::debug!("Starting executing contract {}", &input.instance);
let (leader_receipt, _, leader_diff) = match leader_state let (leader_receipt, _, leader_diff) =
.execute_input(input, self.leader_node) match leader_state.execute_input(input, self.leader_node) {
{ Ok(result) => result,
Ok(result) => result, Err(err) => {
Err(err) => { tracing::error!(
log::error!("Leader execution failed for {}: {err}", input.instance); "Leader execution failed for {}: {err}",
continue; input.instance
} );
}; continue;
}
};
let (follower_receipt, _, follower_diff) = match follower_state let (follower_receipt, _, follower_diff) =
.execute_input(input, self.follower_node) match follower_state.execute_input(input, self.follower_node) {
{ Ok(result) => result,
Ok(result) => result, Err(err) => {
Err(err) => { tracing::error!(
log::error!("Follower execution failed for {}: {err}", input.instance); "Follower execution failed for {}: {err}",
continue; input.instance
} );
}; continue;
}
};
if leader_diff == follower_diff { if leader_diff == follower_diff {
log::debug!("State diffs match between leader and follower."); tracing::debug!("State diffs match between leader and follower.");
} else { } else {
log::debug!("State diffs mismatch between leader and follower."); tracing::debug!("State diffs mismatch between leader and follower.");
Self::trace_diff_mode("Leader", &leader_diff); Self::trace_diff_mode("Leader", &leader_diff);
Self::trace_diff_mode("Follower", &follower_diff); Self::trace_diff_mode("Follower", &follower_diff);
} }
if leader_receipt.logs() != follower_receipt.logs() { if leader_receipt.logs() != follower_receipt.logs() {
log::debug!("Log/event mismatch between leader and follower."); tracing::debug!("Log/event mismatch between leader and follower.");
log::trace!("Leader logs: {:?}", leader_receipt.logs()); tracing::trace!("Leader logs: {:?}", leader_receipt.logs());
log::trace!("Follower logs: {:?}", follower_receipt.logs()); tracing::trace!("Follower logs: {:?}", follower_receipt.logs());
} }
if leader_receipt.status() != follower_receipt.status() { if leader_receipt.status() != follower_receipt.status() {
log::debug!( tracing::debug!(
"Mismatch in status: leader = {}, follower = {}", "Mismatch in status: leader = {}, follower = {}",
leader_receipt.status(), leader_receipt.status(),
follower_receipt.status() follower_receipt.status()
+60 -30
View File
@@ -8,10 +8,12 @@ use revive_dt_core::{
Geth, Kitchensink, Platform, Geth, Kitchensink, Platform,
driver::{Driver, State}, driver::{Driver, State},
}; };
use revive_dt_format::{corpus::Corpus, metadata::Metadata}; use revive_dt_format::{corpus::Corpus, metadata::MetadataFile};
use revive_dt_node::pool::NodePool; use revive_dt_node::pool::NodePool;
use revive_dt_report::reporter::{Report, Span}; use revive_dt_report::reporter::{Report, Span};
use temp_dir::TempDir; use temp_dir::TempDir;
use tracing::Level;
use tracing_subscriber::{EnvFilter, FmtSubscriber, fmt::format::FmtSpan};
static TEMP_DIR: LazyLock<TempDir> = LazyLock::new(|| TempDir::new().unwrap()); static TEMP_DIR: LazyLock<TempDir> = LazyLock::new(|| TempDir::new().unwrap());
@@ -33,7 +35,14 @@ fn main() -> anyhow::Result<()> {
} }
fn init_cli() -> anyhow::Result<Arguments> { fn init_cli() -> anyhow::Result<Arguments> {
env_logger::init(); let subscriber = FmtSubscriber::builder()
.with_thread_ids(true)
.with_thread_names(true)
.with_env_filter(EnvFilter::from_default_env())
.with_span_events(FmtSpan::ENTER | FmtSpan::CLOSE)
.pretty()
.finish();
tracing::subscriber::set_global_default(subscriber)?;
let mut args = Arguments::parse(); let mut args = Arguments::parse();
@@ -51,7 +60,7 @@ fn init_cli() -> anyhow::Result<Arguments> {
args.temp_dir = Some(&TEMP_DIR); args.temp_dir = Some(&TEMP_DIR);
} }
} }
log::info!("workdir: {}", args.directory().display()); tracing::info!("workdir: {}", args.directory().display());
ThreadPoolBuilder::new() ThreadPoolBuilder::new()
.num_threads(args.workers) .num_threads(args.workers)
@@ -60,21 +69,21 @@ fn init_cli() -> anyhow::Result<Arguments> {
Ok(args) Ok(args)
} }
fn collect_corpora(args: &Arguments) -> anyhow::Result<HashMap<Corpus, Vec<Metadata>>> { fn collect_corpora(args: &Arguments) -> anyhow::Result<HashMap<Corpus, Vec<MetadataFile>>> {
let mut corpora = HashMap::new(); let mut corpora = HashMap::new();
for path in &args.corpus { for path in &args.corpus {
let corpus = Corpus::try_from_path(path)?; let corpus = Corpus::try_from_path(path)?;
log::info!("found corpus: {}", path.display()); tracing::info!("found corpus: {}", path.display());
let tests = corpus.enumerate_tests(); let tests = corpus.enumerate_tests();
log::info!("corpus '{}' contains {} tests", &corpus.name, tests.len()); tracing::info!("corpus '{}' contains {} tests", &corpus.name, tests.len());
corpora.insert(corpus, tests); corpora.insert(corpus, tests);
} }
Ok(corpora) Ok(corpora)
} }
fn run_driver<L, F>(args: &Arguments, tests: &[Metadata], span: Span) -> anyhow::Result<()> fn run_driver<L, F>(args: &Arguments, tests: &[MetadataFile], span: Span) -> anyhow::Result<()>
where where
L: Platform, L: Platform,
F: Platform, F: Platform,
@@ -84,34 +93,50 @@ where
let leader_nodes = NodePool::<L::Blockchain>::new(args)?; let leader_nodes = NodePool::<L::Blockchain>::new(args)?;
let follower_nodes = NodePool::<F::Blockchain>::new(args)?; let follower_nodes = NodePool::<F::Blockchain>::new(args)?;
tests.par_iter().for_each(|metadata| { tests.par_iter().for_each(
let mut driver = Driver::<L, F>::new( |MetadataFile {
metadata, content: metadata,
args, path: metadata_file_path,
leader_nodes.round_robbin(), }| {
follower_nodes.round_robbin(), // Starting a new tracing span for this metadata file. This allows our logs to be clear
); // about which metadata file the logs belong to. We can add other information into this
// as well to be able to associate the logs with the correct metadata file and case
// that's being executed.
let tracing_span = tracing::span!(
Level::INFO,
"Running driver",
metadata_file_path = metadata_file_path.display().to_string(),
);
let _guard = tracing_span.enter();
match driver.execute(span) { let mut driver = Driver::<L, F>::new(
Ok(_) => { metadata,
log::info!( args,
"metadata {} success", leader_nodes.round_robbin(),
metadata.directory().as_ref().unwrap().display() follower_nodes.round_robbin(),
); );
match driver.execute(span) {
Ok(_) => {
tracing::info!(
"metadata {} success",
metadata.directory().as_ref().unwrap().display()
);
}
Err(error) => {
tracing::warn!(
"metadata {} failure: {error:?}",
metadata.file_path.as_ref().unwrap().display()
);
}
} }
Err(error) => { },
log::warn!( );
"metadata {} failure: {error:?}",
metadata.file_path.as_ref().unwrap().display()
);
}
}
});
Ok(()) Ok(())
} }
fn execute_corpus(args: &Arguments, tests: &[Metadata], span: Span) -> anyhow::Result<()> { fn execute_corpus(args: &Arguments, tests: &[MetadataFile], span: Span) -> anyhow::Result<()> {
match (&args.leader, &args.follower) { match (&args.leader, &args.follower) {
(TestingPlatform::Geth, TestingPlatform::Kitchensink) => { (TestingPlatform::Geth, TestingPlatform::Kitchensink) => {
run_driver::<Geth, Kitchensink>(args, tests, span)? run_driver::<Geth, Kitchensink>(args, tests, span)?
@@ -125,7 +150,12 @@ fn execute_corpus(args: &Arguments, tests: &[Metadata], span: Span) -> anyhow::R
Ok(()) Ok(())
} }
fn compile_corpus(config: &Arguments, tests: &[Metadata], platform: &TestingPlatform, span: Span) { fn compile_corpus(
config: &Arguments,
tests: &[MetadataFile],
platform: &TestingPlatform,
span: Span,
) {
tests.par_iter().for_each(|metadata| { tests.par_iter().for_each(|metadata| {
for mode in &metadata.solc_modes() { for mode in &metadata.solc_modes() {
match platform { match platform {
+2 -2
View File
@@ -13,7 +13,7 @@ alloy = { workspace = true }
alloy-primitives = { workspace = true } alloy-primitives = { workspace = true }
alloy-sol-types = { workspace = true } alloy-sol-types = { workspace = true }
anyhow = { workspace = true } anyhow = { workspace = true }
log = { workspace = true } tracing = { workspace = true }
semver = { workspace = true } semver = { workspace = true }
serde = { workspace = true, features = [ "derive" ] } serde = { workspace = true, features = ["derive"] }
serde_json = { workspace = true } serde_json = { workspace = true }
+6 -6
View File
@@ -5,7 +5,7 @@ use std::{
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::metadata::Metadata; use crate::metadata::MetadataFile;
#[derive(Clone, Debug, Default, Serialize, Deserialize, Eq, PartialEq, Hash)] #[derive(Clone, Debug, Default, Serialize, Deserialize, Eq, PartialEq, Hash)]
pub struct Corpus { pub struct Corpus {
@@ -21,7 +21,7 @@ impl Corpus {
} }
/// Scan the corpus base directory and return all tests found. /// Scan the corpus base directory and return all tests found.
pub fn enumerate_tests(&self) -> Vec<Metadata> { pub fn enumerate_tests(&self) -> Vec<MetadataFile> {
let mut tests = Vec::new(); let mut tests = Vec::new();
collect_metadata(&self.path, &mut tests); collect_metadata(&self.path, &mut tests);
tests tests
@@ -34,11 +34,11 @@ impl Corpus {
/// Found tests are inserted into `tests`. /// Found tests are inserted into `tests`.
/// ///
/// `path` is expected to be a directory. /// `path` is expected to be a directory.
pub fn collect_metadata(path: &Path, tests: &mut Vec<Metadata>) { pub fn collect_metadata(path: &Path, tests: &mut Vec<MetadataFile>) {
let dir_entry = match std::fs::read_dir(path) { let dir_entry = match std::fs::read_dir(path) {
Ok(dir_entry) => dir_entry, Ok(dir_entry) => dir_entry,
Err(error) => { Err(error) => {
log::error!("failed to read dir '{}': {error}", path.display()); tracing::error!("failed to read dir '{}': {error}", path.display());
return; return;
} }
}; };
@@ -47,7 +47,7 @@ pub fn collect_metadata(path: &Path, tests: &mut Vec<Metadata>) {
let entry = match entry { let entry = match entry {
Ok(entry) => entry, Ok(entry) => entry,
Err(error) => { Err(error) => {
log::error!("error reading dir entry: {error}"); tracing::error!("error reading dir entry: {error}");
continue; continue;
} }
}; };
@@ -59,7 +59,7 @@ pub fn collect_metadata(path: &Path, tests: &mut Vec<Metadata>) {
} }
if path.is_file() { if path.is_file() {
if let Some(metadata) = Metadata::try_from_file(&path) { if let Some(metadata) = MetadataFile::try_from_file(&path) {
tests.push(metadata) tests.push(metadata)
} }
} }
+3 -3
View File
@@ -126,7 +126,7 @@ impl Input {
.get(&self.instance) .get(&self.instance)
.ok_or_else(|| anyhow::anyhow!("ABI for instance '{}' not found", &self.instance))?; .ok_or_else(|| anyhow::anyhow!("ABI for instance '{}' not found", &self.instance))?;
log::trace!("ABI found for instance: {}", &self.instance); tracing::trace!("ABI found for instance: {}", &self.instance);
// Find function by selector // Find function by selector
let function = abi let function = abi
@@ -140,7 +140,7 @@ impl Input {
) )
})?; })?;
log::trace!("Functions found for instance: {}", &self.instance); tracing::trace!("Functions found for instance: {}", &self.instance);
let calldata_args = match &self.calldata { let calldata_args = match &self.calldata {
Some(Calldata::Compound(args)) => args, Some(Calldata::Compound(args)) => args,
@@ -155,7 +155,7 @@ impl Input {
); );
} }
log::trace!( tracing::trace!(
"Starting encoding ABI's parameters for instance: {}", "Starting encoding ABI's parameters for instance: {}",
&self.instance &self.instance
); );
+31 -7
View File
@@ -1,6 +1,7 @@
use std::{ use std::{
collections::BTreeMap, collections::BTreeMap,
fs::{File, read_to_string}, fs::{File, read_to_string},
ops::Deref,
path::{Path, PathBuf}, path::{Path, PathBuf},
}; };
@@ -15,6 +16,29 @@ pub const METADATA_FILE_EXTENSION: &str = "json";
pub const SOLIDITY_CASE_FILE_EXTENSION: &str = "sol"; pub const SOLIDITY_CASE_FILE_EXTENSION: &str = "sol";
pub const SOLIDITY_CASE_COMMENT_MARKER: &str = "//!"; pub const SOLIDITY_CASE_COMMENT_MARKER: &str = "//!";
#[derive(Debug, Default, Deserialize, Clone, Eq, PartialEq)]
pub struct MetadataFile {
pub path: PathBuf,
pub content: Metadata,
}
impl MetadataFile {
pub fn try_from_file(path: &Path) -> Option<Self> {
Metadata::try_from_file(path).map(|metadata| Self {
path: path.to_owned(),
content: metadata,
})
}
}
impl Deref for MetadataFile {
type Target = Metadata;
fn deref(&self) -> &Self::Target {
&self.content
}
}
#[derive(Debug, Default, Deserialize, Clone, Eq, PartialEq)] #[derive(Debug, Default, Deserialize, Clone, Eq, PartialEq)]
pub struct Metadata { pub struct Metadata {
pub cases: Vec<Case>, pub cases: Vec<Case>,
@@ -35,7 +59,7 @@ impl Metadata {
.filter_map(|mode| match mode { .filter_map(|mode| match mode {
Mode::Solidity(solc_mode) => Some(solc_mode), Mode::Solidity(solc_mode) => Some(solc_mode),
Mode::Unknown(mode) => { Mode::Unknown(mode) => {
log::debug!("compiler: ignoring unknown mode '{mode}'"); tracing::debug!("compiler: ignoring unknown mode '{mode}'");
None None
} }
}) })
@@ -90,7 +114,7 @@ impl Metadata {
assert!(path.is_file(), "not a file: {}", path.display()); assert!(path.is_file(), "not a file: {}", path.display());
let Some(file_extension) = path.extension() else { let Some(file_extension) = path.extension() else {
log::debug!("skipping corpus file: {}", path.display()); tracing::debug!("skipping corpus file: {}", path.display());
return None; return None;
}; };
@@ -102,14 +126,14 @@ impl Metadata {
return Self::try_from_solidity(path); return Self::try_from_solidity(path);
} }
log::debug!("ignoring invalid corpus file: {}", path.display()); tracing::debug!("ignoring invalid corpus file: {}", path.display());
None None
} }
fn try_from_json(path: &Path) -> Option<Self> { fn try_from_json(path: &Path) -> Option<Self> {
let file = File::open(path) let file = File::open(path)
.inspect_err(|error| { .inspect_err(|error| {
log::error!( tracing::error!(
"opening JSON test metadata file '{}' error: {error}", "opening JSON test metadata file '{}' error: {error}",
path.display() path.display()
); );
@@ -122,7 +146,7 @@ impl Metadata {
Some(metadata) Some(metadata)
} }
Err(error) => { Err(error) => {
log::error!( tracing::error!(
"parsing JSON test metadata file '{}' error: {error}", "parsing JSON test metadata file '{}' error: {error}",
path.display() path.display()
); );
@@ -134,7 +158,7 @@ impl Metadata {
fn try_from_solidity(path: &Path) -> Option<Self> { fn try_from_solidity(path: &Path) -> Option<Self> {
let spec = read_to_string(path) let spec = read_to_string(path)
.inspect_err(|error| { .inspect_err(|error| {
log::error!( tracing::error!(
"opening JSON test metadata file '{}' error: {error}", "opening JSON test metadata file '{}' error: {error}",
path.display() path.display()
); );
@@ -163,7 +187,7 @@ impl Metadata {
Some(metadata) Some(metadata)
} }
Err(error) => { Err(error) => {
log::error!( tracing::error!(
"parsing Solidity test metadata file '{}' error: '{error}' from data: {spec}", "parsing Solidity test metadata file '{}' error: '{error}' from data: {spec}",
path.display() path.display()
); );
+1 -1
View File
@@ -11,6 +11,6 @@ rust-version.workspace = true
[dependencies] [dependencies]
alloy = { workspace = true } alloy = { workspace = true }
anyhow = { workspace = true } anyhow = { workspace = true }
log = { workspace = true } tracing = { workspace = true }
once_cell = { workspace = true } once_cell = { workspace = true }
tokio = { workspace = true } tokio = { workspace = true }
+3 -3
View File
@@ -51,13 +51,13 @@ impl TokioRuntime {
let nonce_task = spawn(interaction::<Nonce>(nonce_receiver)); let nonce_task = spawn(interaction::<Nonce>(nonce_receiver));
if let Err(error) = transaction_task.await { if let Err(error) = transaction_task.await {
log::error!("tokio transaction task failed: {error}"); tracing::error!("tokio transaction task failed: {error}");
} }
if let Err(error) = trace_task.await { if let Err(error) = trace_task.await {
log::error!("tokio trace transaction task failed: {error}"); tracing::error!("tokio trace transaction task failed: {error}");
} }
if let Err(error) = nonce_task.await { if let Err(error) = nonce_task.await {
log::error!("tokio nonce task failed: {error}"); tracing::error!("tokio nonce task failed: {error}");
} }
}); });
}); });
+1 -1
View File
@@ -11,7 +11,7 @@ rust-version.workspace = true
[dependencies] [dependencies]
anyhow = { workspace = true } anyhow = { workspace = true }
alloy = { workspace = true } alloy = { workspace = true }
log = { workspace = true } tracing = { workspace = true }
revive-dt-node-interaction = { workspace = true } revive-dt-node-interaction = { workspace = true }
revive-dt-config = { workspace = true } revive-dt-config = { workspace = true }
+1 -1
View File
@@ -159,7 +159,7 @@ impl EthereumNode for Instance {
let connection_string = self.connection_string(); let connection_string = self.connection_string();
let wallet = self.wallet.clone(); let wallet = self.wallet.clone();
log::debug!("Submitting transaction: {transaction:#?}"); tracing::debug!("Submitting transaction: {transaction:#?}");
execute_transaction(Box::pin(async move { execute_transaction(Box::pin(async move {
Ok(ProviderBuilder::new() Ok(ProviderBuilder::new()
+1 -1
View File
@@ -252,7 +252,7 @@ impl EthereumNode for KitchensinkNode {
let url = self.rpc_url.clone(); let url = self.rpc_url.clone();
let wallet = self.wallet.clone(); let wallet = self.wallet.clone();
log::debug!("Submitting transaction: {transaction:#?}"); tracing::debug!("Submitting transaction: {transaction:#?}");
execute_transaction(Box::pin(async move { execute_transaction(Box::pin(async move {
Ok(ProviderBuilder::new() Ok(ProviderBuilder::new()
+1 -1
View File
@@ -62,7 +62,7 @@ where
fn spawn_node<T: Node + Send>(args: &Arguments, genesis: String) -> anyhow::Result<T> { fn spawn_node<T: Node + Send>(args: &Arguments, genesis: String) -> anyhow::Result<T> {
let mut node = T::new(args); let mut node = T::new(args);
log::info!("starting node: {}", node.connection_string()); tracing::info!("starting node: {}", node.connection_string());
node.spawn(genesis)?; node.spawn(genesis)?;
Ok(node) Ok(node)
} }
+1 -2
View File
@@ -12,8 +12,7 @@ revive-dt-config = { workspace = true }
revive-dt-format = { workspace = true } revive-dt-format = { workspace = true }
anyhow = { workspace = true } anyhow = { workspace = true }
log = { workspace = true } tracing = { workspace = true }
serde = { workspace = true } serde = { workspace = true }
serde_json = { workspace = true } serde_json = { workspace = true }
revive-solc-json-interface = { workspace = true } revive-solc-json-interface = { workspace = true }
+1 -1
View File
@@ -192,7 +192,7 @@ impl Report {
let file = File::create(&path).context(path.display().to_string())?; let file = File::create(&path).context(path.display().to_string())?;
serde_json::to_writer_pretty(file, &self)?; serde_json::to_writer_pretty(file, &self)?;
log::info!("report written to: {}", path.display()); tracing::info!("report written to: {}", path.display());
Ok(()) Ok(())
} }
+1 -1
View File
@@ -11,7 +11,7 @@ rust-version.workspace = true
[dependencies] [dependencies]
anyhow = { workspace = true } anyhow = { workspace = true }
hex = { workspace = true } hex = { workspace = true }
log = { workspace = true } tracing = { workspace = true }
reqwest = { workspace = true } reqwest = { workspace = true }
semver = { workspace = true } semver = { workspace = true }
serde = { workspace = true } serde = { workspace = true }
+3 -3
View File
@@ -25,7 +25,7 @@ pub(crate) fn get_or_download(
let mut cache = SOLC_CACHER.lock().unwrap(); let mut cache = SOLC_CACHER.lock().unwrap();
if cache.contains(&target_file) { if cache.contains(&target_file) {
log::debug!("using cached solc: {}", target_file.display()); tracing::debug!("using cached solc: {}", target_file.display());
return Ok(target_file); return Ok(target_file);
} }
@@ -37,10 +37,10 @@ pub(crate) fn get_or_download(
} }
fn download_to_file(path: &Path, downloader: &GHDownloader) -> anyhow::Result<()> { fn download_to_file(path: &Path, downloader: &GHDownloader) -> anyhow::Result<()> {
log::info!("caching file: {}", path.display()); tracing::info!("caching file: {}", path.display());
let Ok(file) = File::create_new(path) else { let Ok(file) = File::create_new(path) else {
log::debug!("cache file already exists: {}", path.display()); tracing::debug!("cache file already exists: {}", path.display());
return Ok(()); return Ok(());
}; };
+1 -1
View File
@@ -86,7 +86,7 @@ impl GHDownloader {
/// Errors out if the download fails or the digest of the downloaded file /// Errors out if the download fails or the digest of the downloaded file
/// mismatches the expected digest from the release [List]. /// mismatches the expected digest from the release [List].
pub fn download(&self) -> anyhow::Result<Vec<u8>> { pub fn download(&self) -> anyhow::Result<Vec<u8>> {
log::info!("downloading solc: {self:?}"); tracing::info!("downloading solc: {self:?}");
let expected_digest = List::download(self.list)? let expected_digest = List::download(self.list)?
.builds .builds
.iter() .iter()