mirror of
https://github.com/pezkuwichain/revive-differential-tests.git
synced 2026-06-20 05:41:04 +00:00
Parsed ABI field in order to get method parameter
This commit is contained in:
@@ -27,4 +27,5 @@ log = { workspace = true }
|
|||||||
env_logger = { workspace = true }
|
env_logger = { workspace = true }
|
||||||
rayon = { workspace = true }
|
rayon = { workspace = true }
|
||||||
revive-solc-json-interface = { workspace = true }
|
revive-solc-json-interface = { workspace = true }
|
||||||
|
serde_json = { workspace = true }
|
||||||
temp-dir = { workspace = true }
|
temp-dir = { workspace = true }
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
//! 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::json_abi::JsonAbi;
|
||||||
use alloy::primitives::Bytes;
|
use alloy::primitives::Bytes;
|
||||||
use alloy::rpc::types::TransactionInput;
|
use alloy::rpc::types::TransactionInput;
|
||||||
use alloy::{
|
use alloy::{
|
||||||
primitives::{Address, TxKind, map::HashMap},
|
primitives::{Address, TxKind, map::HashMap},
|
||||||
rpc::types::{
|
rpc::types::{
|
||||||
TransactionReceipt, TransactionRequest,
|
TransactionRequest,
|
||||||
trace::geth::{AccountState, DiffMode, GethTrace},
|
trace::geth::{AccountState, DiffMode},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use revive_dt_compiler::{Compiler, CompilerInput, SolidityCompiler};
|
use revive_dt_compiler::{Compiler, CompilerInput, SolidityCompiler};
|
||||||
@@ -15,6 +16,7 @@ use revive_dt_format::{input::Input, metadata::Metadata, mode::SolcMode};
|
|||||||
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 crate::Platform;
|
use crate::Platform;
|
||||||
|
|
||||||
@@ -28,6 +30,7 @@ pub struct State<'a, T: Platform> {
|
|||||||
span: Span,
|
span: Span,
|
||||||
contracts: Contracts<T>,
|
contracts: Contracts<T>,
|
||||||
deployed_contracts: HashMap<String, Address>,
|
deployed_contracts: HashMap<String, Address>,
|
||||||
|
deployed_abis: HashMap<String, JsonAbi>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T> State<'a, T>
|
impl<'a, T> State<'a, T>
|
||||||
@@ -40,6 +43,7 @@ where
|
|||||||
span,
|
span,
|
||||||
contracts: Default::default(),
|
contracts: Default::default(),
|
||||||
deployed_contracts: Default::default(),
|
deployed_contracts: Default::default(),
|
||||||
|
deployed_abis: Default::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -126,15 +130,21 @@ where
|
|||||||
std::any::type_name::<T>()
|
std::any::type_name::<T>()
|
||||||
);
|
);
|
||||||
|
|
||||||
let tx =
|
let tx = match input.legacy_transaction(
|
||||||
match input.legacy_transaction(self.config.network_id, nonce, &self.deployed_contracts)
|
self.config.network_id,
|
||||||
{
|
nonce,
|
||||||
Ok(tx) => tx,
|
&self.deployed_contracts,
|
||||||
Err(err) => {
|
&self.deployed_abis,
|
||||||
log::error!("Failed to construct legacy transaction: {err:?}");
|
) {
|
||||||
return Err(err);
|
Ok(tx) => {
|
||||||
}
|
log::debug!("Legacy transaction data: {:#?}", tx);
|
||||||
};
|
tx
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
log::error!("Failed to construct legacy transaction: {err:?}");
|
||||||
|
return Err(err);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
log::trace!("Executing transaction for input: {input:?}");
|
log::trace!("Executing transaction for input: {input:?}");
|
||||||
|
|
||||||
@@ -191,9 +201,6 @@ where
|
|||||||
&contract_name,
|
&contract_name,
|
||||||
&input.instance
|
&input.instance
|
||||||
);
|
);
|
||||||
if contract_name != &input.instance {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
let bytecode = contract
|
let bytecode = contract
|
||||||
.evm
|
.evm
|
||||||
@@ -270,6 +277,54 @@ where
|
|||||||
address,
|
address,
|
||||||
std::any::type_name::<T>()
|
std::any::type_name::<T>()
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if let Some(Value::String(metadata_json_str)) = &contract.metadata {
|
||||||
|
log::trace!(
|
||||||
|
"metadata found for contract {}, {}",
|
||||||
|
contract_name,
|
||||||
|
metadata_json_str
|
||||||
|
);
|
||||||
|
|
||||||
|
match serde_json::from_str::<serde_json::Value>(metadata_json_str) {
|
||||||
|
Ok(metadata_json) => {
|
||||||
|
if let Some(abi_value) =
|
||||||
|
metadata_json.get("output").and_then(|o| o.get("abi"))
|
||||||
|
{
|
||||||
|
match serde_json::from_value::<JsonAbi>(abi_value.clone()) {
|
||||||
|
Ok(parsed_abi) => {
|
||||||
|
log::trace!(
|
||||||
|
"ABI found in metadata for contract {}",
|
||||||
|
&contract_name
|
||||||
|
);
|
||||||
|
self.deployed_abis
|
||||||
|
.insert(contract_name.clone(), parsed_abi);
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
log::debug!(
|
||||||
|
"Failed to parse ABI from metadata for {}: {}",
|
||||||
|
contract_name,
|
||||||
|
err
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log::debug!(
|
||||||
|
"No ABI found in metadata for contract {}",
|
||||||
|
contract_name
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
log::debug!(
|
||||||
|
"Failed to parse metadata JSON string for contract {}: {}",
|
||||||
|
contract_name,
|
||||||
|
err
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log::debug!("No metadata found for contract {}", contract_name);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use alloy::{
|
use alloy::{
|
||||||
json_abi::Function,
|
hex,
|
||||||
primitives::{Address, TxKind},
|
json_abi::{Function, JsonAbi},
|
||||||
rpc::types::TransactionRequest,
|
primitives::{Address, Bytes, TxKind},
|
||||||
|
rpc::types::{TransactionInput, TransactionRequest},
|
||||||
};
|
};
|
||||||
use semver::VersionReq;
|
use semver::VersionReq;
|
||||||
use serde::{Deserialize, de::Deserializer};
|
use serde::{Deserialize, de::Deserializer};
|
||||||
@@ -44,7 +45,14 @@ pub struct ExpectedOutput {
|
|||||||
#[serde(untagged)]
|
#[serde(untagged)]
|
||||||
pub enum Calldata {
|
pub enum Calldata {
|
||||||
Single(String),
|
Single(String),
|
||||||
Compound(Vec<String>),
|
Compound(Vec<CalldataArg>),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, Deserialize, Eq, PartialEq)]
|
||||||
|
#[serde(untagged)]
|
||||||
|
pub enum CalldataArg {
|
||||||
|
Literal(String),
|
||||||
|
AddressRef(String), // will be "Contract.address"
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Specify how the contract is called.
|
/// Specify how the contract is called.
|
||||||
@@ -102,12 +110,77 @@ impl Input {
|
|||||||
.ok_or_else(|| anyhow::anyhow!("instance {instance} not deployed"))
|
.ok_or_else(|| anyhow::anyhow!("instance {instance} not deployed"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn encoded_input(
|
||||||
|
&self,
|
||||||
|
deployed_abis: &HashMap<String, JsonAbi>,
|
||||||
|
deployed_contracts: &HashMap<String, Address>,
|
||||||
|
) -> anyhow::Result<Bytes> {
|
||||||
|
let Method::Function(selector) = self.method else {
|
||||||
|
return Ok(Bytes::default()); // fallback or deployer — no input
|
||||||
|
};
|
||||||
|
|
||||||
|
// ABI
|
||||||
|
let abi = deployed_abis
|
||||||
|
.get(&self.instance)
|
||||||
|
.ok_or_else(|| anyhow::anyhow!("ABI for instance '{}' not found", &self.instance))?;
|
||||||
|
|
||||||
|
// Find function by selector
|
||||||
|
let function = abi
|
||||||
|
.functions()
|
||||||
|
.find(|f| f.selector().0 == selector)
|
||||||
|
.ok_or_else(|| {
|
||||||
|
anyhow::anyhow!(
|
||||||
|
"Function with selector {:?} not found in ABI for the instance {:?}",
|
||||||
|
selector,
|
||||||
|
&self.instance
|
||||||
|
)
|
||||||
|
})?;
|
||||||
|
|
||||||
|
// Parse calldata
|
||||||
|
let calldata_args = match &self.calldata {
|
||||||
|
Some(Calldata::Compound(args)) => args,
|
||||||
|
_ => anyhow::bail!("Expected compound calldata for function call"),
|
||||||
|
};
|
||||||
|
|
||||||
|
// Convert each argument
|
||||||
|
let mut tokens = Vec::new();
|
||||||
|
for (i, param) in function.inputs.iter().enumerate() {
|
||||||
|
let arg = calldata_args
|
||||||
|
.get(i)
|
||||||
|
.ok_or_else(|| anyhow::anyhow!("Missing calldata argument {}", i))?;
|
||||||
|
let token = match arg {
|
||||||
|
CalldataArg::Literal(value) => match param.ty.to_string().as_str() {
|
||||||
|
"uint256" | "uint" => Token::Uint(value.parse()?),
|
||||||
|
"address" => Token::Address(value.parse()?),
|
||||||
|
_ => anyhow::bail!("Unsupported literal type {}", param.ty),
|
||||||
|
},
|
||||||
|
CalldataArg::AddressRef(name) => {
|
||||||
|
let addr = if name.ends_with(".address") {
|
||||||
|
let contract_name = name.trim_end_matches(".address");
|
||||||
|
deployed_contracts.get(contract_name).copied()
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
Token::Address(
|
||||||
|
addr.ok_or_else(|| anyhow::anyhow!("Address for '{}' not found", name))?,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
tokens.push(token);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Encode
|
||||||
|
let encoded = function.encode_input(&tokens)?;
|
||||||
|
Ok(Bytes::from(encoded))
|
||||||
|
}
|
||||||
|
|
||||||
/// Parse this input into a legacy transaction.
|
/// Parse this input into a legacy transaction.
|
||||||
pub fn legacy_transaction(
|
pub fn legacy_transaction(
|
||||||
&self,
|
&self,
|
||||||
chain_id: u64,
|
chain_id: u64,
|
||||||
nonce: u64,
|
nonce: u64,
|
||||||
deployed_contracts: &HashMap<String, Address>,
|
deployed_contracts: &HashMap<String, Address>,
|
||||||
|
deployed_abis: &HashMap<String, JsonAbi>,
|
||||||
) -> anyhow::Result<TransactionRequest> {
|
) -> anyhow::Result<TransactionRequest> {
|
||||||
let to = match self.method {
|
let to = match self.method {
|
||||||
Method::Deployer => Some(TxKind::Create),
|
Method::Deployer => Some(TxKind::Create),
|
||||||
@@ -116,6 +189,8 @@ impl Input {
|
|||||||
)),
|
)),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let input_data = self.encoded_input(deployed_abis, deployed_contracts)?;
|
||||||
|
|
||||||
Ok(TransactionRequest {
|
Ok(TransactionRequest {
|
||||||
from: Some(self.caller),
|
from: Some(self.caller),
|
||||||
to,
|
to,
|
||||||
@@ -123,6 +198,7 @@ impl Input {
|
|||||||
chain_id: Some(chain_id),
|
chain_id: Some(chain_id),
|
||||||
gas_price: Some(5_000_000),
|
gas_price: Some(5_000_000),
|
||||||
gas: Some(5_000_000),
|
gas: Some(5_000_000),
|
||||||
|
input: TransactionInput::new(input_data),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user