mirror of
https://github.com/pezkuwichain/revive-differential-tests.git
synced 2026-04-28 10:47:59 +00:00
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.
This commit is contained in:
Generated
+1
-1
@@ -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",
|
||||
|
||||
@@ -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].
|
||||
|
||||
@@ -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 }
|
||||
|
||||
+26
-58
@@ -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<ContractInstance, (Address, JsonAbi)>,
|
||||
chain_state_provider: &impl EthereumNode,
|
||||
chain_state_provider: &impl ResolverApi,
|
||||
) -> anyhow::Result<Vec<u8>> {
|
||||
let mut buffer = Vec::<u8>::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<u8>,
|
||||
deployed_contracts: &HashMap<ContractInstance, (Address, JsonAbi)>,
|
||||
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<ContractInstance, (Address, JsonAbi)>,
|
||||
chain_state_provider: &impl EthereumNode,
|
||||
chain_state_provider: &impl ResolverApi,
|
||||
) -> anyhow::Result<bool> {
|
||||
match self {
|
||||
Calldata::Single(calldata) => Ok(calldata == other),
|
||||
@@ -250,7 +250,7 @@ impl Input {
|
||||
pub fn encoded_input(
|
||||
&self,
|
||||
deployed_contracts: &HashMap<ContractInstance, (Address, JsonAbi)>,
|
||||
chain_state_provider: &impl EthereumNode,
|
||||
chain_state_provider: &impl ResolverApi,
|
||||
) -> anyhow::Result<Bytes> {
|
||||
match self.method {
|
||||
Method::Deployer | Method::Fallback => {
|
||||
@@ -317,7 +317,7 @@ impl Input {
|
||||
pub fn legacy_transaction(
|
||||
&self,
|
||||
deployed_contracts: &HashMap<ContractInstance, (Address, JsonAbi)>,
|
||||
chain_state_provider: &impl EthereumNode,
|
||||
chain_state_provider: &impl ResolverApi,
|
||||
) -> anyhow::Result<TransactionRequest> {
|
||||
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<ContractInstance, (Address, JsonAbi)>,
|
||||
chain_state_provider: &impl EthereumNode,
|
||||
chain_state_provider: &impl ResolverApi,
|
||||
) -> anyhow::Result<U256> {
|
||||
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<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!()
|
||||
}
|
||||
struct MockResolver;
|
||||
|
||||
impl ResolverApi for MockResolver {
|
||||
fn chain_id(&self) -> anyhow::Result<alloy_primitives::ChainId> {
|
||||
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())
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,3 +5,4 @@ pub mod corpus;
|
||||
pub mod input;
|
||||
pub mod metadata;
|
||||
pub mod mode;
|
||||
pub mod traits;
|
||||
|
||||
@@ -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>;
|
||||
}
|
||||
@@ -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<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>;
|
||||
}
|
||||
|
||||
@@ -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 }
|
||||
|
||||
@@ -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<alloy::primitives::ChainId> {
|
||||
let provider = self.provider();
|
||||
|
||||
@@ -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<alloy::primitives::ChainId> {
|
||||
let provider = self.provider();
|
||||
|
||||
Reference in New Issue
Block a user