Skip to content

Commit

Permalink
feat(database): implement order-independent equality for Reverts (#1827)
Browse files Browse the repository at this point in the history
* bet

* bet

* bet

* Update crates/database/src/states/reverts.rs

* bet

* bet

* bet
  • Loading branch information
hoank101 authored and royvardhan committed Dec 20, 2024
1 parent a350fab commit 5e0e91c
Show file tree
Hide file tree
Showing 12 changed files with 98 additions and 14 deletions.
2 changes: 1 addition & 1 deletion crates/bytecode/src/bytecode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
/// The bytecode has been analyzed for valid jump destinations.
Expand Down
2 changes: 1 addition & 1 deletion crates/bytecode/src/eip7702.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
2 changes: 1 addition & 1 deletion crates/bytecode/src/eof.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
2 changes: 1 addition & 1 deletion crates/bytecode/src/eof/body.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
/// Code information
Expand Down
2 changes: 1 addition & 1 deletion crates/bytecode/src/eof/header.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
2 changes: 1 addition & 1 deletion crates/bytecode/src/eof/types_section.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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`
Expand Down
2 changes: 1 addition & 1 deletion crates/bytecode/src/legacy/analyzed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
2 changes: 1 addition & 1 deletion crates/bytecode/src/legacy/jump_map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<BitVec<u8>>);

Expand Down
2 changes: 1 addition & 1 deletion crates/bytecode/src/legacy/raw.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down
2 changes: 1 addition & 1 deletion crates/database/src/states/account_status.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down
90 changes: 87 additions & 3 deletions crates/database/src/states/reverts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Vec<(Address, AccountRevert)>>);

Expand Down Expand Up @@ -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.
Expand All @@ -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.
Expand Down Expand Up @@ -198,9 +236,55 @@ impl AccountRevert {
}
}

/// Implements partial ordering for AccountRevert
impl PartialOrd for AccountRevert {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
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]
Expand All @@ -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),
Expand Down
2 changes: 1 addition & 1 deletion crates/state/src/account_info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down

0 comments on commit 5e0e91c

Please sign in to comment.