Compare commits

...

4 Commits

Author SHA1 Message Date
Omar Abdulla 448edb0cf3 Cleanup the blocking executor 2025-07-24 15:17:36 +03:00
Omar Abdulla 2aaf2f54c7 Add a ResolverApi interface.
This commit adds a `ResolverApi` trait to the `format` crate that can be
implemented by any type that can act as a resolver. A resolver is able
to provide information on the chain state. This chain state could be
fresh or it could be cached (which is something that we will do in a
future PR).

This cleans up our crate graph so that `format` is not depending on the
node interactions crate for the `EthereumNode` trait.
2025-07-24 15:01:00 +03:00
Omar Abdulla df6ad1e9e2 Refactor some code into the common crate 2025-07-24 14:51:42 +03:00
Omar Abdulla 3494ce250e Add a barebones common crate 2025-07-24 14:30:48 +03:00
24 changed files with 169 additions and 141 deletions
Generated
+15 -5
View File
@@ -3948,6 +3948,17 @@ dependencies = [
"serde_stacker", "serde_stacker",
] ]
[[package]]
name = "revive-dt-common"
version = "0.1.0"
dependencies = [
"anyhow",
"futures",
"once_cell",
"tokio",
"tracing",
]
[[package]] [[package]]
name = "revive-dt-compiler" name = "revive-dt-compiler"
version = "0.1.0" version = "0.1.0"
@@ -3982,6 +3993,7 @@ dependencies = [
"clap", "clap",
"indexmap 2.10.0", "indexmap 2.10.0",
"rayon", "rayon",
"revive-dt-common",
"revive-dt-compiler", "revive-dt-compiler",
"revive-dt-config", "revive-dt-config",
"revive-dt-format", "revive-dt-format",
@@ -4003,7 +4015,7 @@ dependencies = [
"alloy-primitives", "alloy-primitives",
"alloy-sol-types", "alloy-sol-types",
"anyhow", "anyhow",
"revive-dt-node-interaction", "revive-dt-common",
"semver 1.0.26", "semver 1.0.26",
"serde", "serde",
"serde_json", "serde_json",
@@ -4016,7 +4028,9 @@ version = "0.1.0"
dependencies = [ dependencies = [
"alloy", "alloy",
"anyhow", "anyhow",
"revive-dt-common",
"revive-dt-config", "revive-dt-config",
"revive-dt-format",
"revive-dt-node-interaction", "revive-dt-node-interaction",
"serde", "serde",
"serde_json", "serde_json",
@@ -4033,10 +4047,6 @@ version = "0.1.0"
dependencies = [ dependencies = [
"alloy", "alloy",
"anyhow", "anyhow",
"futures",
"once_cell",
"tokio",
"tracing",
] ]
[[package]] [[package]]
+1
View File
@@ -11,6 +11,7 @@ repository = "https://github.com/paritytech/revive-differential-testing.git"
rust-version = "1.85.0" rust-version = "1.85.0"
[workspace.dependencies] [workspace.dependencies]
revive-dt-common = { version = "0.1.0", path = "crates/common" }
revive-dt-compiler = { version = "0.1.0", path = "crates/compiler" } revive-dt-compiler = { version = "0.1.0", path = "crates/compiler" }
revive-dt-config = { version = "0.1.0", path = "crates/config" } revive-dt-config = { version = "0.1.0", path = "crates/config" }
revive-dt-core = { version = "0.1.0", path = "crates/core" } revive-dt-core = { version = "0.1.0", path = "crates/core" }
+16
View File
@@ -0,0 +1,16 @@
[package]
name = "revive-dt-common"
description = "A library containing common concepts that other crates in the workspace can rely on"
version.workspace = true
authors.workspace = true
license.workspace = true
edition.workspace = true
repository.workspace = true
rust-version.workspace = true
[dependencies]
anyhow = { workspace = true }
futures = { workspace = true }
tracing = { workspace = true }
once_cell = { workspace = true }
tokio = { workspace = true }
@@ -23,7 +23,7 @@ use tracing::Instrument;
/// executor to drive an async computation: /// executor to drive an async computation:
/// ///
/// ```rust /// ```rust
/// use revive_dt_node_interaction::*; /// use revive_dt_common::concepts::*;
/// ///
/// fn blocking_function() { /// fn blocking_function() {
/// let result = BlockingExecutor::execute(async move { /// let result = BlockingExecutor::execute(async move {
@@ -134,22 +134,17 @@ impl BlockingExecutor {
} }
}; };
match result.map(|result| { let result = match result {
*result Ok(result) => result,
.downcast::<R>()
.expect("Type mismatch in the downcast")
}) {
Ok(result) => Ok(result),
Err(error) => { Err(error) => {
tracing::error!( tracing::error!(?error, "An error occurred when running the async task");
?error, anyhow::bail!("An error occurred when running the async task: {error:?}")
"Failed to downcast the returned result into the expected type"
);
anyhow::bail!(
"Failed to downcast the returned result into the expected type: {error:?}"
)
} }
} };
Ok(*result
.downcast::<R>()
.expect("An error occurred when downcasting into R. This is a bug"))
} }
} }
/// Represents the state of the async runtime. This runtime is designed to be a singleton runtime /// Represents the state of the async runtime. This runtime is designed to be a singleton runtime
@@ -208,7 +203,9 @@ mod test {
fn panics_in_futures_are_caught() { fn panics_in_futures_are_caught() {
// Act // Act
let result = BlockingExecutor::execute(async move { let result = BlockingExecutor::execute(async move {
panic!("This is a panic!"); panic!(
"If this panic causes, well, a panic, then this is an issue. If it's caught then all good!"
);
0xFFu8 0xFFu8
}); });
+3
View File
@@ -0,0 +1,3 @@
mod blocking_executor;
pub use blocking_executor::*;
+3
View File
@@ -0,0 +1,3 @@
mod files_with_extension_iterator;
pub use files_with_extension_iterator::*;
+6
View File
@@ -0,0 +1,6 @@
//! This crate provides common concepts, functionality, types, macros, and more that other crates in
//! the workspace can benefit from.
pub mod concepts;
pub mod iterators;
pub mod macros;
@@ -12,11 +12,9 @@
/// pub struct CaseId(usize); /// pub struct CaseId(usize);
/// ``` /// ```
/// ///
/// And would also implement a number of methods on this type making it easier /// And would also implement a number of methods on this type making it easier to use.
/// to use.
/// ///
/// These wrapper types become very useful as they make the code a lot easier /// These wrapper types become very useful as they make the code a lot easier to read.
/// to read.
/// ///
/// Take the following as an example: /// Take the following as an example:
/// ///
@@ -26,26 +24,28 @@
/// } /// }
/// ``` /// ```
/// ///
/// In the above code it's hard to understand what the various types refer to or /// In the above code it's hard to understand what the various types refer to or what to expect them
/// what to expect them to contain. /// to contain.
/// ///
/// With these wrapper types we're able to create code that's self-documenting /// With these wrapper types we're able to create code that's self-documenting in that the types
/// in that the types tell us what the code is referring to. The above code is /// tell us what the code is referring to. The above code is transformed into
/// transformed into
/// ///
/// ```rust,ignore /// ```rust,ignore
/// struct State { /// struct State {
/// contracts: HashMap<CaseId, HashMap<ContractName, ContractByteCode>> /// contracts: HashMap<CaseId, HashMap<ContractName, ContractByteCode>>
/// } /// }
/// ``` /// ```
///
/// Note that we follow the same syntax for defining wrapper structs but we do not permit the use of
/// generics.
#[macro_export] #[macro_export]
macro_rules! define_wrapper_type { macro_rules! define_wrapper_type {
( (
$(#[$meta: meta])* $(#[$meta: meta])*
$ident: ident($ty: ty) $(;)? $vis:vis struct $ident: ident($ty: ty);
) => { ) => {
$(#[$meta])* $(#[$meta])*
pub struct $ident($ty); $vis struct $ident($ty);
impl $ident { impl $ident {
pub fn new(value: $ty) -> Self { pub fn new(value: $ty) -> Self {
@@ -104,3 +104,7 @@ macro_rules! define_wrapper_type {
} }
}; };
} }
/// Technically not needed but this allows for the macro to be found in the `macros` module of the
/// crate in addition to being found in the root of the crate.
pub use define_wrapper_type;
+3
View File
@@ -0,0 +1,3 @@
mod define_wrapper_type;
pub use define_wrapper_type::*;
+1
View File
@@ -13,6 +13,7 @@ name = "retester"
path = "src/main.rs" path = "src/main.rs"
[dependencies] [dependencies]
revive-dt-common = { workspace = true }
revive-dt-compiler = { workspace = true } revive-dt-compiler = { workspace = true }
revive-dt-config = { workspace = true } revive-dt-config = { workspace = true }
revive-dt-format = { workspace = true } revive-dt-format = { workspace = true }
+4 -3
View File
@@ -1,6 +1,7 @@
//! 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 std::collections::HashMap; use std::collections::HashMap;
use std::fmt::Debug;
use std::marker::PhantomData; use std::marker::PhantomData;
use alloy::json_abi::JsonAbi; use alloy::json_abi::JsonAbi;
@@ -19,6 +20,9 @@ use alloy::{
}; };
use anyhow::Context; use anyhow::Context;
use indexmap::IndexMap; use indexmap::IndexMap;
use serde_json::Value;
use revive_dt_common::iterators::FilesWithExtensionIterator;
use revive_dt_compiler::{Compiler, SolidityCompiler}; use revive_dt_compiler::{Compiler, SolidityCompiler};
use revive_dt_config::Arguments; use revive_dt_config::Arguments;
use revive_dt_format::case::CaseIdx; use revive_dt_format::case::CaseIdx;
@@ -29,11 +33,8 @@ use revive_dt_node::Node;
use revive_dt_node_interaction::EthereumNode; use revive_dt_node_interaction::EthereumNode;
use revive_dt_report::reporter::{CompilationTask, Report, Span}; use revive_dt_report::reporter::{CompilationTask, Report, Span};
use revive_solc_json_interface::SolcStandardJsonOutput; use revive_solc_json_interface::SolcStandardJsonOutput;
use serde_json::Value;
use std::fmt::Debug;
use crate::Platform; use crate::Platform;
use crate::common::*;
pub struct State<'a, T: Platform> { pub struct State<'a, T: Platform> {
/// The configuration that the framework was started with. /// The configuration that the framework was started with.
+2 -2
View File
@@ -5,17 +5,17 @@
use revive_dt_compiler::{SolidityCompiler, revive_resolc, solc}; use revive_dt_compiler::{SolidityCompiler, revive_resolc, solc};
use revive_dt_config::TestingPlatform; use revive_dt_config::TestingPlatform;
use revive_dt_format::traits::ResolverApi;
use revive_dt_node::{Node, geth, kitchensink::KitchensinkNode}; use revive_dt_node::{Node, geth, kitchensink::KitchensinkNode};
use revive_dt_node_interaction::EthereumNode; use revive_dt_node_interaction::EthereumNode;
pub mod common;
pub mod driver; pub mod driver;
/// One platform can be tested differentially against another. /// One platform can be tested differentially against another.
/// ///
/// For this we need a blockchain node implementation and a compiler. /// For this we need a blockchain node implementation and a compiler.
pub trait Platform { pub trait Platform {
type Blockchain: EthereumNode + Node; type Blockchain: EthereumNode + Node + ResolverApi;
type Compiler: SolidityCompiler; type Compiler: SolidityCompiler;
/// Returns the matching [TestingPlatform] of the [revive_dt_config::Arguments]. /// Returns the matching [TestingPlatform] of the [revive_dt_config::Arguments].
+1 -1
View File
@@ -9,7 +9,7 @@ repository.workspace = true
rust-version.workspace = true rust-version.workspace = true
[dependencies] [dependencies]
revive-dt-node-interaction = { workspace = true } revive-dt-common = { workspace = true }
alloy = { workspace = true } alloy = { workspace = true }
alloy-primitives = { workspace = true } alloy-primitives = { workspace = true }
+3 -2
View File
@@ -1,7 +1,8 @@
use serde::Deserialize; use serde::Deserialize;
use revive_dt_common::macros::define_wrapper_type;
use crate::{ use crate::{
define_wrapper_type,
input::{Expected, Input}, input::{Expected, Input},
mode::Mode, mode::Mode,
}; };
@@ -45,5 +46,5 @@ impl Case {
define_wrapper_type!( define_wrapper_type!(
/// A wrapper type for the index of test cases found in metadata file. /// A wrapper type for the index of test cases found in metadata file.
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
CaseIdx(usize); pub struct CaseIdx(usize);
); );
+29 -60
View File
@@ -11,9 +11,10 @@ use alloy_primitives::{FixedBytes, utils::parse_units};
use semver::VersionReq; use semver::VersionReq;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use revive_dt_node_interaction::EthereumNode; use revive_dt_common::macros::define_wrapper_type;
use crate::{define_wrapper_type, metadata::ContractInstance}; use crate::metadata::ContractInstance;
use crate::traits::ResolverApi;
#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq)] #[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq)]
pub struct Input { pub struct Input {
@@ -84,7 +85,7 @@ pub enum Method {
define_wrapper_type!( define_wrapper_type!(
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] #[derive(Clone, Copy, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
EtherValue(U256); pub struct EtherValue(U256);
); );
impl Serialize for EtherValue { impl Serialize for EtherValue {
@@ -154,7 +155,7 @@ impl Calldata {
pub fn calldata( pub fn calldata(
&self, &self,
deployed_contracts: &HashMap<ContractInstance, (Address, JsonAbi)>, deployed_contracts: &HashMap<ContractInstance, (Address, JsonAbi)>,
chain_state_provider: &impl EthereumNode, chain_state_provider: &impl ResolverApi,
) -> anyhow::Result<Vec<u8>> { ) -> anyhow::Result<Vec<u8>> {
let mut buffer = Vec::<u8>::with_capacity(self.size_requirement()); let mut buffer = Vec::<u8>::with_capacity(self.size_requirement());
self.calldata_into_slice(&mut buffer, deployed_contracts, chain_state_provider)?; self.calldata_into_slice(&mut buffer, deployed_contracts, chain_state_provider)?;
@@ -165,7 +166,7 @@ impl Calldata {
&self, &self,
buffer: &mut Vec<u8>, buffer: &mut Vec<u8>,
deployed_contracts: &HashMap<ContractInstance, (Address, JsonAbi)>, deployed_contracts: &HashMap<ContractInstance, (Address, JsonAbi)>,
chain_state_provider: &impl EthereumNode, chain_state_provider: &impl ResolverApi,
) -> anyhow::Result<()> { ) -> anyhow::Result<()> {
match self { match self {
Calldata::Single(bytes) => { Calldata::Single(bytes) => {
@@ -200,7 +201,7 @@ impl Calldata {
&self, &self,
other: &[u8], other: &[u8],
deployed_contracts: &HashMap<ContractInstance, (Address, JsonAbi)>, deployed_contracts: &HashMap<ContractInstance, (Address, JsonAbi)>,
chain_state_provider: &impl EthereumNode, chain_state_provider: &impl ResolverApi,
) -> anyhow::Result<bool> { ) -> anyhow::Result<bool> {
match self { match self {
Calldata::Single(calldata) => Ok(calldata == other), Calldata::Single(calldata) => Ok(calldata == other),
@@ -249,7 +250,7 @@ impl Input {
pub fn encoded_input( pub fn encoded_input(
&self, &self,
deployed_contracts: &HashMap<ContractInstance, (Address, JsonAbi)>, deployed_contracts: &HashMap<ContractInstance, (Address, JsonAbi)>,
chain_state_provider: &impl EthereumNode, chain_state_provider: &impl ResolverApi,
) -> anyhow::Result<Bytes> { ) -> anyhow::Result<Bytes> {
match self.method { match self.method {
Method::Deployer | Method::Fallback => { Method::Deployer | Method::Fallback => {
@@ -316,7 +317,7 @@ impl Input {
pub fn legacy_transaction( pub fn legacy_transaction(
&self, &self,
deployed_contracts: &HashMap<ContractInstance, (Address, JsonAbi)>, deployed_contracts: &HashMap<ContractInstance, (Address, JsonAbi)>,
chain_state_provider: &impl EthereumNode, chain_state_provider: &impl ResolverApi,
) -> anyhow::Result<TransactionRequest> { ) -> anyhow::Result<TransactionRequest> {
let input_data = self.encoded_input(deployed_contracts, chain_state_provider)?; let input_data = self.encoded_input(deployed_contracts, chain_state_provider)?;
let transaction_request = TransactionRequest::default().from(self.caller).value( let transaction_request = TransactionRequest::default().from(self.caller).value(
@@ -363,7 +364,7 @@ pub const fn default_caller() -> Address {
fn resolve_argument( fn resolve_argument(
value: &str, value: &str,
deployed_contracts: &HashMap<ContractInstance, (Address, JsonAbi)>, deployed_contracts: &HashMap<ContractInstance, (Address, JsonAbi)>,
chain_state_provider: &impl EthereumNode, chain_state_provider: &impl ResolverApi,
) -> anyhow::Result<U256> { ) -> anyhow::Result<U256> {
if let Some(instance) = value.strip_suffix(".address") { if let Some(instance) = value.strip_suffix(".address") {
Ok(U256::from_be_slice( Ok(U256::from_be_slice(
@@ -432,31 +433,9 @@ mod tests {
use alloy_sol_types::SolValue; use alloy_sol_types::SolValue;
use std::collections::HashMap; use std::collections::HashMap;
struct DummyEthereumNode; struct MockResolver;
impl EthereumNode for DummyEthereumNode {
fn execute_transaction(
&self,
_: TransactionRequest,
) -> anyhow::Result<alloy::rpc::types::TransactionReceipt> {
unimplemented!()
}
fn trace_transaction(
&self,
_: &alloy::rpc::types::TransactionReceipt,
_: alloy::rpc::types::trace::geth::GethDebugTracingOptions,
) -> anyhow::Result<alloy::rpc::types::trace::geth::GethTrace> {
unimplemented!()
}
fn state_diff(
&self,
_: &alloy::rpc::types::TransactionReceipt,
) -> anyhow::Result<alloy::rpc::types::trace::geth::DiffMode> {
unimplemented!()
}
impl ResolverApi for MockResolver {
fn chain_id(&self) -> anyhow::Result<alloy_primitives::ChainId> { fn chain_id(&self) -> anyhow::Result<alloy_primitives::ChainId> {
Ok(0x123) Ok(0x123)
} }
@@ -528,7 +507,7 @@ mod tests {
(Address::ZERO, parsed_abi), (Address::ZERO, parsed_abi),
); );
let encoded = input.encoded_input(&contracts, &DummyEthereumNode).unwrap(); let encoded = input.encoded_input(&contracts, &MockResolver).unwrap();
assert!(encoded.0.starts_with(&selector)); assert!(encoded.0.starts_with(&selector));
type T = (u64,); type T = (u64,);
@@ -572,7 +551,7 @@ mod tests {
(Address::ZERO, parsed_abi), (Address::ZERO, parsed_abi),
); );
let encoded = input.encoded_input(&contracts, &DummyEthereumNode).unwrap(); let encoded = input.encoded_input(&contracts, &MockResolver).unwrap();
assert!(encoded.0.starts_with(&selector)); assert!(encoded.0.starts_with(&selector));
type T = (alloy_primitives::Address,); type T = (alloy_primitives::Address,);
@@ -619,7 +598,7 @@ mod tests {
(Address::ZERO, parsed_abi), (Address::ZERO, parsed_abi),
); );
let encoded = input.encoded_input(&contracts, &DummyEthereumNode).unwrap(); let encoded = input.encoded_input(&contracts, &MockResolver).unwrap();
assert!(encoded.0.starts_with(&selector)); assert!(encoded.0.starts_with(&selector));
type T = (alloy_primitives::Address,); type T = (alloy_primitives::Address,);
@@ -636,11 +615,11 @@ mod tests {
let input = "$CHAIN_ID"; let input = "$CHAIN_ID";
// Act // Act
let resolved = resolve_argument(input, &Default::default(), &DummyEthereumNode); let resolved = resolve_argument(input, &Default::default(), &MockResolver);
// Assert // Assert
let resolved = resolved.expect("Failed to resolve argument"); let resolved = resolved.expect("Failed to resolve argument");
assert_eq!(resolved, U256::from(DummyEthereumNode.chain_id().unwrap())) assert_eq!(resolved, U256::from(MockResolver.chain_id().unwrap()))
} }
#[test] #[test]
@@ -649,17 +628,13 @@ mod tests {
let input = "$GAS_LIMIT"; let input = "$GAS_LIMIT";
// Act // Act
let resolved = resolve_argument(input, &Default::default(), &DummyEthereumNode); let resolved = resolve_argument(input, &Default::default(), &MockResolver);
// Assert // Assert
let resolved = resolved.expect("Failed to resolve argument"); let resolved = resolved.expect("Failed to resolve argument");
assert_eq!( assert_eq!(
resolved, resolved,
U256::from( U256::from(MockResolver.block_gas_limit(Default::default()).unwrap())
DummyEthereumNode
.block_gas_limit(Default::default())
.unwrap()
)
) )
} }
@@ -669,14 +644,14 @@ mod tests {
let input = "$COINBASE"; let input = "$COINBASE";
// Act // Act
let resolved = resolve_argument(input, &Default::default(), &DummyEthereumNode); let resolved = resolve_argument(input, &Default::default(), &MockResolver);
// Assert // Assert
let resolved = resolved.expect("Failed to resolve argument"); let resolved = resolved.expect("Failed to resolve argument");
assert_eq!( assert_eq!(
resolved, resolved,
U256::from_be_slice( U256::from_be_slice(
DummyEthereumNode MockResolver
.block_coinbase(Default::default()) .block_coinbase(Default::default())
.unwrap() .unwrap()
.as_ref() .as_ref()
@@ -690,15 +665,13 @@ mod tests {
let input = "$DIFFICULTY"; let input = "$DIFFICULTY";
// Act // Act
let resolved = resolve_argument(input, &Default::default(), &DummyEthereumNode); let resolved = resolve_argument(input, &Default::default(), &MockResolver);
// Assert // Assert
let resolved = resolved.expect("Failed to resolve argument"); let resolved = resolved.expect("Failed to resolve argument");
assert_eq!( assert_eq!(
resolved, resolved,
DummyEthereumNode MockResolver.block_difficulty(Default::default()).unwrap()
.block_difficulty(Default::default())
.unwrap()
) )
} }
@@ -708,13 +681,13 @@ mod tests {
let input = "$BLOCK_HASH"; let input = "$BLOCK_HASH";
// Act // Act
let resolved = resolve_argument(input, &Default::default(), &DummyEthereumNode); let resolved = resolve_argument(input, &Default::default(), &MockResolver);
// Assert // Assert
let resolved = resolved.expect("Failed to resolve argument"); let resolved = resolved.expect("Failed to resolve argument");
assert_eq!( assert_eq!(
resolved, resolved,
U256::from_be_bytes(DummyEthereumNode.block_hash(Default::default()).unwrap().0) U256::from_be_bytes(MockResolver.block_hash(Default::default()).unwrap().0)
) )
} }
@@ -724,13 +697,13 @@ mod tests {
let input = "$BLOCK_NUMBER"; let input = "$BLOCK_NUMBER";
// Act // Act
let resolved = resolve_argument(input, &Default::default(), &DummyEthereumNode); let resolved = resolve_argument(input, &Default::default(), &MockResolver);
// Assert // Assert
let resolved = resolved.expect("Failed to resolve argument"); let resolved = resolved.expect("Failed to resolve argument");
assert_eq!( assert_eq!(
resolved, resolved,
U256::from(DummyEthereumNode.last_block_number().unwrap()) U256::from(MockResolver.last_block_number().unwrap())
) )
} }
@@ -740,17 +713,13 @@ mod tests {
let input = "$BLOCK_TIMESTAMP"; let input = "$BLOCK_TIMESTAMP";
// Act // Act
let resolved = resolve_argument(input, &Default::default(), &DummyEthereumNode); let resolved = resolve_argument(input, &Default::default(), &MockResolver);
// Assert // Assert
let resolved = resolved.expect("Failed to resolve argument"); let resolved = resolved.expect("Failed to resolve argument");
assert_eq!( assert_eq!(
resolved, resolved,
U256::from( U256::from(MockResolver.block_timestamp(Default::default()).unwrap())
DummyEthereumNode
.block_timestamp(Default::default())
.unwrap()
)
) )
} }
} }
+1 -1
View File
@@ -3,6 +3,6 @@
pub mod case; pub mod case;
pub mod corpus; pub mod corpus;
pub mod input; pub mod input;
pub mod macros;
pub mod metadata; pub mod metadata;
pub mod mode; pub mod mode;
pub mod traits;
+10 -5
View File
@@ -9,9 +9,10 @@ use std::{
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use revive_dt_common::macros::define_wrapper_type;
use crate::{ use crate::{
case::Case, case::Case,
define_wrapper_type,
mode::{Mode, SolcMode}, mode::{Mode, SolcMode},
}; };
@@ -217,18 +218,22 @@ define_wrapper_type!(
/// Represents a contract instance found a metadata file. /// Represents a contract instance found a metadata file.
/// ///
/// Typically, this is used as the key to the "contracts" field of metadata files. /// Typically, this is used as the key to the "contracts" field of metadata files.
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)] #[derive(
Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize,
)]
#[serde(transparent)] #[serde(transparent)]
ContractInstance(String); pub struct ContractInstance(String);
); );
define_wrapper_type!( define_wrapper_type!(
/// Represents a contract identifier found a metadata file. /// Represents a contract identifier found a metadata file.
/// ///
/// A contract identifier is the name of the contract in the source code. /// A contract identifier is the name of the contract in the source code.
#[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)] #[derive(
Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize,
)]
#[serde(transparent)] #[serde(transparent)]
ContractIdent(String); pub struct ContractIdent(String);
); );
/// Represents an identifier used for contracts. /// Represents an identifier used for contracts.
+30
View File
@@ -0,0 +1,30 @@
use alloy::eips::BlockNumberOrTag;
use alloy::primitives::{Address, BlockHash, BlockNumber, BlockTimestamp, ChainId, U256};
use anyhow::Result;
/// A trait of the interface are required to implement to be used by the resolution logic that this
/// crate implements to go from string calldata and into the bytes calldata.
pub trait ResolverApi {
/// Returns the ID of the chain that the node is on.
fn chain_id(&self) -> Result<ChainId>;
// TODO: This is currently a u128 due to Kitchensink needing more than 64 bits for its gas limit
// when we implement the changes to the gas we need to adjust this to be a u64.
/// Returns the gas limit of the specified block.
fn block_gas_limit(&self, number: BlockNumberOrTag) -> Result<u128>;
/// Returns the coinbase of the specified block.
fn block_coinbase(&self, number: BlockNumberOrTag) -> Result<Address>;
/// Returns the difficulty of the specified block.
fn block_difficulty(&self, number: BlockNumberOrTag) -> Result<U256>;
/// Returns the hash of the specified block.
fn block_hash(&self, number: BlockNumberOrTag) -> Result<BlockHash>;
/// Returns the timestamp of the specified block,
fn block_timestamp(&self, number: BlockNumberOrTag) -> Result<BlockTimestamp>;
/// Returns the number of the last block.
fn last_block_number(&self) -> Result<BlockNumber>;
}
-4
View File
@@ -11,7 +11,3 @@ rust-version.workspace = true
[dependencies] [dependencies]
alloy = { workspace = true } alloy = { workspace = true }
anyhow = { workspace = true } anyhow = { workspace = true }
futures = { workspace = true }
tracing = { workspace = true }
once_cell = { workspace = true }
tokio = { workspace = true }
-28
View File
@@ -1,14 +1,9 @@
//! This crate implements all node interactions. //! This crate implements all node interactions.
use alloy::eips::BlockNumberOrTag;
use alloy::primitives::{Address, BlockHash, BlockNumber, BlockTimestamp, ChainId, U256};
use alloy::rpc::types::trace::geth::{DiffMode, GethDebugTracingOptions, GethTrace}; use alloy::rpc::types::trace::geth::{DiffMode, GethDebugTracingOptions, GethTrace};
use alloy::rpc::types::{TransactionReceipt, TransactionRequest}; use alloy::rpc::types::{TransactionReceipt, TransactionRequest};
use anyhow::Result; use anyhow::Result;
mod blocking_executor;
pub use blocking_executor::*;
/// An interface for all interactions with Ethereum compatible nodes. /// An interface for all interactions with Ethereum compatible nodes.
pub trait EthereumNode { pub trait EthereumNode {
/// Execute the [TransactionRequest] and return a [TransactionReceipt]. /// Execute the [TransactionRequest] and return a [TransactionReceipt].
@@ -23,27 +18,4 @@ pub trait EthereumNode {
/// Returns the state diff of the transaction hash in the [TransactionReceipt]. /// Returns the state diff of the transaction hash in the [TransactionReceipt].
fn state_diff(&self, receipt: &TransactionReceipt) -> Result<DiffMode>; fn state_diff(&self, receipt: &TransactionReceipt) -> Result<DiffMode>;
/// Returns the ID of the chain that the node is on.
fn chain_id(&self) -> Result<ChainId>;
// TODO: This is currently a u128 due to Kitchensink needing more than 64 bits for its gas limit
// when we implement the changes to the gas we need to adjust this to be a u64.
/// Returns the gas limit of the specified block.
fn block_gas_limit(&self, number: BlockNumberOrTag) -> Result<u128>;
/// Returns the coinbase of the specified block.
fn block_coinbase(&self, number: BlockNumberOrTag) -> Result<Address>;
/// Returns the difficulty of the specified block.
fn block_difficulty(&self, number: BlockNumberOrTag) -> Result<U256>;
/// Returns the hash of the specified block.
fn block_hash(&self, number: BlockNumberOrTag) -> Result<BlockHash>;
/// Returns the timestamp of the specified block,
fn block_timestamp(&self, number: BlockNumberOrTag) -> Result<BlockTimestamp>;
/// Returns the number of the last block.
fn last_block_number(&self) -> Result<BlockNumber>;
} }
+3 -1
View File
@@ -14,8 +14,10 @@ alloy = { workspace = true }
tracing = { workspace = true } tracing = { workspace = true }
tokio = { workspace = true } tokio = { workspace = true }
revive-dt-node-interaction = { workspace = true } revive-dt-common = { workspace = true }
revive-dt-config = { workspace = true } revive-dt-config = { workspace = true }
revive-dt-format = { workspace = true }
revive-dt-node-interaction = { workspace = true }
serde = { workspace = true } serde = { workspace = true }
serde_json = { workspace = true } serde_json = { workspace = true }
+5 -1
View File
@@ -25,8 +25,10 @@ use alloy::{
}, },
signers::local::PrivateKeySigner, signers::local::PrivateKeySigner,
}; };
use revive_dt_common::concepts::BlockingExecutor;
use revive_dt_config::Arguments; use revive_dt_config::Arguments;
use revive_dt_node_interaction::{BlockingExecutor, EthereumNode}; use revive_dt_format::traits::ResolverApi;
use revive_dt_node_interaction::EthereumNode;
use tracing::Level; use tracing::Level;
use crate::{Node, common::FallbackGasFiller, constants::INITIAL_BALANCE}; use crate::{Node, common::FallbackGasFiller, constants::INITIAL_BALANCE};
@@ -343,7 +345,9 @@ impl EthereumNode for Instance {
_ => anyhow::bail!("expected a diff mode trace"), _ => anyhow::bail!("expected a diff mode trace"),
} }
} }
}
impl ResolverApi for Instance {
#[tracing::instrument(skip_all, fields(geth_node_id = self.id))] #[tracing::instrument(skip_all, fields(geth_node_id = self.id))]
fn chain_id(&self) -> anyhow::Result<alloy::primitives::ChainId> { fn chain_id(&self) -> anyhow::Result<alloy::primitives::ChainId> {
let provider = self.provider(); let provider = self.provider();
+5 -1
View File
@@ -30,14 +30,16 @@ use alloy::{
}, },
signers::local::PrivateKeySigner, signers::local::PrivateKeySigner,
}; };
use revive_dt_format::traits::ResolverApi;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use serde_json::{Value as JsonValue, json}; use serde_json::{Value as JsonValue, json};
use sp_core::crypto::Ss58Codec; use sp_core::crypto::Ss58Codec;
use sp_runtime::AccountId32; use sp_runtime::AccountId32;
use tracing::Level; use tracing::Level;
use revive_dt_common::concepts::BlockingExecutor;
use revive_dt_config::Arguments; use revive_dt_config::Arguments;
use revive_dt_node_interaction::{BlockingExecutor, EthereumNode}; use revive_dt_node_interaction::EthereumNode;
use crate::{Node, common::FallbackGasFiller, constants::INITIAL_BALANCE}; use crate::{Node, common::FallbackGasFiller, constants::INITIAL_BALANCE};
@@ -424,7 +426,9 @@ impl EthereumNode for KitchensinkNode {
_ => anyhow::bail!("expected a diff mode trace"), _ => anyhow::bail!("expected a diff mode trace"),
} }
} }
}
impl ResolverApi for KitchensinkNode {
#[tracing::instrument(skip_all, fields(geth_node_id = self.id))] #[tracing::instrument(skip_all, fields(geth_node_id = self.id))]
fn chain_id(&self) -> anyhow::Result<alloy::primitives::ChainId> { fn chain_id(&self) -> anyhow::Result<alloy::primitives::ChainId> {
let provider = self.provider(); let provider = self.provider();