diff --git a/crates/bytecode/src/bytecode.rs b/crates/bytecode/src/bytecode.rs index f1a4a58ae2..d7fa73b46e 100644 --- a/crates/bytecode/src/bytecode.rs +++ b/crates/bytecode/src/bytecode.rs @@ -8,7 +8,7 @@ use primitives::{keccak256, Address, Bytes, B256, KECCAK_EMPTY}; use std::sync::Arc; /// State of the [`Bytecode`] analysis. -#[derive(Clone, Debug, PartialEq, Eq, Hash)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, Ord, PartialOrd)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub enum Bytecode { /// No analysis has been performed. diff --git a/crates/bytecode/src/eip7702.rs b/crates/bytecode/src/eip7702.rs index 191a0c33da..88a1ca5319 100644 --- a/crates/bytecode/src/eip7702.rs +++ b/crates/bytecode/src/eip7702.rs @@ -14,7 +14,7 @@ pub const EIP7702_VERSION: u8 = 0; /// /// Format of EIP-7702 bytecode consist of: /// 0xEF00 (MAGIC) + 0x00 (VERSION) + 20 bytes of address. -#[derive(Clone, Debug, PartialEq, Eq, Hash)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, Ord, PartialOrd)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct Eip7702Bytecode { pub delegated_address: Address, diff --git a/crates/bytecode/src/eof.rs b/crates/bytecode/src/eof.rs index 6aa7a00597..ce9279b162 100644 --- a/crates/bytecode/src/eof.rs +++ b/crates/bytecode/src/eof.rs @@ -27,7 +27,7 @@ pub static EOF_MAGIC_BYTES: Bytes = bytes!("ef00"); /// EVM Object Format (EOF) container. /// /// It consists of a header, body and the raw original bytes. -#[derive(Clone, Debug, PartialEq, Eq, Hash)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, Ord, PartialOrd)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct Eof { pub header: EofHeader, diff --git a/crates/bytecode/src/eof/body.rs b/crates/bytecode/src/eof/body.rs index 66ccd9707c..9b0423820b 100644 --- a/crates/bytecode/src/eof/body.rs +++ b/crates/bytecode/src/eof/body.rs @@ -7,7 +7,7 @@ use std::vec::Vec; /// Contains types, code, container and data sections. /// /// Can be used to create a new EOF container using the [`into_eof`](EofBody::into_eof) method. -#[derive(Clone, Debug, Default, PartialEq, Eq, Hash)] +#[derive(Clone, Debug, Default, PartialEq, Eq, Hash, Ord, PartialOrd)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct EofBody { pub types_section: Vec, diff --git a/crates/bytecode/src/eof/header.rs b/crates/bytecode/src/eof/header.rs index a1226678cf..bbe3e364c0 100644 --- a/crates/bytecode/src/eof/header.rs +++ b/crates/bytecode/src/eof/header.rs @@ -5,7 +5,7 @@ use super::{ use std::vec::Vec; /// EOF Header containing -#[derive(Clone, Debug, Default, PartialEq, Eq, Hash)] +#[derive(Clone, Debug, Default, PartialEq, Eq, Hash, Ord, PartialOrd)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct EofHeader { /// Size of EOF types section. diff --git a/crates/bytecode/src/eof/types_section.rs b/crates/bytecode/src/eof/types_section.rs index c2c6c475db..87f828321c 100644 --- a/crates/bytecode/src/eof/types_section.rs +++ b/crates/bytecode/src/eof/types_section.rs @@ -8,7 +8,7 @@ use std::vec::Vec; const EOF_NON_RETURNING_FUNCTION: u8 = 0x80; /// Types section that contains stack information for matching code section. -#[derive(Debug, Clone, Default, Hash, PartialEq, Eq, Copy)] +#[derive(Debug, Clone, Default, Hash, PartialEq, Eq, Copy, PartialOrd, Ord)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct TypesSection { /// inputs - 1 byte - `0x00-0x7F` diff --git a/crates/bytecode/src/legacy/analyzed.rs b/crates/bytecode/src/legacy/analyzed.rs index 1a8f08511c..e16dfc8a64 100644 --- a/crates/bytecode/src/legacy/analyzed.rs +++ b/crates/bytecode/src/legacy/analyzed.rs @@ -4,7 +4,7 @@ use primitives::Bytes; use std::sync::Arc; // Legacy analyzed -#[derive(Clone, Debug, PartialEq, Eq, Hash)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, Ord, PartialOrd)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct LegacyAnalyzedBytecode { /// Bytecode with 32 zero bytes padding. diff --git a/crates/bytecode/src/legacy/jump_map.rs b/crates/bytecode/src/legacy/jump_map.rs index bd791646fa..32069c0f0c 100644 --- a/crates/bytecode/src/legacy/jump_map.rs +++ b/crates/bytecode/src/legacy/jump_map.rs @@ -3,7 +3,7 @@ use primitives::hex; use std::{fmt::Debug, sync::Arc}; /// A map of valid `jump` destinations. -#[derive(Clone, Default, PartialEq, Eq, Hash)] +#[derive(Clone, Default, PartialEq, Eq, Hash, Ord, PartialOrd)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct JumpTable(pub Arc>); diff --git a/crates/bytecode/src/legacy/raw.rs b/crates/bytecode/src/legacy/raw.rs index c12252cb2c..b55ea2845a 100644 --- a/crates/bytecode/src/legacy/raw.rs +++ b/crates/bytecode/src/legacy/raw.rs @@ -5,7 +5,7 @@ use core::ops::Deref; use primitives::Bytes; use std::{sync::Arc, vec::Vec}; -#[derive(Clone, Debug, PartialEq, Eq, Hash)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, Ord, PartialOrd)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct LegacyRawBytecode(pub Bytes); diff --git a/crates/database/src/states/account_status.rs b/crates/database/src/states/account_status.rs index 6f0d8e7f78..4de97c8824 100644 --- a/crates/database/src/states/account_status.rs +++ b/crates/database/src/states/account_status.rs @@ -14,7 +14,7 @@ /// - `Destroyed`: the account has been destroyed. /// - `DestroyedChanged`: the account has been destroyed and then modified. /// - `DestroyedAgain`: the account has been destroyed again. -#[derive(Clone, Copy, Default, Debug, PartialEq, Eq, Hash)] +#[derive(Clone, Copy, Default, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub enum AccountStatus { #[default] diff --git a/crates/database/src/states/reverts.rs b/crates/database/src/states/reverts.rs index 3c14154cdc..259739259e 100644 --- a/crates/database/src/states/reverts.rs +++ b/crates/database/src/states/reverts.rs @@ -4,11 +4,13 @@ use super::{ }; use core::ops::{Deref, DerefMut}; use primitives::{Address, HashMap, U256}; +use std::cmp::Ordering; + use state::AccountInfo; use std::vec::Vec; /// Contains reverts of multiple account in multiple transitions (Transitions as a block). -#[derive(Clone, Debug, Default, PartialEq, Eq)] +#[derive(Clone, Debug, Default, Eq)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct Reverts(Vec>); @@ -81,6 +83,36 @@ impl Reverts { state_reverts } + /// Compare two Reverts instances, ignoring the order of elements + pub fn content_eq(&self, other: &Self) -> bool { + if self.0.len() != other.0.len() { + return false; + } + + for (self_transition, other_transition) in self.0.iter().zip(other.0.iter()) { + if self_transition.len() != other_transition.len() { + return false; + } + + let mut self_transition = self_transition.clone(); + let mut other_transition = other_transition.clone(); + // Sort both transitions + self_transition.sort_by(|(addr1, revert1), (addr2, revert2)| { + addr1.cmp(addr2).then_with(|| revert1.cmp(revert2)) + }); + other_transition.sort_by(|(addr1, revert1), (addr2, revert2)| { + addr1.cmp(addr2).then_with(|| revert1.cmp(revert2)) + }); + + // Compare sorted transitions + if self_transition != other_transition { + return false; + } + } + + true + } + /// Consume reverts and create [`PlainStateReverts`]. /// /// Note that account are sorted by address. @@ -90,6 +122,12 @@ impl Reverts { } } +impl PartialEq for Reverts { + fn eq(&self, other: &Self) -> bool { + self.content_eq(other) + } +} + /// Assumption is that Revert can return full state from any future state to any past state. /// /// It is created when new account state is applied to old account state. @@ -198,9 +236,55 @@ impl AccountRevert { } } +/// Implements partial ordering for AccountRevert +impl PartialOrd for AccountRevert { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +/// Implements total ordering for AccountRevert +impl Ord for AccountRevert { + fn cmp(&self, other: &Self) -> Ordering { + // First compare accounts + if let Some(ord) = self.account.partial_cmp(&other.account) { + if ord != Ordering::Equal { + return ord; + } + } + + // Convert HashMaps to sorted vectors for comparison + let mut self_storage: Vec<_> = self.storage.iter().collect(); + let mut other_storage: Vec<_> = other.storage.iter().collect(); + + // Sort by key and then by value + self_storage.sort_by(|(k1, v1), (k2, v2)| k1.cmp(k2).then_with(|| v1.cmp(v2))); + other_storage.sort_by(|(k1, v1), (k2, v2)| k1.cmp(k2).then_with(|| v1.cmp(v2))); + + // Compare each element + for (self_entry, other_entry) in self_storage.iter().zip(other_storage.iter()) { + let key_ord = self_entry.0.cmp(other_entry.0); + if key_ord != Ordering::Equal { + return key_ord; + } + let value_ord = self_entry.1.cmp(other_entry.1); + if value_ord != Ordering::Equal { + return value_ord; + } + } + + // If one vector is longer than the other, or if all elements are equal + self_storage + .len() + .cmp(&other_storage.len()) + .then_with(|| self.previous_status.cmp(&other.previous_status)) + .then_with(|| self.wipe_storage.cmp(&other.wipe_storage)) + } +} + /// Depending on previous state of account info this /// will tell us what to do on revert. -#[derive(Clone, Default, Debug, PartialEq, Eq, Hash)] +#[derive(Clone, Default, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub enum AccountInfoRevert { #[default] @@ -219,7 +303,7 @@ pub enum AccountInfoRevert { /// /// Note: It is completely different state if Storage is Zero or Some or if Storage was /// Destroyed. Because if it is destroyed, previous values can be found in database or it can be zero. -#[derive(Clone, Debug, Copy, PartialEq, Eq, Hash)] +#[derive(Clone, Debug, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub enum RevertToSlot { Some(U256), diff --git a/crates/state/src/account_info.rs b/crates/state/src/account_info.rs index 0dbdd75c63..18c2824415 100644 --- a/crates/state/src/account_info.rs +++ b/crates/state/src/account_info.rs @@ -3,7 +3,7 @@ use core::hash::{Hash, Hasher}; use primitives::{B256, KECCAK_EMPTY, U256}; /// AccountInfo account information. -#[derive(Clone, Debug, Eq)] +#[derive(Clone, Debug, Eq, Ord, PartialOrd)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct AccountInfo { /// Account balance.