deploy tx

Signed-off-by: Cyrill Leutwiler <bigcyrill@hotmail.com>
This commit is contained in:
Cyrill Leutwiler
2025-03-25 17:54:40 +01:00
parent a835754d41
commit 34b8879b15
7 changed files with 141 additions and 18 deletions
+4
View File
@@ -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 {
+26 -11
View File
@@ -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
View File
@@ -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",
+55 -2
View File
@@ -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()
}
+1
View File
@@ -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");
+38
View File
@@ -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!()
}
+1 -1
View File
@@ -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(());
}; };