mirror of
https://github.com/pezkuwichain/revive-differential-tests.git
synced 2026-06-09 20:21:04 +00:00
@@ -32,7 +32,7 @@ impl<'a, T> State<'a, T>
|
||||
where
|
||||
T: Platform,
|
||||
{
|
||||
fn new(config: &'a Arguments) -> Self {
|
||||
pub fn new(config: &'a Arguments) -> Self {
|
||||
Self {
|
||||
config,
|
||||
contracts: Default::default(),
|
||||
@@ -49,6 +49,7 @@ where
|
||||
let base_path = metadata.directory()?.display().to_string();
|
||||
let mut compiler = Compiler::<T::Compiler>::new().base_path(base_path.clone());
|
||||
for (file, _contract) in sources.values() {
|
||||
log::debug!("contract source {}", file.display());
|
||||
compiler = compiler.with_source(file)?;
|
||||
}
|
||||
|
||||
@@ -73,15 +74,15 @@ where
|
||||
&self.deployed_contracts,
|
||||
)?)?;
|
||||
dbg!(&receipt);
|
||||
Ok(node.trace_transaction(receipt)?)
|
||||
node.trace_transaction(receipt)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Driver<'a, Leader: Platform, Follower: Platform> {
|
||||
metadata: &'a Metadata,
|
||||
config: &'a Arguments,
|
||||
leader: State<'a, Leader>,
|
||||
follower: State<'a, Follower>,
|
||||
leader_node: &'a Leader::Blockchain,
|
||||
follower_node: &'a Follower::Blockchain,
|
||||
}
|
||||
|
||||
impl<'a, L, F> Driver<'a, L, F>
|
||||
@@ -89,52 +90,36 @@ where
|
||||
L: Platform,
|
||||
F: Platform,
|
||||
{
|
||||
pub fn new(metadata: &'a Metadata, config: &'a Arguments) -> Driver<'a, L, F> {
|
||||
pub fn new(
|
||||
metadata: &'a Metadata,
|
||||
config: &'a Arguments,
|
||||
leader_node: &'a L::Blockchain,
|
||||
follower_node: &'a F::Blockchain,
|
||||
) -> Driver<'a, L, F> {
|
||||
Self {
|
||||
metadata,
|
||||
config,
|
||||
leader: State::new(config),
|
||||
follower: State::new(config),
|
||||
leader_node,
|
||||
follower_node,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn execute(
|
||||
&mut self,
|
||||
leader: L::Blockchain,
|
||||
follower: F::Blockchain,
|
||||
) -> anyhow::Result<()> {
|
||||
for mode in self.modes() {
|
||||
self.leader.build_contracts(&mode, self.metadata)?;
|
||||
self.follower.build_contracts(&mode, self.metadata)?;
|
||||
pub fn execute(&mut self) -> anyhow::Result<()> {
|
||||
for mode in self.metadata.solc_modes() {
|
||||
let mut leader_state = State::<L>::new(self.config);
|
||||
leader_state.build_contracts(&mode, self.metadata)?;
|
||||
|
||||
if self.config.compile_only {
|
||||
continue;
|
||||
}
|
||||
let mut follower_state = State::<F>::new(self.config);
|
||||
follower_state.build_contracts(&mode, self.metadata)?;
|
||||
|
||||
for case in &self.metadata.cases {
|
||||
for input in &case.inputs {
|
||||
let expected = self.leader.execute_input(input, &leader)?;
|
||||
let expected = leader_state.execute_input(input, self.leader_node)?;
|
||||
let received = follower_state.execute_input(input, self.follower_node)?;
|
||||
}
|
||||
}
|
||||
|
||||
*self = Self::new(self.metadata, self.config);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn modes(&self) -> Vec<SolcMode> {
|
||||
self.metadata
|
||||
.modes()
|
||||
.iter()
|
||||
.filter_map(|mode| match mode {
|
||||
Mode::Solidity(solc_mode) => Some(solc_mode),
|
||||
Mode::Unknown(mode) => {
|
||||
log::debug!("compiler: ignoring unknown mode '{mode}'");
|
||||
None
|
||||
}
|
||||
})
|
||||
.cloned()
|
||||
.collect()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,8 @@
|
||||
//! provides a helper utilty to execute tests.
|
||||
|
||||
use revive_dt_compiler::{SolidityCompiler, solc};
|
||||
use revive_dt_node::{Node, geth};
|
||||
use revive_dt_node::geth;
|
||||
use revive_dt_node_interaction::EthereumNode;
|
||||
|
||||
pub mod driver;
|
||||
|
||||
@@ -12,7 +13,7 @@ pub mod driver;
|
||||
///
|
||||
/// For this we need a blockchain node implementation and a compiler.
|
||||
pub trait Platform {
|
||||
type Blockchain: Node;
|
||||
type Blockchain: EthereumNode;
|
||||
type Compiler: SolidityCompiler;
|
||||
}
|
||||
|
||||
|
||||
+92
-40
@@ -1,15 +1,40 @@
|
||||
use std::collections::BTreeSet;
|
||||
use std::{collections::HashMap, sync::LazyLock};
|
||||
|
||||
use clap::Parser;
|
||||
use rayon::{ThreadPoolBuilder, prelude::*};
|
||||
|
||||
use revive_dt_config::*;
|
||||
use revive_dt_core::{Geth, Kitchensink, driver::Driver};
|
||||
use revive_dt_format::corpus::Corpus;
|
||||
use revive_dt_node::{Node, geth};
|
||||
use revive_dt_core::{
|
||||
Geth, Kitchensink,
|
||||
driver::{Driver, State},
|
||||
};
|
||||
use revive_dt_format::{corpus::Corpus, metadata::Metadata};
|
||||
use revive_dt_node::pool::NodePool;
|
||||
use temp_dir::TempDir;
|
||||
|
||||
static TEMP_DIR: LazyLock<TempDir> = LazyLock::new(|| TempDir::new().unwrap());
|
||||
|
||||
fn main() -> anyhow::Result<()> {
|
||||
let args = init_cli()?;
|
||||
|
||||
let corpora = collect_corpora(&args)?;
|
||||
|
||||
if let Some(platform) = &args.compile_only {
|
||||
for tests in corpora.values() {
|
||||
main_compile_only(&args, tests, platform)?;
|
||||
}
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
for tests in corpora.values() {
|
||||
main_execute_differential(&args, tests)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn init_cli() -> anyhow::Result<Arguments> {
|
||||
env_logger::init();
|
||||
|
||||
let mut args = Arguments::parse();
|
||||
@@ -17,7 +42,7 @@ fn main() -> anyhow::Result<()> {
|
||||
anyhow::bail!("no test corpus specified");
|
||||
}
|
||||
if args.working_directory.is_none() {
|
||||
args.temp_dir = TempDir::new()?.into()
|
||||
args.temp_dir = Some(&TEMP_DIR);
|
||||
}
|
||||
|
||||
ThreadPoolBuilder::new()
|
||||
@@ -25,45 +50,72 @@ fn main() -> anyhow::Result<()> {
|
||||
.build_global()
|
||||
.unwrap();
|
||||
|
||||
for path in args.corpus.iter().collect::<BTreeSet<_>>() {
|
||||
log::trace!("attempting corpus {path:?}");
|
||||
let corpus = Corpus::try_from_path(path)?;
|
||||
log::info!("found corpus: {corpus:?}");
|
||||
Ok(args)
|
||||
}
|
||||
|
||||
fn collect_corpora(args: &Arguments) -> anyhow::Result<HashMap<Corpus, Vec<Metadata>>> {
|
||||
let mut corpora = HashMap::new();
|
||||
|
||||
for path in &args.corpus {
|
||||
let corpus = Corpus::try_from_path(path)?;
|
||||
log::info!("found corpus: {}", path.display());
|
||||
let tests = corpus.enumerate_tests();
|
||||
log::info!("corpus '{}' contains {} tests", &corpus.name, tests.len());
|
||||
|
||||
tests.par_iter().for_each(|metadata| {
|
||||
let (leader, follower) = match (&args.leader, &args.follower) {
|
||||
(TestingPlatform::Geth, TestingPlatform::Kitchensink) => {
|
||||
(geth::Instance::new(&args), geth::Instance::new(&args))
|
||||
}
|
||||
_ => unimplemented!(),
|
||||
};
|
||||
let mut driver = match (&args.leader, &args.follower) {
|
||||
(TestingPlatform::Geth, TestingPlatform::Kitchensink) => {
|
||||
Driver::<Geth, Geth>::new(metadata, &args)
|
||||
}
|
||||
_ => unimplemented!(),
|
||||
};
|
||||
|
||||
match Driver::<Geth, Geth>::new(metadata, &args).execute(leader, follower) {
|
||||
Ok(build) => {
|
||||
log::info!(
|
||||
"metadata {} success",
|
||||
metadata.directory().as_ref().unwrap().display()
|
||||
);
|
||||
build
|
||||
}
|
||||
Err(error) => {
|
||||
log::warn!(
|
||||
"metadata {} failure: {error:?}",
|
||||
metadata.file_path.as_ref().unwrap().display()
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
corpora.insert(corpus, tests);
|
||||
}
|
||||
|
||||
Ok(corpora)
|
||||
}
|
||||
|
||||
fn main_execute_differential(args: &Arguments, tests: &[Metadata]) -> anyhow::Result<()> {
|
||||
let leader_nodes = NodePool::new(args)?;
|
||||
let follower_nodes = NodePool::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!(),
|
||||
};
|
||||
|
||||
match driver.execute() {
|
||||
Ok(build) => {
|
||||
log::info!(
|
||||
"metadata {} success",
|
||||
metadata.directory().as_ref().unwrap().display()
|
||||
);
|
||||
build
|
||||
}
|
||||
Err(error) => {
|
||||
log::warn!(
|
||||
"metadata {} failure: {error:?}",
|
||||
metadata.file_path.as_ref().unwrap().display()
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn main_compile_only(
|
||||
config: &Arguments,
|
||||
tests: &[Metadata],
|
||||
platform: &TestingPlatform,
|
||||
) -> anyhow::Result<()> {
|
||||
tests.par_iter().for_each(|metadata| {
|
||||
for mode in &metadata.solc_modes() {
|
||||
let mut state = match platform {
|
||||
TestingPlatform::Geth => State::<Geth>::new(config),
|
||||
_ => todo!(),
|
||||
};
|
||||
let _ = state.build_contracts(mode, metadata);
|
||||
}
|
||||
});
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user