mirror of
https://github.com/pezkuwichain/revive-differential-tests.git
synced 2026-06-15 14:51:05 +00:00
@@ -81,6 +81,10 @@ pub struct Arguments {
|
|||||||
/// Only compile against this testing platform (doesn't execute the tests).
|
/// Only compile against this testing platform (doesn't execute the tests).
|
||||||
#[arg(long = "compile-only")]
|
#[arg(long = "compile-only")]
|
||||||
pub compile_only: bool,
|
pub compile_only: bool,
|
||||||
|
|
||||||
|
/// Determines the amount of tests that are executed in parallel.
|
||||||
|
#[arg(long = "workers", default_value = "12")]
|
||||||
|
pub workers: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Arguments {
|
impl Arguments {
|
||||||
|
|||||||
@@ -1,14 +1,17 @@
|
|||||||
//! The test driver handles the compilation and execution of the test cases.
|
//! The test driver handles the compilation and execution of the test cases.
|
||||||
|
|
||||||
use alloy::primitives::{Address, map::HashMap};
|
use alloy::{
|
||||||
|
primitives::{Address, map::HashMap},
|
||||||
|
rpc::types::trace::geth::GethTrace,
|
||||||
|
};
|
||||||
use revive_dt_compiler::{Compiler, CompilerInput, SolidityCompiler};
|
use revive_dt_compiler::{Compiler, CompilerInput, SolidityCompiler};
|
||||||
use revive_dt_config::Arguments;
|
use revive_dt_config::Arguments;
|
||||||
use revive_dt_format::{
|
use revive_dt_format::{
|
||||||
case::Case,
|
input::Input,
|
||||||
metadata::Metadata,
|
metadata::Metadata,
|
||||||
mode::{Mode, SolcMode},
|
mode::{Mode, SolcMode},
|
||||||
};
|
};
|
||||||
use revive_dt_node::Node;
|
use revive_dt_node_interaction::EthereumNode;
|
||||||
use revive_dt_solc_binaries::download_solc;
|
use revive_dt_solc_binaries::download_solc;
|
||||||
use revive_solc_json_interface::SolcStandardJsonOutput;
|
use revive_solc_json_interface::SolcStandardJsonOutput;
|
||||||
|
|
||||||
@@ -23,7 +26,6 @@ pub struct State<'a, T: Platform> {
|
|||||||
config: &'a Arguments,
|
config: &'a Arguments,
|
||||||
contracts: Contracts<T>,
|
contracts: Contracts<T>,
|
||||||
deployed_contracts: HashMap<String, Address>,
|
deployed_contracts: HashMap<String, Address>,
|
||||||
node: T::Blockchain,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T> State<'a, T>
|
impl<'a, T> State<'a, T>
|
||||||
@@ -35,7 +37,6 @@ where
|
|||||||
config,
|
config,
|
||||||
contracts: Default::default(),
|
contracts: Default::default(),
|
||||||
deployed_contracts: Default::default(),
|
deployed_contracts: Default::default(),
|
||||||
node: <T::Blockchain as Node>::new(config),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -61,10 +62,18 @@ where
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn execute_case(&mut self, case: &Case) -> anyhow::Result<()> {
|
pub fn execute_input(
|
||||||
for input in &case.inputs {}
|
&mut self,
|
||||||
|
input: &Input,
|
||||||
Ok(())
|
node: &T::Blockchain,
|
||||||
|
) -> anyhow::Result<GethTrace> {
|
||||||
|
let receipt = node.execute_transaction(input.legacy_transaction(
|
||||||
|
self.config.network_id,
|
||||||
|
0,
|
||||||
|
&self.deployed_contracts,
|
||||||
|
)?)?;
|
||||||
|
dbg!(&receipt);
|
||||||
|
Ok(node.trace_transaction(receipt)?)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -89,7 +98,11 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn execute(&mut self) -> anyhow::Result<()> {
|
pub fn execute(
|
||||||
|
&mut self,
|
||||||
|
leader: L::Blockchain,
|
||||||
|
follower: F::Blockchain,
|
||||||
|
) -> anyhow::Result<()> {
|
||||||
for mode in self.modes() {
|
for mode in self.modes() {
|
||||||
self.leader.build_contracts(&mode, self.metadata)?;
|
self.leader.build_contracts(&mode, self.metadata)?;
|
||||||
self.follower.build_contracts(&mode, self.metadata)?;
|
self.follower.build_contracts(&mode, self.metadata)?;
|
||||||
@@ -99,7 +112,9 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
for case in &self.metadata.cases {
|
for case in &self.metadata.cases {
|
||||||
self.leader.execute_case(case)?;
|
for input in &case.inputs {
|
||||||
|
let expected = self.leader.execute_input(input, &leader)?;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
*self = Self::new(self.metadata, self.config);
|
*self = Self::new(self.metadata, self.config);
|
||||||
|
|||||||
+16
-4
@@ -1,11 +1,12 @@
|
|||||||
use std::collections::BTreeSet;
|
use std::collections::BTreeSet;
|
||||||
|
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
use rayon::prelude::*;
|
use rayon::{ThreadPoolBuilder, prelude::*};
|
||||||
|
|
||||||
use revive_dt_config::*;
|
use revive_dt_config::*;
|
||||||
use revive_dt_core::{Geth, Kitchensink, driver::Driver};
|
use revive_dt_core::{Geth, Kitchensink, driver::Driver};
|
||||||
use revive_dt_format::corpus::Corpus;
|
use revive_dt_format::corpus::Corpus;
|
||||||
|
use revive_dt_node::{Node, geth};
|
||||||
use temp_dir::TempDir;
|
use temp_dir::TempDir;
|
||||||
|
|
||||||
fn main() -> anyhow::Result<()> {
|
fn main() -> anyhow::Result<()> {
|
||||||
@@ -19,23 +20,34 @@ fn main() -> anyhow::Result<()> {
|
|||||||
args.temp_dir = TempDir::new()?.into()
|
args.temp_dir = TempDir::new()?.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ThreadPoolBuilder::new()
|
||||||
|
.num_threads(args.workers)
|
||||||
|
.build_global()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
for path in args.corpus.iter().collect::<BTreeSet<_>>() {
|
for path in args.corpus.iter().collect::<BTreeSet<_>>() {
|
||||||
log::trace!("attempting corpus {path:?}");
|
log::trace!("attempting corpus {path:?}");
|
||||||
let corpus = Corpus::try_from_path(path)?;
|
let corpus = Corpus::try_from_path(path)?;
|
||||||
log::info!("found corpus: {corpus:?}");
|
log::info!("found corpus: {corpus:?}");
|
||||||
|
|
||||||
let tests = corpus.enumerate_tests();
|
let tests = corpus.enumerate_tests();
|
||||||
log::info!("found {} tests", tests.len());
|
log::info!("corpus '{}' contains {} tests", &corpus.name, tests.len());
|
||||||
|
|
||||||
tests.par_iter().for_each(|metadata| {
|
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) {
|
let mut driver = match (&args.leader, &args.follower) {
|
||||||
(TestingPlatform::Geth, TestingPlatform::Kitchensink) => {
|
(TestingPlatform::Geth, TestingPlatform::Kitchensink) => {
|
||||||
Driver::<Geth, Kitchensink>::new(metadata, &args)
|
Driver::<Geth, Geth>::new(metadata, &args)
|
||||||
}
|
}
|
||||||
_ => unimplemented!(),
|
_ => unimplemented!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
match driver.execute() {
|
match Driver::<Geth, Geth>::new(metadata, &args).execute(leader, follower) {
|
||||||
Ok(build) => {
|
Ok(build) => {
|
||||||
log::info!(
|
log::info!(
|
||||||
"metadata {} success",
|
"metadata {} success",
|
||||||
|
|||||||
@@ -1,4 +1,9 @@
|
|||||||
use alloy::json_abi::Function;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use alloy::{
|
||||||
|
json_abi::Function, network::TransactionBuilder, primitives::Address,
|
||||||
|
rpc::types::TransactionRequest,
|
||||||
|
};
|
||||||
use semver::VersionReq;
|
use semver::VersionReq;
|
||||||
use serde::{Deserialize, de::Deserializer};
|
use serde::{Deserialize, de::Deserializer};
|
||||||
use serde_json::Value;
|
use serde_json::Value;
|
||||||
@@ -26,11 +31,17 @@ where
|
|||||||
|
|
||||||
#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq)]
|
#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq)]
|
||||||
pub struct Input {
|
pub struct Input {
|
||||||
pub instance: Option<String>,
|
#[serde(default = "default_caller")]
|
||||||
|
pub caller: Address,
|
||||||
|
pub comment: Option<String>,
|
||||||
|
#[serde(default = "default_instance")]
|
||||||
|
pub instance: String,
|
||||||
#[serde(deserialize_with = "deserialize_method")]
|
#[serde(deserialize_with = "deserialize_method")]
|
||||||
pub method: Method,
|
pub method: Method,
|
||||||
pub calldata: Option<Calldata>,
|
pub calldata: Option<Calldata>,
|
||||||
pub expected: Option<Expected>,
|
pub expected: Option<Expected>,
|
||||||
|
pub value: Option<String>,
|
||||||
|
pub storage: Option<HashMap<String, Calldata>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Deserialize, Eq, PartialEq)]
|
#[derive(Clone, Debug, Deserialize, Eq, PartialEq)]
|
||||||
@@ -98,3 +109,45 @@ where
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Input {
|
||||||
|
fn instance_to_address(
|
||||||
|
&self,
|
||||||
|
instance: &str,
|
||||||
|
deployed_contracts: &HashMap<String, Address>,
|
||||||
|
) -> anyhow::Result<Address> {
|
||||||
|
deployed_contracts
|
||||||
|
.get(instance)
|
||||||
|
.copied()
|
||||||
|
.ok_or_else(|| anyhow::anyhow!("instance {instance} not deployed"))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Parse this input into a legacy transaction.
|
||||||
|
pub fn legacy_transaction(
|
||||||
|
&self,
|
||||||
|
chain_id: u64,
|
||||||
|
nonce: u64,
|
||||||
|
deployed_contracts: &HashMap<String, Address>,
|
||||||
|
) -> anyhow::Result<TransactionRequest> {
|
||||||
|
let to = match self.method {
|
||||||
|
Method::Deployer => Address::ZERO,
|
||||||
|
_ => self.instance_to_address(&self.instance, deployed_contracts)?,
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(TransactionRequest::default()
|
||||||
|
.with_from(self.caller.clone())
|
||||||
|
.with_to(to)
|
||||||
|
.with_nonce(nonce)
|
||||||
|
.with_chain_id(chain_id)
|
||||||
|
.with_gas_price(20_000_000_000)
|
||||||
|
.with_gas_limit(20_000_000_000))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn default_instance() -> String {
|
||||||
|
"Test".to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn default_caller() -> Address {
|
||||||
|
"90F8bf6A479f320ead074411a4B0e7944Ea8c9C1".parse().unwrap()
|
||||||
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ use revive_dt_config::Arguments;
|
|||||||
use revive_dt_node_interaction::EthereumNode;
|
use revive_dt_node_interaction::EthereumNode;
|
||||||
|
|
||||||
pub mod geth;
|
pub mod geth;
|
||||||
|
pub mod pool;
|
||||||
|
|
||||||
/// The default genesis configuration.
|
/// The default genesis configuration.
|
||||||
pub const GENESIS_JSON: &str = include_str!("../../../genesis.json");
|
pub const GENESIS_JSON: &str = include_str!("../../../genesis.json");
|
||||||
|
|||||||
@@ -0,0 +1,38 @@
|
|||||||
|
use std::sync::{
|
||||||
|
LazyLock, Mutex,
|
||||||
|
mpsc::{Receiver, Sender},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub trait NodePool<T: Node> {
|
||||||
|
fn access() -> &'static LazyLock<Mutex<Vec<T>>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
use revive_dt_config::Arguments;
|
||||||
|
|
||||||
|
use crate::Node;
|
||||||
|
|
||||||
|
//static POOL: LazyLock<Mutex<Pool<T>>> = LazyLock::new(Default::default);
|
||||||
|
|
||||||
|
pub struct Handle<T> {
|
||||||
|
node: T,
|
||||||
|
notifier: Sender<()>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Pool<T> {
|
||||||
|
request: Receiver<()>,
|
||||||
|
nodes: usize,
|
||||||
|
handles: Vec<T>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Pool<T>
|
||||||
|
where
|
||||||
|
T: Node,
|
||||||
|
{
|
||||||
|
pub fn spawn() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
// spawner: loops on a queue
|
||||||
|
|
||||||
|
pub fn get_handle<T: Node + NodePool<T>>(config: &Arguments) -> Receiver<T> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
@@ -39,7 +39,7 @@ fn download_to_file(path: &Path, downloader: &GHDownloader) -> anyhow::Result<()
|
|||||||
log::info!("caching file: {}", path.display());
|
log::info!("caching file: {}", path.display());
|
||||||
|
|
||||||
let Ok(file) = File::create_new(path) else {
|
let Ok(file) = File::create_new(path) else {
|
||||||
log::warn!("cache file already exists: {}", path.display());
|
log::debug!("cache file already exists: {}", path.display());
|
||||||
return Ok(());
|
return Ok(());
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user