Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add more JournaledState methods to EvmContext #1158

Merged
merged 2 commits into from Mar 6, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
104 changes: 62 additions & 42 deletions crates/revm/src/context.rs
Expand Up @@ -7,12 +7,12 @@ use crate::{
journaled_state::JournaledState,
precompile::{Precompile, Precompiles},
primitives::{
keccak256, Address, AnalysisKind, Bytecode, Bytes, CreateScheme, EVMError, Env, HandlerCfg,
HashSet, Spec, SpecId, SpecId::*, B256, U256,
keccak256, Account, Address, AnalysisKind, Bytecode, Bytes, CreateScheme, EVMError, Env,
HandlerCfg, HashSet, Spec, SpecId, SpecId::*, B256, U256,
},
FrameOrResult, JournalCheckpoint, CALL_STACK_LIMIT,
};
use revm_interpreter::SStoreResult;
use revm_interpreter::{SStoreResult, SelfDestructResult};
use std::boxed::Box;

/// Main Context structure that contains both EvmContext and External context.
Expand Down Expand Up @@ -96,7 +96,7 @@ where
}

/// EVM contexts contains data that EVM needs for execution.
#[derive(Debug)]
#[derive(Clone, Debug)]
pub struct EvmContext<DB: Database> {
/// EVM Environment contains all the information about config, block and transaction that
/// evm needs.
Expand All @@ -114,39 +114,18 @@ pub struct EvmContext<DB: Database> {
pub l1_block_info: Option<crate::optimism::L1BlockInfo>,
}

impl<DB: Database + Clone> Clone for EvmContext<DB>
where
DB::Error: Clone,
{
fn clone(&self) -> Self {
Self {
env: self.env.clone(),
journaled_state: self.journaled_state.clone(),
db: self.db.clone(),
error: self.error.clone(),
precompiles: self.precompiles.clone(),
#[cfg(feature = "optimism")]
l1_block_info: self.l1_block_info.clone(),
}
}
}

impl<DB: Database> EvmContext<DB> {
pub fn with_db<ODB: Database>(self, db: ODB) -> EvmContext<ODB> {
EvmContext {
env: self.env,
journaled_state: self.journaled_state,
db,
error: Ok(()),
precompiles: self.precompiles,
#[cfg(feature = "optimism")]
l1_block_info: self.l1_block_info,
}
/// Creates a new context with the given database.
#[inline]
pub fn new(db: DB) -> Self {
Self::new_with_env(db, Box::default())
}

pub fn new(db: DB) -> Self {
/// Creates a new context with the given environment and database.
#[inline]
pub fn new_with_env(db: DB, env: Box<Env>) -> Self {
Self {
env: Box::default(),
env,
journaled_state: JournaledState::new(SpecId::LATEST, HashSet::new()),
db,
error: Ok(()),
Expand All @@ -156,24 +135,34 @@ impl<DB: Database> EvmContext<DB> {
}
}

/// New context with database and environment.
pub fn new_with_env(db: DB, env: Box<Env>) -> Self {
Self {
env,
journaled_state: JournaledState::new(SpecId::LATEST, HashSet::new()),
/// Sets the database.
///
/// Note that this will ignore the previous `error` if set.
#[inline]
pub fn with_db<ODB: Database>(self, db: ODB) -> EvmContext<ODB> {
EvmContext {
env: self.env,
journaled_state: self.journaled_state,
db,
error: Ok(()),
precompiles: Precompiles::default(),
precompiles: self.precompiles,
#[cfg(feature = "optimism")]
l1_block_info: None,
l1_block_info: self.l1_block_info,
}
}

/// Returns the configured EVM spec ID.
#[inline]
pub const fn spec_id(&self) -> SpecId {
self.journaled_state.spec
}

/// Returns the current depth of the journaled state.
#[inline]
pub fn depth(&self) -> u64 {
self.journaled_state.depth()
}

/// Sets precompiles
#[inline]
pub fn set_precompiles(&mut self, precompiles: Precompiles) {
Expand Down Expand Up @@ -206,9 +195,29 @@ impl<DB: Database> EvmContext<DB> {
self.db.block_hash(number).map_err(EVMError::Database)
}

/// Load account and return flags (is_cold, exists)
/// Mark account as touched as only touched accounts will be added to state.
#[inline]
pub fn touch(&mut self, address: &Address) {
self.journaled_state.touch(address);
}

/// Loads an account into memory. Returns `true` if it is cold accessed.
#[inline]
pub fn load_account(
&mut self,
address: Address,
) -> Result<(&mut Account, bool), EVMError<DB::Error>> {
self.journaled_state.load_account(address, &mut self.db)
}

/// Load account from database to JournaledState.
///
/// Return boolean pair where first is `is_cold` second bool `exists`.
#[inline]
pub fn load_account(&mut self, address: Address) -> Result<(bool, bool), EVMError<DB::Error>> {
pub fn load_account_exist(
&mut self,
address: Address,
) -> Result<(bool, bool), EVMError<DB::Error>> {
self.journaled_state
.load_account_exist(address, &mut self.db)
}
Expand Down Expand Up @@ -274,6 +283,17 @@ impl<DB: Database> EvmContext<DB> {
self.journaled_state.tstore(address, index, value)
}

/// Selfdestructs the account.
#[inline]
pub fn selfdestruct(
&mut self,
address: Address,
target: Address,
) -> Result<SelfDestructResult, EVMError<DB::Error>> {
self.journaled_state
.selfdestruct(address, target, &mut self.db)
}

/// Make create frame.
#[inline]
pub fn make_create_frame(
Expand Down
2 changes: 1 addition & 1 deletion crates/revm/src/evm.rs
Expand Up @@ -400,7 +400,7 @@ impl<EXT, DB: Database> Host for Evm<'_, EXT, DB> {
fn load_account(&mut self, address: Address) -> Option<(bool, bool)> {
self.context
.evm
.load_account(address)
.load_account_exist(address)
.map_err(|e| self.context.evm.error = Err(e))
.ok()
}
Expand Down
13 changes: 7 additions & 6 deletions crates/revm/src/journaled_state.rs
Expand Up @@ -95,7 +95,6 @@ impl JournaledState {
#[inline]
pub fn finalize(&mut self) -> (State, Vec<Log>) {
let state = mem::take(&mut self.state);

let logs = mem::take(&mut self.logs);
self.journal = vec![vec![]];
self.depth = 0;
Expand Down Expand Up @@ -568,9 +567,10 @@ impl JournaledState {
address: Address,
db: &mut DB,
) -> Result<(bool, bool), EVMError<DB::Error>> {
let is_spurious_dragon_enabled = SpecId::enabled(self.spec, SPURIOUS_DRAGON);
let spec = self.spec;
let (acc, is_cold) = self.load_account(address, db)?;

let is_spurious_dragon_enabled = SpecId::enabled(spec, SPURIOUS_DRAGON);
let exist = if is_spurious_dragon_enabled {
!acc.is_empty()
} else {
Expand Down Expand Up @@ -605,18 +605,19 @@ impl JournaledState {

/// Load storage slot
///
/// # Note
/// # Panics
///
/// Account is already present and loaded.
/// Panics if the account is present in the state.
rakita marked this conversation as resolved.
Show resolved Hide resolved
#[inline]
pub fn sload<DB: Database>(
&mut self,
address: Address,
key: U256,
db: &mut DB,
) -> Result<(U256, bool), EVMError<DB::Error>> {
let account = self.state.get_mut(&address).unwrap(); // assume acc is warm
// only if account is created in this tx we can assume that storage is empty.
// assume acc is warm
let account = self.state.get_mut(&address).unwrap();
// only if account is created in this tx we can assume that storage is empty.
let is_newly_created = account.is_created();
let load = match account.storage.entry(key) {
Entry::Occupied(occ) => (occ.get().present_value, false),
Expand Down