Compare commits

...

4 Commits

Author SHA1 Message Date
xermicus 5c31fdb236 fix the simple test case definition
Signed-off-by: xermicus <cyrill@parity.io>
2025-06-17 12:20:14 +02:00
xermicus 534170db6f dont fail machete on polkadot-sdk submodule (#23)
Signed-off-by: xermicus <cyrill@parity.io>
2025-06-14 10:12:30 +00:00
activecoder10 090b56c46a deploy contracts (#22) 2025-06-12 11:09:01 +00:00
activecoder10 547563e718 Extended execute_input method (#21)
* Extended execute_input method

* Improve tracing part
2025-06-10 08:23:37 +00:00
5 changed files with 149 additions and 30 deletions
+1 -1
View File
@@ -8,7 +8,7 @@ clippy:
machete:
cargo install cargo-machete
cargo machete
cargo machete crates
test: format clippy machete
cargo test --workspace -- --nocapture
+105 -8
View File
@@ -1,8 +1,12 @@
//! The test driver handles the compilation and execution of the test cases.
use alloy::{
primitives::{Address, map::HashMap},
rpc::types::trace::geth::GethTrace,
network::TransactionBuilder,
primitives::{Address, bytes::Bytes, map::HashMap},
rpc::types::{
TransactionRequest,
trace::geth::{AccountState, DiffMode, GethTrace},
},
};
use revive_dt_compiler::{Compiler, CompilerInput, SolidityCompiler};
use revive_dt_config::Arguments;
@@ -94,15 +98,70 @@ where
&mut self,
input: &Input,
node: &T::Blockchain,
) -> anyhow::Result<GethTrace> {
) -> anyhow::Result<(GethTrace, DiffMode)> {
let receipt = node.execute_transaction(input.legacy_transaction(
self.config.network_id,
0,
&self.deployed_contracts,
)?)?;
dbg!(&receipt);
//node.trace_transaction(receipt)
todo!()
log::trace!("Transaction receipt: {:?}", receipt);
let trace = node.trace_transaction(receipt.clone())?;
log::trace!("Trace result: {:?}", trace);
let diff = node.state_diff(receipt)?;
Ok((trace, diff))
}
pub fn deploy_contracts(&mut self, input: &Input, node: &T::Blockchain) -> anyhow::Result<()> {
for output in self.contracts.values() {
let Some(contract_map) = &output.contracts else {
log::debug!("No contracts in output — skipping deployment for this input.");
continue;
};
for contracts in contract_map.values() {
for (contract_name, contract) in contracts {
if contract_name != &input.instance {
continue;
}
let bytecode = contract
.evm
.as_ref()
.and_then(|evm| evm.bytecode.as_ref())
.map(|b| b.object.clone());
let Some(code) = bytecode else {
anyhow::bail!("no bytecode for contract `{}`", contract_name);
};
let tx = TransactionRequest::default()
.with_from(input.caller)
.with_to(Address::ZERO)
.with_input(Bytes::from(code.clone()))
.with_gas_price(20_000_000_000)
.with_gas_limit(20_000_000_000)
.with_chain_id(self.config.network_id)
.with_nonce(0);
let receipt = node.execute_transaction(tx)?;
let Some(address) = receipt.contract_address else {
anyhow::bail!(
"contract `{}` deployment did not return an address",
contract_name
);
};
self.deployed_contracts
.insert(contract_name.clone(), address);
log::info!("deployed contract `{}` at {:?}", contract_name, address);
}
}
}
Ok(())
}
}
@@ -132,6 +191,32 @@ where
}
}
pub fn trace_diff_mode(label: &str, diff: &DiffMode) {
log::trace!("{} - PRE STATE:", label);
for (addr, state) in &diff.pre {
Self::trace_account_state(" [pre]", addr, state);
}
log::trace!("{} - POST STATE:", label);
for (addr, state) in &diff.post {
Self::trace_account_state(" [post]", addr, state);
}
}
fn trace_account_state(prefix: &str, addr: &Address, state: &AccountState) {
log::trace!("{} 0x{:x}", prefix, addr);
if let Some(balance) = &state.balance {
log::trace!("{} balance: {}", prefix, balance);
}
if let Some(nonce) = &state.nonce {
log::trace!("{} nonce: {}", prefix, nonce);
}
if let Some(code) = &state.code {
log::trace!("{} code: {}", prefix, code);
}
}
pub fn execute(&mut self, span: Span) -> anyhow::Result<()> {
for mode in self.metadata.solc_modes() {
let mut leader_state = State::<L>::new(self.config, span);
@@ -142,8 +227,20 @@ where
for case in &self.metadata.cases {
for input in &case.inputs {
let _ = leader_state.execute_input(input, self.leader_node)?;
let _ = follower_state.execute_input(input, self.follower_node)?;
leader_state.deploy_contracts(input, self.leader_node)?;
follower_state.deploy_contracts(input, self.follower_node)?;
let (_, leader_diff) = leader_state.execute_input(input, self.leader_node)?;
let (_, follower_diff) =
follower_state.execute_input(input, self.follower_node)?;
if leader_diff == follower_diff {
log::debug!("State diffs match between leader and follower.");
} else {
log::debug!("State diffs mismatch between leader and follower.");
Self::trace_diff_mode("Leader", &leader_diff);
Self::trace_diff_mode("Follower", &follower_diff);
}
}
}
}
+2 -2
View File
@@ -5,7 +5,7 @@
use revive_dt_compiler::{SolidityCompiler, revive_resolc, solc};
use revive_dt_config::TestingPlatform;
use revive_dt_node::geth;
use revive_dt_node::{geth, kitchensink::KitchensinkNode};
use revive_dt_node_interaction::EthereumNode;
pub mod driver;
@@ -37,7 +37,7 @@ impl Platform for Geth {
pub struct Kitchensink;
impl Platform for Kitchensink {
type Blockchain = geth::Instance;
type Blockchain = KitchensinkNode;
type Compiler = revive_resolc::Resolc;
fn config_id() -> TestingPlatform {
+31 -15
View File
@@ -5,7 +5,7 @@ use rayon::{ThreadPoolBuilder, prelude::*};
use revive_dt_config::*;
use revive_dt_core::{
Geth, Kitchensink,
Geth, Kitchensink, Platform,
driver::{Driver, State},
};
use revive_dt_format::{corpus::Corpus, metadata::Metadata};
@@ -74,28 +74,30 @@ fn collect_corpora(args: &Arguments) -> anyhow::Result<HashMap<Corpus, Vec<Metad
Ok(corpora)
}
fn execute_corpus(args: &Arguments, tests: &[Metadata], span: Span) -> anyhow::Result<()> {
let leader_nodes = NodePool::new(args)?;
let follower_nodes = NodePool::new(args)?;
fn run_driver<L, F>(args: &Arguments, tests: &[Metadata], span: Span) -> anyhow::Result<()>
where
L: Platform,
F: Platform,
L::Blockchain: revive_dt_node::Node + Send + Sync + 'static,
F::Blockchain: revive_dt_node::Node + Send + Sync + 'static,
{
let leader_nodes = NodePool::<L::Blockchain>::new(args)?;
let follower_nodes = NodePool::<F::Blockchain>::new(args)?;
tests.par_iter().for_each(|metadata| {
let mut driver = match (&args.leader, &args.follower) {
(TestingPlatform::Geth, TestingPlatform::Kitchensink) => Driver::<Geth, Geth>::new(
metadata,
args,
leader_nodes.round_robbin(),
follower_nodes.round_robbin(),
),
_ => unimplemented!(),
};
let mut driver = Driver::<L, F>::new(
metadata,
args,
leader_nodes.round_robbin(),
follower_nodes.round_robbin(),
);
match driver.execute(span) {
Ok(build) => {
Ok(_) => {
log::info!(
"metadata {} success",
metadata.directory().as_ref().unwrap().display()
);
build
}
Err(error) => {
log::warn!(
@@ -109,6 +111,20 @@ fn execute_corpus(args: &Arguments, tests: &[Metadata], span: Span) -> anyhow::R
Ok(())
}
fn execute_corpus(args: &Arguments, tests: &[Metadata], span: Span) -> anyhow::Result<()> {
match (&args.leader, &args.follower) {
(TestingPlatform::Geth, TestingPlatform::Kitchensink) => {
run_driver::<Geth, Kitchensink>(args, tests, span)?
}
(TestingPlatform::Geth, TestingPlatform::Geth) => {
run_driver::<Geth, Geth>(args, tests, span)?
}
_ => unimplemented!(),
}
Ok(())
}
fn compile_corpus(config: &Arguments, tests: &[Metadata], platform: &TestingPlatform, span: Span) {
tests.par_iter().for_each(|metadata| {
for mode in &metadata.solc_modes() {
+10 -4
View File
@@ -132,7 +132,7 @@ impl Metadata {
}
fn try_from_solidity(path: &Path) -> Option<Self> {
let buf = read_to_string(path)
let spec = read_to_string(path)
.inspect_err(|error| {
log::error!(
"opening JSON test metadata file '{}' error: {error}",
@@ -147,18 +147,24 @@ impl Metadata {
buf
});
if buf.is_empty() {
if spec.is_empty() {
return None;
}
match serde_json::from_str::<Self>(&buf) {
match serde_json::from_str::<Self>(&spec) {
Ok(mut metadata) => {
metadata.file_path = Some(path.to_path_buf());
let name = path
.file_name()
.expect("this should be the path to a Solidity file")
.to_str()
.expect("the file name should be valid UTF-8k");
metadata.contracts = Some([(String::from("Test"), format!("{name}:Test"))].into());
Some(metadata)
}
Err(error) => {
log::error!(
"parsing Solidity test metadata file '{}' error: {error}",
"parsing Solidity test metadata file '{}' error: '{error}' from data: {spec}",
path.display()
);
None