diff --git a/crates/compiler/src/solc.rs b/crates/compiler/src/solc.rs index 28e578b..aa21d51 100644 --- a/crates/compiler/src/solc.rs +++ b/crates/compiler/src/solc.rs @@ -6,8 +6,6 @@ use std::{ process::{Command, Stdio}, }; -use semver::Version; - use crate::{CompilerInput, CompilerOutput, SolidityCompiler}; pub struct Solc { diff --git a/crates/config/src/lib.rs b/crates/config/src/lib.rs index 7ab366f..0c6114e 100644 --- a/crates/config/src/lib.rs +++ b/crates/config/src/lib.rs @@ -1,11 +1,8 @@ //! The global configuration used accross all revive differential testing crates. -use std::{ - env, - path::{Path, PathBuf}, -}; +use std::path::{Path, PathBuf}; -use clap::{Arg, Parser, ValueEnum}; +use clap::{Parser, ValueEnum}; use semver::Version; use temp_dir::TempDir; diff --git a/crates/core/src/driver/mod.rs b/crates/core/src/driver/mod.rs index 00c884c..8c8d256 100644 --- a/crates/core/src/driver/mod.rs +++ b/crates/core/src/driver/mod.rs @@ -6,11 +6,7 @@ use alloy::{ }; use revive_dt_compiler::{Compiler, CompilerInput, SolidityCompiler}; use revive_dt_config::Arguments; -use revive_dt_format::{ - input::Input, - metadata::Metadata, - mode::{Mode, SolcMode}, -}; +use revive_dt_format::{input::Input, metadata::Metadata, mode::SolcMode}; use revive_dt_node_interaction::EthereumNode; use revive_dt_solc_binaries::download_solc; use revive_solc_json_interface::SolcStandardJsonOutput; @@ -74,7 +70,8 @@ where &self.deployed_contracts, )?)?; dbg!(&receipt); - node.trace_transaction(receipt) + //node.trace_transaction(receipt) + todo!() } } @@ -114,8 +111,8 @@ where for case in &self.metadata.cases { for input in &case.inputs { - let expected = leader_state.execute_input(input, self.leader_node)?; - let received = follower_state.execute_input(input, self.follower_node)?; + let _ = leader_state.execute_input(input, self.leader_node)?; + let _ = follower_state.execute_input(input, self.follower_node)?; } } } diff --git a/crates/core/src/main.rs b/crates/core/src/main.rs index e64e621..21ab8b0 100644 --- a/crates/core/src/main.rs +++ b/crates/core/src/main.rs @@ -5,7 +5,7 @@ use rayon::{ThreadPoolBuilder, prelude::*}; use revive_dt_config::*; use revive_dt_core::{ - Geth, Kitchensink, + Geth, driver::{Driver, State}, }; use revive_dt_format::{corpus::Corpus, metadata::Metadata}; diff --git a/crates/format/src/input.rs b/crates/format/src/input.rs index 543ae2e..c81dfcf 100644 --- a/crates/format/src/input.rs +++ b/crates/format/src/input.rs @@ -135,7 +135,7 @@ impl Input { }; Ok(TransactionRequest::default() - .with_from(self.caller.clone()) + .with_from(self.caller) .with_to(to) .with_nonce(nonce) .with_chain_id(chain_id) diff --git a/crates/node-interaction/src/tokio_runtime.rs b/crates/node-interaction/src/tokio_runtime.rs index 942d427..d58aa2f 100644 --- a/crates/node-interaction/src/tokio_runtime.rs +++ b/crates/node-interaction/src/tokio_runtime.rs @@ -1,12 +1,13 @@ -//! The alloy crate is convenient but requires a tokio runtime. +//! The alloy crate __requires__ a tokio runtime. //! We contain any async rust right here. use once_cell::sync::Lazy; +use std::pin::Pin; use std::sync::Mutex; use std::thread; use tokio::runtime::Runtime; use tokio::spawn; -use tokio::sync::mpsc; +use tokio::sync::{mpsc, oneshot}; use tokio::task::JoinError; use crate::trace::Trace; @@ -15,15 +16,18 @@ use crate::transaction::Transaction; pub(crate) static TO_TOKIO: Lazy> = Lazy::new(|| Mutex::new(TokioRuntime::spawn())); -// Common interface for executing async node interactions from a non-async context. +/// Common interface for executing async node interactions from a non-async context. +#[allow(clippy::type_complexity)] pub(crate) trait AsyncNodeInteraction: Send + 'static { - type Output: Send + 'static; + type Output: Send; - /// Any async calls the task needs to perform go here. - fn execute_async(self) -> impl std::future::Future + Send; - - /// Returns the interactions output sender. - fn output_sender(&self) -> mpsc::Sender; + //// Returns the task and the output sender. + fn split( + self, + ) -> ( + Pin + Send>>, + oneshot::Sender, + ); } pub(crate) struct TokioRuntime { @@ -58,18 +62,17 @@ impl TokioRuntime { } } -async fn interaction( - mut receiver: mpsc::Receiver, -) -> Result<(), JoinError> { +async fn interaction(mut receiver: mpsc::Receiver) -> Result<(), JoinError> +where + T: AsyncNodeInteraction, +{ while let Some(task) = receiver.recv().await { spawn(async move { - let sender = task.output_sender(); - let result = task.execute_async().await; - if let Err(error) = sender.send(result).await { - log::error!("failed to send task output: {error}"); - } - }) - .await?; + let (task, sender) = task.split(); + sender + .send(task.await) + .unwrap_or_else(|_| panic!("failed to send task output")); + }); } Ok(()) diff --git a/crates/node-interaction/src/trace.rs b/crates/node-interaction/src/trace.rs index 0bbfab1..9255d00 100644 --- a/crates/node-interaction/src/trace.rs +++ b/crates/node-interaction/src/trace.rs @@ -1,57 +1,43 @@ //! Trace transactions in a sync context. -use alloy::primitives::TxHash; -use alloy::providers::ProviderBuilder; -use alloy::providers::ext::DebugApi; -use alloy::rpc::types::TransactionReceipt; -use alloy::rpc::types::trace::geth::{GethDebugTracingOptions, GethTrace}; -use tokio::sync::mpsc; +use std::pin::Pin; + +use alloy::rpc::types::trace::geth::GethTrace; +use tokio::sync::oneshot; use crate::TO_TOKIO; use crate::tokio_runtime::AsyncNodeInteraction; +pub type Task = Pin> + Send>>; + pub(crate) struct Trace { - transaction_hash: TxHash, - options: GethDebugTracingOptions, - geth_trace_sender: mpsc::Sender>, - connection_string: String, + sender: oneshot::Sender>, + task: Task, } impl AsyncNodeInteraction for Trace { type Output = anyhow::Result; - async fn execute_async(self) -> Self::Output { - let provider = ProviderBuilder::new() - .connect(&self.connection_string) - .await?; - Ok(provider - .debug_trace_transaction(self.transaction_hash, self.options) - .await?) - } - - fn output_sender(&self) -> mpsc::Sender { - self.geth_trace_sender.clone() + fn split( + self, + ) -> ( + std::pin::Pin + Send>>, + oneshot::Sender, + ) { + (self.task, self.sender) } } -/// Trace the transaction in [TransactionReceipt] against the `node`, -/// using the provided [GethDebugTracingOptions]. -pub fn trace_transaction( - transaction_receipt: TransactionReceipt, - options: GethDebugTracingOptions, - connection_string: String, -) -> anyhow::Result { - let trace_sender = TO_TOKIO.lock().unwrap().trace_sender.clone(); - let (geth_trace_sender, mut geth_trace_receiver) = mpsc::channel(1); +/// Execute some [Task] that return a [GethTrace] result. +pub fn trace_transaction(task: Task) -> anyhow::Result { + let task_sender = TO_TOKIO.lock().unwrap().trace_sender.clone(); + let (sender, receiver) = oneshot::channel(); - trace_sender.blocking_send(Trace { - transaction_hash: transaction_receipt.transaction_hash, - options, - geth_trace_sender, - connection_string, - })?; + task_sender + .blocking_send(Trace { task, sender }) + .expect("we are not calling this from an async context"); - geth_trace_receiver + receiver .blocking_recv() - .unwrap_or_else(|| anyhow::bail!("no receipt received")) + .unwrap_or_else(|error| anyhow::bail!("no trace received: {error}")) } diff --git a/crates/node-interaction/src/transaction.rs b/crates/node-interaction/src/transaction.rs index 1e83f09..b5af221 100644 --- a/crates/node-interaction/src/transaction.rs +++ b/crates/node-interaction/src/transaction.rs @@ -1,52 +1,46 @@ //! Execute transactions in a sync context. -use alloy::providers::{Provider, ProviderBuilder}; -use alloy::rpc::types::{TransactionReceipt, TransactionRequest}; -use tokio::sync::mpsc; +use std::pin::Pin; + +use alloy::rpc::types::TransactionReceipt; +use tokio::sync::oneshot; use crate::TO_TOKIO; use crate::tokio_runtime::AsyncNodeInteraction; +pub type Task = Pin> + Send>>; + pub(crate) struct Transaction { - transaction_request: TransactionRequest, - receipt_sender: mpsc::Sender>, - connection_string: String, + receipt_sender: oneshot::Sender>, + task: Task, } impl AsyncNodeInteraction for Transaction { type Output = anyhow::Result; - async fn execute_async(self) -> Self::Output { - let provider = ProviderBuilder::new() - .connect(&self.connection_string) - .await?; - Ok(provider - .send_transaction(self.transaction_request) - .await? - .get_receipt() - .await?) - } - - fn output_sender(&self) -> mpsc::Sender { - self.receipt_sender.clone() + fn split( + self, + ) -> ( + Pin + Send>>, + oneshot::Sender, + ) { + (self.task, self.receipt_sender) } } -/// Execute the [TransactionRequest] against the `node`. -pub fn execute_transaction( - transaction_request: TransactionRequest, - connection_string: String, -) -> anyhow::Result { +/// Execute some [Task] that returns a [TransactionReceipt]. +pub fn execute_transaction(task: Task) -> anyhow::Result { let request_sender = TO_TOKIO.lock().unwrap().transaction_sender.clone(); - let (receipt_sender, mut receipt_receiver) = mpsc::channel(1); + let (receipt_sender, receipt_receiver) = oneshot::channel(); - request_sender.blocking_send(Transaction { - transaction_request, - receipt_sender, - connection_string, - })?; + request_sender + .blocking_send(Transaction { + receipt_sender, + task, + }) + .expect("we are not calling this from an async context"); receipt_receiver .blocking_recv() - .unwrap_or_else(|| anyhow::bail!("no receipt received")) + .unwrap_or_else(|error| anyhow::bail!("no receipt received: {error}")) } diff --git a/crates/node/src/geth.rs b/crates/node/src/geth.rs index a46a4c8..84c6b31 100644 --- a/crates/node/src/geth.rs +++ b/crates/node/src/geth.rs @@ -10,9 +10,12 @@ use std::{ time::{Duration, Instant}, }; -use alloy::rpc::types::{ - TransactionReceipt, TransactionRequest, - trace::geth::{DiffMode, PreStateFrame}, +use alloy::{ + providers::{Provider, ProviderBuilder, ext::DebugApi}, + rpc::types::{ + TransactionReceipt, TransactionRequest, + trace::geth::{DiffMode, GethDebugTracingOptions, PreStateConfig, PreStateFrame}, + }, }; use revive_dt_config::Arguments; use revive_dt_node_interaction::{ @@ -144,14 +147,37 @@ impl EthereumNode for Instance { &self, transaction: TransactionRequest, ) -> anyhow::Result { - execute_transaction(transaction, self.connection_string()) + let connection_string = self.connection_string(); + + execute_transaction(Box::pin(async move { + Ok(ProviderBuilder::new() + .connect(&connection_string) + .await? + .send_transaction(transaction) + .await? + .get_receipt() + .await?) + })) } fn trace_transaction( &self, transaction: TransactionReceipt, ) -> anyhow::Result { - trace_transaction(transaction, Default::default(), self.connection_string()) + let connection_string = self.connection_string(); + let trace_options = GethDebugTracingOptions::prestate_tracer(PreStateConfig { + diff_mode: Some(true), + disable_code: None, + disable_storage: None, + }); + + trace_transaction(Box::pin(async move { + Ok(ProviderBuilder::new() + .connect(&connection_string) + .await? + .debug_trace_transaction(transaction.transaction_hash, trace_options) + .await?) + })) } } diff --git a/crates/node/src/pool.rs b/crates/node/src/pool.rs index 0143000..864a742 100644 --- a/crates/node/src/pool.rs +++ b/crates/node/src/pool.rs @@ -61,7 +61,7 @@ where } fn spawn_node(args: &Arguments, genesis: String) -> anyhow::Result { - let mut node = T::new(&args); + let mut node = T::new(args); log::info!("starting node: {}", node.connection_string()); node.spawn(genesis)?; Ok(node)