diff --git a/crates/interpreter/src/host.rs b/crates/interpreter/src/host.rs index 06189d544e..fff18bb848 100644 --- a/crates/interpreter/src/host.rs +++ b/crates/interpreter/src/host.rs @@ -37,12 +37,7 @@ pub trait Host { /// Set storage value of account address at index. /// /// Returns (original, present, new, is_cold). - fn sstore( - &mut self, - address: Address, - index: U256, - value: U256, - ) -> Option<(U256, U256, U256, bool)>; + fn sstore(&mut self, address: Address, index: U256, value: U256) -> Option; /// Get the transient storage value of `address` at `index`. fn tload(&mut self, address: Address, index: U256) -> U256; @@ -56,3 +51,17 @@ pub trait Host { /// Mark `address` to be deleted, with funds transferred to `target`. fn selfdestruct(&mut self, address: Address, target: Address) -> Option; } + +/// Represents the result of an `sstore` operation. +#[derive(Debug, Clone, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub struct SStoreResult { + /// Value of the storage when it is first read + pub original_value: U256, + /// Current value of the storage + pub present_value: U256, + /// New value that is set + pub new_value: U256, + /// Is storage slot loaded from database + pub is_cold: bool, +} diff --git a/crates/interpreter/src/host/dummy.rs b/crates/interpreter/src/host/dummy.rs index ca8e2b4538..519d3e06ee 100644 --- a/crates/interpreter/src/host/dummy.rs +++ b/crates/interpreter/src/host/dummy.rs @@ -1,7 +1,7 @@ use crate::primitives::{hash_map::Entry, Bytecode, HashMap, U256}; use crate::{ primitives::{Address, Env, Log, B256, KECCAK_EMPTY}, - Host, SelfDestructResult, + Host, SStoreResult, SelfDestructResult, }; use std::vec::Vec; @@ -80,12 +80,7 @@ impl Host for DummyHost { } #[inline] - fn sstore( - &mut self, - _address: Address, - index: U256, - value: U256, - ) -> Option<(U256, U256, U256, bool)> { + fn sstore(&mut self, _address: Address, index: U256, value: U256) -> Option { let (present, is_cold) = match self.storage.entry(index) { Entry::Occupied(mut entry) => (entry.insert(value), false), Entry::Vacant(entry) => { @@ -94,7 +89,12 @@ impl Host for DummyHost { } }; - Some((U256::ZERO, present, value, is_cold)) + Some(SStoreResult { + original_value: U256::ZERO, + present_value: present, + new_value: value, + is_cold, + }) } #[inline] diff --git a/crates/interpreter/src/instructions/host.rs b/crates/interpreter/src/instructions/host.rs index 9a4a9e79ea..a80c3b54e2 100644 --- a/crates/interpreter/src/instructions/host.rs +++ b/crates/interpreter/src/instructions/host.rs @@ -7,7 +7,7 @@ use crate::{ interpreter::{Interpreter, InterpreterAction}, primitives::{Address, Bytes, Log, LogData, Spec, SpecId::*, B256, U256}, CallContext, CallInputs, CallScheme, CreateInputs, CreateScheme, Host, InstructionResult, - Transfer, MAX_INITCODE_SIZE, + SStoreResult, Transfer, MAX_INITCODE_SIZE, }; use core::cmp::min; use revm_primitives::BLOCK_HASH_HISTORY; @@ -154,8 +154,12 @@ pub fn sstore(interpreter: &mut Interpreter, host: &mut H) check_staticcall!(interpreter); pop!(interpreter, index, value); - let Some((original, old, new, is_cold)) = - host.sstore(interpreter.contract.address, index, value) + let Some(SStoreResult { + original_value: original, + present_value: old, + new_value: new, + is_cold, + }) = host.sstore(interpreter.contract.address, index, value) else { interpreter.instruction_result = InstructionResult::FatalExternalError; return; diff --git a/crates/interpreter/src/lib.rs b/crates/interpreter/src/lib.rs index cecef71120..861853dcd1 100644 --- a/crates/interpreter/src/lib.rs +++ b/crates/interpreter/src/lib.rs @@ -25,7 +25,7 @@ mod interpreter; pub use call_outcome::CallOutcome; pub use create_outcome::CreateOutcome; pub use gas::Gas; -pub use host::{DummyHost, Host}; +pub use host::{DummyHost, Host, SStoreResult}; pub use inner_models::*; pub use instruction_result::*; pub use instructions::{opcode, Instruction, OpCode, OPCODE_JUMPMAP}; diff --git a/crates/revm/src/context.rs b/crates/revm/src/context.rs index ef91258729..e21cc63720 100644 --- a/crates/revm/src/context.rs +++ b/crates/revm/src/context.rs @@ -12,6 +12,7 @@ use crate::{ }, FrameOrResult, JournalCheckpoint, CALL_STACK_LIMIT, }; +use revm_interpreter::SStoreResult; use std::boxed::Box; /// Main Context structure that contains both EvmContext and External context. @@ -261,12 +262,7 @@ impl EvmContext { /// Storage change of storage slot, before storing `sload` will be called for that slot. #[inline] #[must_use] - pub fn sstore( - &mut self, - address: Address, - index: U256, - value: U256, - ) -> Option<(U256, U256, U256, bool)> { + pub fn sstore(&mut self, address: Address, index: U256, value: U256) -> Option { self.journaled_state .sstore(address, index, value, &mut self.db) .map_err(|e| self.error = Some(e)) diff --git a/crates/revm/src/evm.rs b/crates/revm/src/evm.rs index 8dfe358618..fb9cb3293a 100644 --- a/crates/revm/src/evm.rs +++ b/crates/revm/src/evm.rs @@ -3,8 +3,8 @@ use crate::{ db::{Database, DatabaseCommit, EmptyDB}, handler::Handler, interpreter::{ - opcode::InstructionTables, Host, Interpreter, InterpreterAction, SelfDestructResult, - SharedMemory, + opcode::InstructionTables, Host, Interpreter, InterpreterAction, SStoreResult, + SelfDestructResult, SharedMemory, }, primitives::{ specification::SpecId, Address, BlockEnv, Bytecode, CfgEnv, EVMError, EVMResult, Env, @@ -392,12 +392,7 @@ impl Host for Evm<'_, EXT, DB> { self.context.evm.sload(address, index) } - fn sstore( - &mut self, - address: Address, - index: U256, - value: U256, - ) -> Option<(U256, U256, U256, bool)> { + fn sstore(&mut self, address: Address, index: U256, value: U256) -> Option { self.context.evm.sstore(address, index, value) } diff --git a/crates/revm/src/journaled_state.rs b/crates/revm/src/journaled_state.rs index 2d04ae3c5c..2c1c76f5cb 100644 --- a/crates/revm/src/journaled_state.rs +++ b/crates/revm/src/journaled_state.rs @@ -5,6 +5,7 @@ use crate::primitives::{ }; use core::mem; use revm_interpreter::primitives::SpecId; +use revm_interpreter::SStoreResult; use std::vec::Vec; /// JournalState is internal EVM state that is used to contain state and track changes to that state. @@ -652,7 +653,7 @@ impl JournaledState { key: U256, new: U256, db: &mut DB, - ) -> Result<(U256, U256, U256, bool), DB::Error> { + ) -> Result { // assume that acc exists and load the slot. let (present, is_cold) = self.sload(address, key, db)?; let acc = self.state.get_mut(&address).unwrap(); @@ -662,7 +663,12 @@ impl JournaledState { // new value is same as present, we don't need to do anything if present == new { - return Ok((slot.previous_or_original_value, present, new, is_cold)); + return Ok(SStoreResult { + original_value: slot.previous_or_original_value, + present_value: present, + new_value: new, + is_cold, + }); } self.journal @@ -675,7 +681,12 @@ impl JournaledState { }); // insert value into present state. slot.present_value = new; - Ok((slot.previous_or_original_value, present, new, is_cold)) + Ok(SStoreResult { + original_value: slot.previous_or_original_value, + present_value: present, + new_value: new, + is_cold, + }) } /// Read transient storage tied to the account.