mirror of
https://github.com/pezkuwichain/revive-differential-tests.git
synced 2026-06-15 17:11:03 +00:00
Add support for wildcards in exceptions
This commit is contained in:
@@ -5,7 +5,6 @@ use std::marker::PhantomData;
|
|||||||
|
|
||||||
use alloy::json_abi::JsonAbi;
|
use alloy::json_abi::JsonAbi;
|
||||||
use alloy::network::{Ethereum, TransactionBuilder};
|
use alloy::network::{Ethereum, TransactionBuilder};
|
||||||
use alloy::primitives::Bytes;
|
|
||||||
use alloy::rpc::types::TransactionReceipt;
|
use alloy::rpc::types::TransactionReceipt;
|
||||||
use alloy::rpc::types::trace::geth::{
|
use alloy::rpc::types::trace::geth::{
|
||||||
DefaultFrame, GethDebugTracingOptions, GethDefaultTracingOptions, GethTrace, PreStateConfig,
|
DefaultFrame, GethDebugTracingOptions, GethDefaultTracingOptions, GethTrace, PreStateConfig,
|
||||||
@@ -437,6 +436,9 @@ where
|
|||||||
// Additionally, what happens if the compiler filter doesn't match? Do we consider that the
|
// Additionally, what happens if the compiler filter doesn't match? Do we consider that the
|
||||||
// transaction should succeed? Do we just ignore the expectation?
|
// transaction should succeed? Do we just ignore the expectation?
|
||||||
|
|
||||||
|
let deployed_contracts = self.deployed_contracts.entry(case_idx).or_default();
|
||||||
|
let chain_state_provider = node;
|
||||||
|
|
||||||
// Handling the receipt state assertion.
|
// Handling the receipt state assertion.
|
||||||
let expected = !expectation.exception;
|
let expected = !expectation.exception;
|
||||||
let actual = execution_receipt.status();
|
let actual = execution_receipt.status();
|
||||||
@@ -454,13 +456,16 @@ where
|
|||||||
|
|
||||||
// Handling the calldata assertion
|
// Handling the calldata assertion
|
||||||
if let Some(ref expected_calldata) = expectation.return_data {
|
if let Some(ref expected_calldata) = expectation.return_data {
|
||||||
let expected = expected_calldata
|
let expected = expected_calldata;
|
||||||
.calldata(self.deployed_contracts.entry(case_idx).or_default(), node)
|
let actual = &tracing_result.return_value;
|
||||||
.map(Bytes::from)?;
|
if !expected.is_equivalent(actual, deployed_contracts, chain_state_provider)? {
|
||||||
let actual = tracing_result.return_value.clone();
|
tracing::error!(
|
||||||
if !expected.starts_with(&actual) {
|
?execution_receipt,
|
||||||
tracing::error!(?execution_receipt, %expected, %actual, "Calldata assertion failed");
|
?expected,
|
||||||
anyhow::bail!("Calldata assertion failed - Expected {expected} but got {actual}",);
|
%actual,
|
||||||
|
"Calldata assertion failed"
|
||||||
|
);
|
||||||
|
anyhow::bail!("Calldata assertion failed - Expected {expected:?} but got {actual}",);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -503,27 +508,34 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Handling the topics assertion.
|
// Handling the topics assertion.
|
||||||
let expected = expected_event.topics.as_slice();
|
for (expected, actual) in expected_event
|
||||||
let actual = actual_event.topics();
|
.topics
|
||||||
if actual != expected {
|
.as_slice()
|
||||||
tracing::error!(
|
.iter()
|
||||||
?execution_receipt,
|
.zip(actual_event.topics())
|
||||||
?expected,
|
{
|
||||||
?actual,
|
let expected = Calldata::Compound(vec![expected.clone()]);
|
||||||
"Event topics assertion failed",
|
if !expected.is_equivalent(
|
||||||
);
|
&actual.0,
|
||||||
anyhow::bail!(
|
deployed_contracts,
|
||||||
"Event topics assertion failed - Expected {expected:?} but got {actual:?}",
|
chain_state_provider,
|
||||||
);
|
)? {
|
||||||
|
tracing::error!(
|
||||||
|
?execution_receipt,
|
||||||
|
?expected,
|
||||||
|
?actual,
|
||||||
|
"Event topics assertion failed",
|
||||||
|
);
|
||||||
|
anyhow::bail!(
|
||||||
|
"Event topics assertion failed - Expected {expected:?} but got {actual:?}",
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handling the values assertion.
|
// Handling the values assertion.
|
||||||
let expected = &expected_event
|
let expected = &expected_event.values;
|
||||||
.values
|
|
||||||
.calldata(self.deployed_contracts.entry(case_idx).or_default(), node)
|
|
||||||
.map(Bytes::from)?;
|
|
||||||
let actual = &actual_event.data().data;
|
let actual = &actual_event.data().data;
|
||||||
if !expected.starts_with(actual) {
|
if !expected.is_equivalent(&actual.0, deployed_contracts, chain_state_provider)? {
|
||||||
tracing::error!(
|
tracing::error!(
|
||||||
?execution_receipt,
|
?execution_receipt,
|
||||||
?expected,
|
?expected,
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ use alloy::{
|
|||||||
primitives::{Address, Bytes, U256},
|
primitives::{Address, Bytes, U256},
|
||||||
rpc::types::TransactionRequest,
|
rpc::types::TransactionRequest,
|
||||||
};
|
};
|
||||||
use alloy_primitives::B256;
|
|
||||||
use semver::VersionReq;
|
use semver::VersionReq;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
|
||||||
@@ -50,14 +49,14 @@ pub struct ExpectedOutput {
|
|||||||
#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq)]
|
#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq)]
|
||||||
pub struct Event {
|
pub struct Event {
|
||||||
pub address: Option<Address>,
|
pub address: Option<Address>,
|
||||||
pub topics: Vec<B256>,
|
pub topics: Vec<String>,
|
||||||
pub values: Calldata,
|
pub values: Calldata,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Deserialize, Eq, PartialEq)]
|
#[derive(Clone, Debug, Deserialize, Eq, PartialEq)]
|
||||||
#[serde(untagged)]
|
#[serde(untagged)]
|
||||||
pub enum Calldata {
|
pub enum Calldata {
|
||||||
Single(String),
|
Single(Bytes),
|
||||||
Compound(Vec<String>),
|
Compound(Vec<String>),
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -159,14 +158,40 @@ impl Calldata {
|
|||||||
|
|
||||||
pub fn size_requirement(&self) -> usize {
|
pub fn size_requirement(&self) -> usize {
|
||||||
match self {
|
match self {
|
||||||
Calldata::Single(single) => single
|
Calldata::Single(single) => single.len(),
|
||||||
.len()
|
|
||||||
.checked_sub(2)
|
|
||||||
.and_then(|value| value.checked_div(2))
|
|
||||||
.unwrap_or_default(),
|
|
||||||
Calldata::Compound(items) => items.len() * 32,
|
Calldata::Compound(items) => items.len() * 32,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Checks if this [`Calldata`] is equivalent to the passed calldata bytes.
|
||||||
|
pub fn is_equivalent(
|
||||||
|
&self,
|
||||||
|
other: &[u8],
|
||||||
|
deployed_contracts: &HashMap<ContractInstance, (Address, JsonAbi)>,
|
||||||
|
chain_state_provider: &impl EthereumNode,
|
||||||
|
) -> anyhow::Result<bool> {
|
||||||
|
match self {
|
||||||
|
Calldata::Single(calldata) => Ok(calldata == other),
|
||||||
|
Calldata::Compound(items) => {
|
||||||
|
// Chunking the "other" calldata into 32 byte chunks since each
|
||||||
|
// one of the items in the compound calldata represents 32 bytes
|
||||||
|
for (this, other) in items.iter().zip(other.chunks(32)) {
|
||||||
|
// The matterlabs format supports wildcards and therefore we
|
||||||
|
// also need to support them.
|
||||||
|
if this == "*" {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let this = resolve_argument(this, deployed_contracts, chain_state_provider)?;
|
||||||
|
let other = U256::from_be_slice(other);
|
||||||
|
if this != other {
|
||||||
|
return Ok(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Input {
|
impl Input {
|
||||||
|
|||||||
Reference in New Issue
Block a user