diff --git a/Cargo.lock b/Cargo.lock index 5dde5f9..39a8a80 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4016,7 +4016,6 @@ dependencies = [ "alloy-sol-types", "anyhow", "revive-dt-common", - "revive-dt-node-interaction", "semver 1.0.26", "serde", "serde_json", @@ -4031,6 +4030,7 @@ dependencies = [ "anyhow", "revive-dt-common", "revive-dt-config", + "revive-dt-format", "revive-dt-node-interaction", "serde", "serde_json", diff --git a/crates/core/src/lib.rs b/crates/core/src/lib.rs index a955838..c332803 100644 --- a/crates/core/src/lib.rs +++ b/crates/core/src/lib.rs @@ -5,6 +5,7 @@ use revive_dt_compiler::{SolidityCompiler, revive_resolc, solc}; use revive_dt_config::TestingPlatform; +use revive_dt_format::traits::ResolverApi; use revive_dt_node::{Node, geth, kitchensink::KitchensinkNode}; use revive_dt_node_interaction::EthereumNode; @@ -14,7 +15,7 @@ pub mod driver; /// /// For this we need a blockchain node implementation and a compiler. pub trait Platform { - type Blockchain: EthereumNode + Node; + type Blockchain: EthereumNode + Node + ResolverApi; type Compiler: SolidityCompiler; /// Returns the matching [TestingPlatform] of the [revive_dt_config::Arguments]. diff --git a/crates/format/Cargo.toml b/crates/format/Cargo.toml index a1f4286..f5150ac 100644 --- a/crates/format/Cargo.toml +++ b/crates/format/Cargo.toml @@ -10,7 +10,6 @@ rust-version.workspace = true [dependencies] revive-dt-common = { workspace = true } -revive-dt-node-interaction = { workspace = true } alloy = { workspace = true } alloy-primitives = { workspace = true } diff --git a/crates/format/src/input.rs b/crates/format/src/input.rs index 59f9ca5..68d491d 100644 --- a/crates/format/src/input.rs +++ b/crates/format/src/input.rs @@ -12,9 +12,9 @@ use semver::VersionReq; use serde::{Deserialize, Serialize}; use revive_dt_common::macros::define_wrapper_type; -use revive_dt_node_interaction::EthereumNode; use crate::metadata::ContractInstance; +use crate::traits::ResolverApi; #[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq)] pub struct Input { @@ -155,7 +155,7 @@ impl Calldata { pub fn calldata( &self, deployed_contracts: &HashMap, - chain_state_provider: &impl EthereumNode, + chain_state_provider: &impl ResolverApi, ) -> anyhow::Result> { let mut buffer = Vec::::with_capacity(self.size_requirement()); self.calldata_into_slice(&mut buffer, deployed_contracts, chain_state_provider)?; @@ -166,7 +166,7 @@ impl Calldata { &self, buffer: &mut Vec, deployed_contracts: &HashMap, - chain_state_provider: &impl EthereumNode, + chain_state_provider: &impl ResolverApi, ) -> anyhow::Result<()> { match self { Calldata::Single(bytes) => { @@ -201,7 +201,7 @@ impl Calldata { &self, other: &[u8], deployed_contracts: &HashMap, - chain_state_provider: &impl EthereumNode, + chain_state_provider: &impl ResolverApi, ) -> anyhow::Result { match self { Calldata::Single(calldata) => Ok(calldata == other), @@ -250,7 +250,7 @@ impl Input { pub fn encoded_input( &self, deployed_contracts: &HashMap, - chain_state_provider: &impl EthereumNode, + chain_state_provider: &impl ResolverApi, ) -> anyhow::Result { match self.method { Method::Deployer | Method::Fallback => { @@ -317,7 +317,7 @@ impl Input { pub fn legacy_transaction( &self, deployed_contracts: &HashMap, - chain_state_provider: &impl EthereumNode, + chain_state_provider: &impl ResolverApi, ) -> anyhow::Result { let input_data = self.encoded_input(deployed_contracts, chain_state_provider)?; let transaction_request = TransactionRequest::default().from(self.caller).value( @@ -364,7 +364,7 @@ pub const fn default_caller() -> Address { fn resolve_argument( value: &str, deployed_contracts: &HashMap, - chain_state_provider: &impl EthereumNode, + chain_state_provider: &impl ResolverApi, ) -> anyhow::Result { if let Some(instance) = value.strip_suffix(".address") { Ok(U256::from_be_slice( @@ -433,31 +433,9 @@ mod tests { use alloy_sol_types::SolValue; use std::collections::HashMap; - struct DummyEthereumNode; - - impl EthereumNode for DummyEthereumNode { - fn execute_transaction( - &self, - _: TransactionRequest, - ) -> anyhow::Result { - unimplemented!() - } - - fn trace_transaction( - &self, - _: &alloy::rpc::types::TransactionReceipt, - _: alloy::rpc::types::trace::geth::GethDebugTracingOptions, - ) -> anyhow::Result { - unimplemented!() - } - - fn state_diff( - &self, - _: &alloy::rpc::types::TransactionReceipt, - ) -> anyhow::Result { - unimplemented!() - } + struct MockResolver; + impl ResolverApi for MockResolver { fn chain_id(&self) -> anyhow::Result { Ok(0x123) } @@ -529,7 +507,7 @@ mod tests { (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)); type T = (u64,); @@ -573,7 +551,7 @@ mod tests { (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)); type T = (alloy_primitives::Address,); @@ -620,7 +598,7 @@ mod tests { (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)); type T = (alloy_primitives::Address,); @@ -637,11 +615,11 @@ mod tests { let input = "$CHAIN_ID"; // Act - let resolved = resolve_argument(input, &Default::default(), &DummyEthereumNode); + let resolved = resolve_argument(input, &Default::default(), &MockResolver); // Assert 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] @@ -650,17 +628,13 @@ mod tests { let input = "$GAS_LIMIT"; // Act - let resolved = resolve_argument(input, &Default::default(), &DummyEthereumNode); + let resolved = resolve_argument(input, &Default::default(), &MockResolver); // Assert let resolved = resolved.expect("Failed to resolve argument"); assert_eq!( resolved, - U256::from( - DummyEthereumNode - .block_gas_limit(Default::default()) - .unwrap() - ) + U256::from(MockResolver.block_gas_limit(Default::default()).unwrap()) ) } @@ -670,14 +644,14 @@ mod tests { let input = "$COINBASE"; // Act - let resolved = resolve_argument(input, &Default::default(), &DummyEthereumNode); + let resolved = resolve_argument(input, &Default::default(), &MockResolver); // Assert let resolved = resolved.expect("Failed to resolve argument"); assert_eq!( resolved, U256::from_be_slice( - DummyEthereumNode + MockResolver .block_coinbase(Default::default()) .unwrap() .as_ref() @@ -691,15 +665,13 @@ mod tests { let input = "$DIFFICULTY"; // Act - let resolved = resolve_argument(input, &Default::default(), &DummyEthereumNode); + let resolved = resolve_argument(input, &Default::default(), &MockResolver); // Assert let resolved = resolved.expect("Failed to resolve argument"); assert_eq!( resolved, - DummyEthereumNode - .block_difficulty(Default::default()) - .unwrap() + MockResolver.block_difficulty(Default::default()).unwrap() ) } @@ -709,13 +681,13 @@ mod tests { let input = "$BLOCK_HASH"; // Act - let resolved = resolve_argument(input, &Default::default(), &DummyEthereumNode); + let resolved = resolve_argument(input, &Default::default(), &MockResolver); // Assert let resolved = resolved.expect("Failed to resolve argument"); assert_eq!( resolved, - U256::from_be_bytes(DummyEthereumNode.block_hash(Default::default()).unwrap().0) + U256::from_be_bytes(MockResolver.block_hash(Default::default()).unwrap().0) ) } @@ -725,13 +697,13 @@ mod tests { let input = "$BLOCK_NUMBER"; // Act - let resolved = resolve_argument(input, &Default::default(), &DummyEthereumNode); + let resolved = resolve_argument(input, &Default::default(), &MockResolver); // Assert let resolved = resolved.expect("Failed to resolve argument"); assert_eq!( resolved, - U256::from(DummyEthereumNode.last_block_number().unwrap()) + U256::from(MockResolver.last_block_number().unwrap()) ) } @@ -741,17 +713,13 @@ mod tests { let input = "$BLOCK_TIMESTAMP"; // Act - let resolved = resolve_argument(input, &Default::default(), &DummyEthereumNode); + let resolved = resolve_argument(input, &Default::default(), &MockResolver); // Assert let resolved = resolved.expect("Failed to resolve argument"); assert_eq!( resolved, - U256::from( - DummyEthereumNode - .block_timestamp(Default::default()) - .unwrap() - ) + U256::from(MockResolver.block_timestamp(Default::default()).unwrap()) ) } } diff --git a/crates/format/src/lib.rs b/crates/format/src/lib.rs index 21ae375..8ef7301 100644 --- a/crates/format/src/lib.rs +++ b/crates/format/src/lib.rs @@ -5,3 +5,4 @@ pub mod corpus; pub mod input; pub mod metadata; pub mod mode; +pub mod traits; diff --git a/crates/format/src/traits.rs b/crates/format/src/traits.rs new file mode 100644 index 0000000..c22f24a --- /dev/null +++ b/crates/format/src/traits.rs @@ -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; + + // 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; + + /// Returns the coinbase of the specified block. + fn block_coinbase(&self, number: BlockNumberOrTag) -> Result
; + + /// Returns the difficulty of the specified block. + fn block_difficulty(&self, number: BlockNumberOrTag) -> Result; + + /// Returns the hash of the specified block. + fn block_hash(&self, number: BlockNumberOrTag) -> Result; + + /// Returns the timestamp of the specified block, + fn block_timestamp(&self, number: BlockNumberOrTag) -> Result; + + /// Returns the number of the last block. + fn last_block_number(&self) -> Result; +} diff --git a/crates/node-interaction/src/lib.rs b/crates/node-interaction/src/lib.rs index bf7bcf4..130d804 100644 --- a/crates/node-interaction/src/lib.rs +++ b/crates/node-interaction/src/lib.rs @@ -1,7 +1,5 @@ //! 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::{TransactionReceipt, TransactionRequest}; use anyhow::Result; @@ -20,27 +18,4 @@ pub trait EthereumNode { /// Returns the state diff of the transaction hash in the [TransactionReceipt]. fn state_diff(&self, receipt: &TransactionReceipt) -> Result; - - /// Returns the ID of the chain that the node is on. - fn chain_id(&self) -> Result; - - // 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; - - /// Returns the coinbase of the specified block. - fn block_coinbase(&self, number: BlockNumberOrTag) -> Result
; - - /// Returns the difficulty of the specified block. - fn block_difficulty(&self, number: BlockNumberOrTag) -> Result; - - /// Returns the hash of the specified block. - fn block_hash(&self, number: BlockNumberOrTag) -> Result; - - /// Returns the timestamp of the specified block, - fn block_timestamp(&self, number: BlockNumberOrTag) -> Result; - - /// Returns the number of the last block. - fn last_block_number(&self) -> Result; } diff --git a/crates/node/Cargo.toml b/crates/node/Cargo.toml index bbb9e80..a930312 100644 --- a/crates/node/Cargo.toml +++ b/crates/node/Cargo.toml @@ -14,9 +14,10 @@ alloy = { workspace = true } tracing = { workspace = true } tokio = { workspace = true } -revive-dt-node-interaction = { workspace = true } revive-dt-common = { workspace = true } revive-dt-config = { workspace = true } +revive-dt-format = { workspace = true } +revive-dt-node-interaction = { workspace = true } serde = { workspace = true } serde_json = { workspace = true } diff --git a/crates/node/src/geth.rs b/crates/node/src/geth.rs index c37fb04..7679171 100644 --- a/crates/node/src/geth.rs +++ b/crates/node/src/geth.rs @@ -27,6 +27,7 @@ use alloy::{ }; use revive_dt_common::concepts::BlockingExecutor; use revive_dt_config::Arguments; +use revive_dt_format::traits::ResolverApi; use revive_dt_node_interaction::EthereumNode; use tracing::Level; @@ -344,7 +345,9 @@ impl EthereumNode for Instance { _ => anyhow::bail!("expected a diff mode trace"), } } +} +impl ResolverApi for Instance { #[tracing::instrument(skip_all, fields(geth_node_id = self.id))] fn chain_id(&self) -> anyhow::Result { let provider = self.provider(); diff --git a/crates/node/src/kitchensink.rs b/crates/node/src/kitchensink.rs index bc198a1..ff9d652 100644 --- a/crates/node/src/kitchensink.rs +++ b/crates/node/src/kitchensink.rs @@ -30,6 +30,7 @@ use alloy::{ }, signers::local::PrivateKeySigner, }; +use revive_dt_format::traits::ResolverApi; use serde::{Deserialize, Serialize}; use serde_json::{Value as JsonValue, json}; use sp_core::crypto::Ss58Codec; @@ -425,7 +426,9 @@ impl EthereumNode for KitchensinkNode { _ => anyhow::bail!("expected a diff mode trace"), } } +} +impl ResolverApi for KitchensinkNode { #[tracing::instrument(skip_all, fields(geth_node_id = self.id))] fn chain_id(&self) -> anyhow::Result { let provider = self.provider();