mirror of
https://github.com/pezkuwichain/revive-differential-tests.git
synced 2026-04-22 11:27:59 +00:00
Compare commits
13 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| edbbbab934 | |||
| 757cbaf61e | |||
| 2c7e95bb4f | |||
| 2b6ee18e40 | |||
| ca1ce3e5b4 | |||
| 3d28179dde | |||
| 6303f3b917 | |||
| e434c163c7 | |||
| 404d2f7452 | |||
| 750d9fff27 | |||
| 94afdbecc7 | |||
| ce1b4862b4 | |||
| 799f07f04f |
@@ -76,7 +76,7 @@ pub struct Arguments {
|
|||||||
/// This argument controls which private keys the nodes should have access to and be added to
|
/// This argument controls which private keys the nodes should have access to and be added to
|
||||||
/// its wallet signers. With a value of N, private keys (0, N] will be added to the signer set
|
/// its wallet signers. With a value of N, private keys (0, N] will be added to the signer set
|
||||||
/// of the node.
|
/// of the node.
|
||||||
#[arg(short, long = "private-keys-count", default_value_t = 30)]
|
#[arg(long = "private-keys-count", default_value_t = 30)]
|
||||||
pub private_keys_to_add: usize,
|
pub private_keys_to_add: usize,
|
||||||
|
|
||||||
/// The differential testing leader node implementation.
|
/// The differential testing leader node implementation.
|
||||||
|
|||||||
@@ -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::{
|
||||||
CallFrame, GethDebugBuiltInTracerType, GethDebugTracerType, GethDebugTracingOptions, GethTrace,
|
CallFrame, GethDebugBuiltInTracerType, GethDebugTracerType, GethDebugTracingOptions, GethTrace,
|
||||||
@@ -442,9 +441,8 @@ 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 error_span =
|
let deployed_contracts = self.deployed_contracts.entry(case_idx).or_default();
|
||||||
tracing::error_span!("Exception failed", ?tracing_result, ?execution_receipt,);
|
let chain_state_provider = node;
|
||||||
let _guard = error_span.enter();
|
|
||||||
|
|
||||||
// Handling the receipt state assertion.
|
// Handling the receipt state assertion.
|
||||||
let expected = !expectation.exception;
|
let expected = !expectation.exception;
|
||||||
@@ -458,17 +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.output.as_ref().unwrap_or_default();
|
||||||
.map(Bytes::from)?;
|
if !expected.is_equivalent(actual, deployed_contracts, chain_state_provider)? {
|
||||||
let actual = tracing_result.output.clone().unwrap_or_default();
|
|
||||||
if !expected.starts_with(&actual) {
|
|
||||||
tracing::error!(
|
tracing::error!(
|
||||||
%expected,
|
?execution_receipt,
|
||||||
|
?expected,
|
||||||
%actual,
|
%actual,
|
||||||
"Calldata assertion failed"
|
"Calldata assertion failed"
|
||||||
);
|
);
|
||||||
anyhow::bail!("Calldata assertion failed - Expected {expected} but got {actual}",);
|
anyhow::bail!("Calldata assertion failed - Expected {expected:?} but got {actual}",);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -505,17 +502,24 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Handling the topics assertion.
|
// Handling the topics assertion.
|
||||||
for (expected_topic, actual_topic) in expected_event
|
for (expected, actual) in expected_event
|
||||||
.topics
|
.topics
|
||||||
.as_slice()
|
.as_slice()
|
||||||
.iter()
|
.iter()
|
||||||
.zip(actual_event.topics())
|
.zip(actual_event.topics())
|
||||||
{
|
{
|
||||||
let expected = Calldata::Compound(vec![expected_topic.clone()])
|
let expected = Calldata::Compound(vec![expected.clone()]);
|
||||||
.calldata(self.deployed_contracts.entry(case_idx).or_default(), node)?;
|
if !expected.is_equivalent(
|
||||||
let actual = actual_topic.to_vec();
|
&actual.0,
|
||||||
if actual != expected {
|
deployed_contracts,
|
||||||
tracing::error!(?expected, ?actual, "Event topics assertion failed",);
|
chain_state_provider,
|
||||||
|
)? {
|
||||||
|
tracing::error!(
|
||||||
|
?execution_receipt,
|
||||||
|
?expected,
|
||||||
|
?actual,
|
||||||
|
"Event topics assertion failed",
|
||||||
|
);
|
||||||
anyhow::bail!(
|
anyhow::bail!(
|
||||||
"Event topics assertion failed - Expected {expected:?} but got {actual:?}",
|
"Event topics assertion failed - Expected {expected:?} but got {actual:?}",
|
||||||
);
|
);
|
||||||
@@ -523,13 +527,15 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 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!(?expected, ?actual, "Event value assertion failed",);
|
tracing::error!(
|
||||||
|
?execution_receipt,
|
||||||
|
?expected,
|
||||||
|
?actual,
|
||||||
|
"Event value assertion failed",
|
||||||
|
);
|
||||||
anyhow::bail!(
|
anyhow::bail!(
|
||||||
"Event value assertion failed - Expected {expected:?} but got {actual:?}",
|
"Event value assertion failed - Expected {expected:?} but got {actual:?}",
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ pub struct Event {
|
|||||||
#[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>),
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -168,8 +168,8 @@ impl Calldata {
|
|||||||
chain_state_provider: &impl EthereumNode,
|
chain_state_provider: &impl EthereumNode,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
match self {
|
match self {
|
||||||
Calldata::Single(string) => {
|
Calldata::Single(bytes) => {
|
||||||
alloy::hex::decode_to_slice(string, buffer)?;
|
buffer.extend_from_slice(bytes);
|
||||||
}
|
}
|
||||||
Calldata::Compound(items) => {
|
Calldata::Compound(items) => {
|
||||||
for (arg_idx, arg) in items.iter().enumerate() {
|
for (arg_idx, arg) in items.iter().enumerate() {
|
||||||
@@ -190,10 +190,48 @@ impl Calldata {
|
|||||||
|
|
||||||
pub fn size_requirement(&self) -> usize {
|
pub fn size_requirement(&self) -> usize {
|
||||||
match self {
|
match self {
|
||||||
Calldata::Single(single) => (single.len() - 2) / 2,
|
Calldata::Single(single) => single.len(),
|
||||||
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 other = if other.len() < 32 {
|
||||||
|
let mut vec = other.to_vec();
|
||||||
|
vec.resize(32, 0);
|
||||||
|
std::borrow::Cow::Owned(vec)
|
||||||
|
} else {
|
||||||
|
std::borrow::Cow::Borrowed(other)
|
||||||
|
};
|
||||||
|
|
||||||
|
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 {
|
||||||
|
|||||||
@@ -0,0 +1,5 @@
|
|||||||
|
/// This constant defines how much Wei accounts are pre-seeded with in genesis.
|
||||||
|
///
|
||||||
|
/// We use [`u128::MAX`] here which means that accounts will be given 2^128 - 1 WEI which is
|
||||||
|
/// (2^128 - 1) / 10^18 ETH.
|
||||||
|
pub const INITIAL_BALANCE: u128 = u128::MAX;
|
||||||
@@ -29,7 +29,7 @@ use revive_dt_config::Arguments;
|
|||||||
use revive_dt_node_interaction::{BlockingExecutor, EthereumNode};
|
use revive_dt_node_interaction::{BlockingExecutor, EthereumNode};
|
||||||
use tracing::Level;
|
use tracing::Level;
|
||||||
|
|
||||||
use crate::{Node, common::FallbackGasFiller};
|
use crate::{Node, common::FallbackGasFiller, constants::INITIAL_BALANCE};
|
||||||
|
|
||||||
static NODE_COUNT: AtomicU32 = AtomicU32::new(0);
|
static NODE_COUNT: AtomicU32 = AtomicU32::new(0);
|
||||||
|
|
||||||
@@ -84,10 +84,10 @@ impl Instance {
|
|||||||
for signer_address in
|
for signer_address in
|
||||||
<EthereumWallet as NetworkWallet<Ethereum>>::signer_addresses(&self.wallet)
|
<EthereumWallet as NetworkWallet<Ethereum>>::signer_addresses(&self.wallet)
|
||||||
{
|
{
|
||||||
genesis.alloc.entry(signer_address).or_insert(
|
genesis
|
||||||
GenesisAccount::default()
|
.alloc
|
||||||
.with_balance(10000000000000000000000u128.try_into().unwrap()),
|
.entry(signer_address)
|
||||||
);
|
.or_insert(GenesisAccount::default().with_balance(U256::from(INITIAL_BALANCE)));
|
||||||
}
|
}
|
||||||
let genesis_path = self.base_directory.join(Self::GENESIS_JSON_FILE);
|
let genesis_path = self.base_directory.join(Self::GENESIS_JSON_FILE);
|
||||||
serde_json::to_writer(File::create(&genesis_path)?, &genesis)?;
|
serde_json::to_writer(File::create(&genesis_path)?, &genesis)?;
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ use tracing::Level;
|
|||||||
use revive_dt_config::Arguments;
|
use revive_dt_config::Arguments;
|
||||||
use revive_dt_node_interaction::{BlockingExecutor, EthereumNode};
|
use revive_dt_node_interaction::{BlockingExecutor, EthereumNode};
|
||||||
|
|
||||||
use crate::{Node, common::FallbackGasFiller};
|
use crate::{Node, common::FallbackGasFiller, constants::INITIAL_BALANCE};
|
||||||
|
|
||||||
static NODE_COUNT: AtomicU32 = AtomicU32::new(0);
|
static NODE_COUNT: AtomicU32 = AtomicU32::new(0);
|
||||||
|
|
||||||
@@ -131,10 +131,10 @@ impl KitchensinkNode {
|
|||||||
for signer_address in
|
for signer_address in
|
||||||
<EthereumWallet as NetworkWallet<Ethereum>>::signer_addresses(&self.wallet)
|
<EthereumWallet as NetworkWallet<Ethereum>>::signer_addresses(&self.wallet)
|
||||||
{
|
{
|
||||||
genesis.alloc.entry(signer_address).or_insert(
|
genesis
|
||||||
GenesisAccount::default()
|
.alloc
|
||||||
.with_balance(10000000000000000000000u128.try_into().unwrap()),
|
.entry(signer_address)
|
||||||
);
|
.or_insert(GenesisAccount::default().with_balance(U256::from(INITIAL_BALANCE)));
|
||||||
}
|
}
|
||||||
self.extract_balance_from_genesis_file(&genesis)?
|
self.extract_balance_from_genesis_file(&genesis)?
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ use revive_dt_config::Arguments;
|
|||||||
use revive_dt_node_interaction::EthereumNode;
|
use revive_dt_node_interaction::EthereumNode;
|
||||||
|
|
||||||
pub mod common;
|
pub mod common;
|
||||||
|
pub mod constants;
|
||||||
pub mod geth;
|
pub mod geth;
|
||||||
pub mod kitchensink;
|
pub mod kitchensink;
|
||||||
pub mod pool;
|
pub mod pool;
|
||||||
|
|||||||
Reference in New Issue
Block a user