Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ indicatif = "0.18"
plain_hasher = "0.2"
rstest = "0.26.0"
serde_derive = "1.0"
thiserror = "2.0"
thiserror = { version = "2.0", default-features = false }
triehash = "0.8"
walkdir = "2.5"

Expand Down
35 changes: 20 additions & 15 deletions crates/context/interface/src/journaled_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ pub mod entry;
use crate::{
context::{SStoreResult, SelfDestructResult},
host::LoadError,
journaled_state::{account::JournaledAccount, entry::JournalEntryTr},
journaled_state::account::JournaledAccountTr,
};
use core::ops::{Deref, DerefMut};
use database_interface::Database;
Expand All @@ -22,8 +22,10 @@ pub trait JournalTr {
type Database: Database;
/// State type that is returned by the journal after finalization.
type State;
/// Journal Entry type that is used in the journal.
type JournalEntry: JournalEntryTr;
/// Journal account allows modification of account with all needed changes.
type JournaledAccount<'a>: JournaledAccountTr
where
Self: 'a;

/// Creates new Journaled state.
///
Expand Down Expand Up @@ -186,10 +188,7 @@ pub trait JournalTr {
fn load_account_mut(
&mut self,
address: Address,
) -> Result<
StateLoad<JournaledAccount<'_, Self::JournalEntry>>,
<Self::Database as Database>::Error,
> {
) -> Result<StateLoad<Self::JournaledAccount<'_>>, <Self::Database as Database>::Error> {
self.load_account_mut_optional_code(address, false)
}

Expand All @@ -198,10 +197,7 @@ pub trait JournalTr {
fn load_account_with_code_mut(
&mut self,
address: Address,
) -> Result<
StateLoad<JournaledAccount<'_, Self::JournalEntry>>,
<Self::Database as Database>::Error,
> {
) -> Result<StateLoad<Self::JournaledAccount<'_>>, <Self::Database as Database>::Error> {
self.load_account_mut_optional_code(address, true)
}

Expand All @@ -210,10 +206,7 @@ pub trait JournalTr {
&mut self,
address: Address,
load_code: bool,
) -> Result<
StateLoad<JournaledAccount<'_, Self::JournalEntry>>,
<Self::Database as Database>::Error,
>;
) -> Result<StateLoad<Self::JournaledAccount<'_>>, <Self::Database as Database>::Error>;

/// Sets bytecode with hash. Assume that account is warm.
fn set_code_with_hash(&mut self, address: Address, code: Bytecode, hash: B256);
Expand Down Expand Up @@ -352,6 +345,18 @@ impl<E> JournalLoadError<E> {
JournalLoadError::ColdLoadSkipped => (LoadError::ColdLoadSkipped, None),
}
}

/// Maps the database error to a new error.
#[inline]
pub fn map<B, F>(self, f: F) -> JournalLoadError<B>
where
F: FnOnce(E) -> B,
{
match self {
JournalLoadError::DBError(e) => JournalLoadError::DBError(f(e)),
JournalLoadError::ColdLoadSkipped => JournalLoadError::ColdLoadSkipped,
}
}
}

impl<E> From<E> for JournalLoadError<E> {
Expand Down
132 changes: 107 additions & 25 deletions crates/context/interface/src/journaled_state/account.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,100 @@
//!
//! Useful to encapsulate account and journal entries together. So when account gets changed, we can add a journal entry for it.

use crate::journaled_state::entry::JournalEntry;

use super::entry::JournalEntryTr;
use core::ops::Deref;
use auto_impl::auto_impl;
use primitives::{Address, B256, KECCAK_EMPTY, U256};
use state::{Account, Bytecode};
use std::vec::Vec;

/// Trait that contains database and journal of all changes that were made to the account.
#[auto_impl(&mut, Box)]
pub trait JournaledAccountTr {
/// Returns the account.
fn account(&self) -> &Account;

/// Returns the balance of the account.
fn balance(&self) -> &U256;

/// Returns the nonce of the account.
fn nonce(&self) -> u64;

/// Returns the code hash of the account.
fn code_hash(&self) -> &B256;

/// Returns the code of the account.
fn code(&self) -> Option<&Bytecode>;

/// Touches the account.
fn touch(&mut self);

/// Marks the account as cold without making a journal entry.
///
/// Changing account without journal entry can be a footgun as reverting of the state change
/// would not happen without entry. It is the reason why this function has an `unsafe` prefix.
///
/// If account is in access list, it would still be marked as warm if account get accessed again.
fn unsafe_mark_cold(&mut self);

/// Sets the balance of the account.
///
/// If balance is the same, we don't add a journal entry.
///
/// Touches the account in all cases.
fn set_balance(&mut self, balance: U256);

/// Increments the balance of the account.
///
/// Touches the account in all cases.
fn incr_balance(&mut self, balance: U256) -> bool;

/// Decrements the balance of the account.
///
/// Touches the account in all cases.
fn decr_balance(&mut self, balance: U256) -> bool;
Comment on lines +50 to +58
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what's the bool that this returns?


/// Bumps the nonce of the account.
///
/// Touches the account in all cases.
///
/// Returns true if nonce was bumped, false if nonce is at the max value.
fn bump_nonce(&mut self) -> bool;

/// Set the nonce of the account and create a journal entry.
///
/// Touches the account in all cases.
fn set_nonce(&mut self, nonce: u64);

/// Set the nonce of the account without creating a journal entry.
///
/// Changing account without journal entry can be a footgun as reverting of the state change
/// would not happen without entry. It is the reason why this function has an `unsafe` prefix.
fn unsafe_set_nonce(&mut self, nonce: u64);

/// Sets the code of the account.
///
/// Touches the account in all cases.
fn set_code(&mut self, code_hash: B256, code: Bytecode);

/// Sets the code of the account. Calculates hash of the code.
///
/// Touches the account in all cases.
fn set_code_and_hash_slow(&mut self, code: Bytecode);

/// Delegates the account to another address (EIP-7702).
///
/// This touches the account, sets the code to the delegation designation,
/// and bumps the nonce.
fn delegate(&mut self, address: Address);
}

/// Journaled account contains both mutable account and journal entries.
///
/// Useful to encapsulate account and journal entries together. So when account gets changed, we can add a journal entry for it.
#[derive(Debug, PartialEq, Eq)]
pub struct JournaledAccount<'a, ENTRY: JournalEntryTr> {
pub struct JournaledAccount<'a, ENTRY: JournalEntryTr = JournalEntry> {
/// Address of the account.
address: Address,
/// Mutable account.
Expand Down Expand Up @@ -42,34 +125,41 @@ impl<'a, ENTRY: JournalEntryTr> JournaledAccount<'a, ENTRY> {
journal_entries,
}
}
}

impl<'a, ENTRY: JournalEntryTr> JournaledAccountTr for JournaledAccount<'a, ENTRY> {
/// Returns the account.
fn account(&self) -> &Account {
self.account
}

/// Returns the balance of the account.
#[inline]
pub fn balance(&self) -> &U256 {
fn balance(&self) -> &U256 {
&self.account.info.balance
}

/// Returns the nonce of the account.
#[inline]
pub fn nonce(&self) -> u64 {
fn nonce(&self) -> u64 {
self.account.info.nonce
}

/// Returns the code hash of the account.
#[inline]
pub fn code_hash(&self) -> &B256 {
fn code_hash(&self) -> &B256 {
&self.account.info.code_hash
}

/// Returns the code of the account.
#[inline]
pub fn code(&self) -> Option<&Bytecode> {
fn code(&self) -> Option<&Bytecode> {
self.account.info.code.as_ref()
}

/// Touches the account.
#[inline]
pub fn touch(&mut self) {
fn touch(&mut self) {
if !self.account.status.is_touched() {
self.account.mark_touch();
self.journal_entries
Expand All @@ -84,7 +174,7 @@ impl<'a, ENTRY: JournalEntryTr> JournaledAccount<'a, ENTRY> {
///
/// If account is in access list, it would still be marked as warm if account get accessed again.
#[inline]
pub fn unsafe_mark_cold(&mut self) {
fn unsafe_mark_cold(&mut self) {
self.account.mark_cold();
}

Expand All @@ -94,7 +184,7 @@ impl<'a, ENTRY: JournalEntryTr> JournaledAccount<'a, ENTRY> {
///
/// Touches the account in all cases.
#[inline]
pub fn set_balance(&mut self, balance: U256) {
fn set_balance(&mut self, balance: U256) {
self.touch();
if self.account.info.balance != balance {
self.journal_entries.push(ENTRY::balance_changed(
Expand All @@ -109,7 +199,7 @@ impl<'a, ENTRY: JournalEntryTr> JournaledAccount<'a, ENTRY> {
///
/// Touches the account in all cases.
#[inline]
pub fn incr_balance(&mut self, balance: U256) -> bool {
fn incr_balance(&mut self, balance: U256) -> bool {
self.touch();
let Some(balance) = self.account.info.balance.checked_add(balance) else {
return false;
Expand All @@ -122,7 +212,7 @@ impl<'a, ENTRY: JournalEntryTr> JournaledAccount<'a, ENTRY> {
///
/// Touches the account in all cases.
#[inline]
pub fn decr_balance(&mut self, balance: U256) -> bool {
fn decr_balance(&mut self, balance: U256) -> bool {
self.touch();
let Some(balance) = self.account.info.balance.checked_sub(balance) else {
return false;
Expand All @@ -137,7 +227,7 @@ impl<'a, ENTRY: JournalEntryTr> JournaledAccount<'a, ENTRY> {
///
/// Returns true if nonce was bumped, false if nonce is at the max value.
#[inline]
pub fn bump_nonce(&mut self) -> bool {
fn bump_nonce(&mut self) -> bool {
self.touch();
let Some(nonce) = self.account.info.nonce.checked_add(1) else {
return false;
Expand All @@ -151,7 +241,7 @@ impl<'a, ENTRY: JournalEntryTr> JournaledAccount<'a, ENTRY> {
///
/// Touches the account in all cases.
#[inline]
pub fn set_nonce(&mut self, nonce: u64) {
fn set_nonce(&mut self, nonce: u64) {
self.touch();
let previous_nonce = self.account.info.nonce;
self.account.info.set_nonce(nonce);
Expand All @@ -164,15 +254,15 @@ impl<'a, ENTRY: JournalEntryTr> JournaledAccount<'a, ENTRY> {
/// Changing account without journal entry can be a footgun as reverting of the state change
/// would not happen without entry. It is the reason why this function has an `unsafe` prefix.
#[inline]
pub fn unsafe_set_nonce(&mut self, nonce: u64) {
fn unsafe_set_nonce(&mut self, nonce: u64) {
self.account.info.set_nonce(nonce);
}

/// Sets the code of the account.
///
/// Touches the account in all cases.
#[inline]
pub fn set_code(&mut self, code_hash: B256, code: Bytecode) {
fn set_code(&mut self, code_hash: B256, code: Bytecode) {
self.touch();
self.account.info.set_code_hash(code_hash);
self.account.info.set_code(code);
Expand All @@ -183,7 +273,7 @@ impl<'a, ENTRY: JournalEntryTr> JournaledAccount<'a, ENTRY> {
///
/// Touches the account in all cases.
#[inline]
pub fn set_code_and_hash_slow(&mut self, code: Bytecode) {
fn set_code_and_hash_slow(&mut self, code: Bytecode) {
let code_hash = code.hash_slow();
self.set_code(code_hash, code);
}
Expand All @@ -193,7 +283,7 @@ impl<'a, ENTRY: JournalEntryTr> JournaledAccount<'a, ENTRY> {
/// This touches the account, sets the code to the delegation designation,
/// and bumps the nonce.
#[inline]
pub fn delegate(&mut self, address: Address) {
fn delegate(&mut self, address: Address) {
let (bytecode, hash) = if address.is_zero() {
(Bytecode::default(), KECCAK_EMPTY)
} else {
Expand All @@ -206,11 +296,3 @@ impl<'a, ENTRY: JournalEntryTr> JournaledAccount<'a, ENTRY> {
self.bump_nonce();
}
}

impl<'a, ENTRY: JournalEntryTr> Deref for JournaledAccount<'a, ENTRY> {
type Target = Account;

fn deref(&self) -> &Self::Target {
self.account
}
}
1 change: 1 addition & 0 deletions crates/context/interface/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ pub mod transaction;
pub use block::Block;
pub use cfg::{Cfg, CreateScheme, TransactTo};
pub use context::{ContextError, ContextSetters, ContextTr};
pub use database_interface::erased_error::ErasedError;
pub use database_interface::{DBErrorMarker, Database};
pub use either;
pub use host::{DummyHost, Host};
Expand Down
10 changes: 5 additions & 5 deletions crates/context/src/journal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,10 @@ impl<DB, ENTRY: JournalEntryTr + Clone> Journal<DB, ENTRY> {
impl<DB: Database, ENTRY: JournalEntryTr> JournalTr for Journal<DB, ENTRY> {
type Database = DB;
type State = EvmState;
type JournalEntry = ENTRY;
type JournaledAccount<'a>
= JournaledAccount<'a, ENTRY>
where
Self: 'a;

fn new(database: DB) -> Journal<DB, ENTRY> {
Self {
Expand Down Expand Up @@ -257,10 +260,7 @@ impl<DB: Database, ENTRY: JournalEntryTr> JournalTr for Journal<DB, ENTRY> {
&mut self,
address: Address,
load_code: bool,
) -> Result<
StateLoad<JournaledAccount<'_, Self::JournalEntry>>,
<Self::Database as Database>::Error,
> {
) -> Result<StateLoad<Self::JournaledAccount<'_>>, DB::Error> {
self.inner
.load_account_mut_optional_code(&mut self.database, address, load_code, false)
.map_err(JournalLoadError::unwrap_db_error)
Expand Down
2 changes: 1 addition & 1 deletion crates/context/src/journal/inner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use bytecode::Bytecode;
use context_interface::{
context::{SStoreResult, SelfDestructResult, StateLoad},
journaled_state::{
account::JournaledAccount,
account::{JournaledAccount, JournaledAccountTr},
entry::{JournalEntryTr, SelfdestructionRevertStatus},
AccountLoad, JournalCheckpoint, JournalLoadError, TransferError,
},
Expand Down
Loading
Loading