Skip to content
This repository has been archived by the owner on Jul 5, 2024. It is now read-only.

Commit

Permalink
tload in busmapping with test case
Browse files Browse the repository at this point in the history
  • Loading branch information
zemse committed Apr 3, 2024
1 parent d98385c commit 1c1cd7e
Show file tree
Hide file tree
Showing 6 changed files with 84 additions and 46 deletions.
5 changes: 4 additions & 1 deletion bus-mapping/src/evm/opcodes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,6 @@ mod precompiles;
#[cfg(test)]
mod memory_expansion_test;

use self::{invalid_tx::InvalidTx, sha3::Sha3};
use address::Address;
use balance::Balance;
use begin_end_tx::BeginEndTx;
Expand Down Expand Up @@ -97,6 +96,7 @@ use extcodecopy::Extcodecopy;
use extcodehash::Extcodehash;
use extcodesize::Extcodesize;
use gasprice::GasPrice;
use invalid_tx::InvalidTx;
use logs::Log;
use mload::Mload;
use mstore::Mstore;
Expand All @@ -105,11 +105,13 @@ use return_revert::ReturnRevert;
use returndatacopy::Returndatacopy;
use returndatasize::Returndatasize;
use selfbalance::Selfbalance;
use sha3::Sha3;
use sload::Sload;
use sstore::Sstore;
use stackonlyop::StackOnlyOpcode;
use stop::Stop;
use swap::Swap;
use tload::Tload;

#[cfg(any(feature = "test", test))]
pub use crate::precompile::PrecompileCallArgs;
Expand Down Expand Up @@ -225,6 +227,7 @@ fn fn_gen_associated_ops(opcode_id: &OpcodeId) -> FnGenAssociatedOps {
OpcodeId::MSIZE => StackOnlyOpcode::<0, 1>::gen_associated_ops,
OpcodeId::GAS => StackOnlyOpcode::<0, 1>::gen_associated_ops,
OpcodeId::JUMPDEST => Dummy::gen_associated_ops,
OpcodeId::TLOAD => Tload::gen_associated_ops,
OpcodeId::DUP1 => Dup::<1>::gen_associated_ops,
OpcodeId::DUP2 => Dup::<2>::gen_associated_ops,
OpcodeId::DUP3 => Dup::<3>::gen_associated_ops,
Expand Down
53 changes: 9 additions & 44 deletions bus-mapping/src/evm/opcodes/tload.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use super::Opcode;
use crate::{
circuit_input_builder::{CircuitInputStateRef, ExecStep},
operation::{CallContextField, StorageOp, TxAccessListAccountStorageOp, RW},
operation::{CallContextField, TransientStorageOp, RW},
Error,
};
use eth_types::{GethExecStep, ToWord, Word};
Expand All @@ -18,6 +18,7 @@ impl Opcode for Tload {
geth_steps: &[GethExecStep],
) -> Result<Vec<ExecStep>, Error> {
let geth_step = &geth_steps[0];
let next_geth_step = &geth_steps[1];
let mut exec_step = state.new_step(geth_step)?;

let call_id = state.call()?.call_id;
Expand Down Expand Up @@ -59,50 +60,19 @@ impl Opcode for Tload {
state.stack_read(&mut exec_step, stack_position, key)?;

// Storage read
let value = geth_step.storage.get_or_err(&key)?;
let value = next_geth_step
.stack
.last()
.expect("No value in stack in TLOAD next step");

let is_warm = state
.sdb
.check_account_storage_in_access_list(&(contract_addr, key));

let (_, committed_value) = state.sdb.get_committed_storage(&contract_addr, &key);
let committed_value = *committed_value;
state.push_op(
&mut exec_step,
RW::READ,
StorageOp::new(
contract_addr,
key,
value,
value,
state.tx_ctx.id(),
committed_value,
),
TransientStorageOp::new(contract_addr, key, value, value, state.tx_ctx.id()),
)?;

// First stack write
state.stack_write(&mut exec_step, stack_position, value)?;
state.push_op(
&mut exec_step,
RW::READ,
TxAccessListAccountStorageOp {
tx_id: state.tx_ctx.id(),
address: contract_addr,
key,
is_warm,
is_warm_prev: is_warm,
},
)?;
state.push_op_reversible(
&mut exec_step,
TxAccessListAccountStorageOp {
tx_id: state.tx_ctx.id(),
address: contract_addr,
key,
is_warm: true,
is_warm_prev: is_warm,
},
)?;

Ok(vec![exec_step])
}
Expand All @@ -128,7 +98,8 @@ mod tload_tests {
};
use pretty_assertions::assert_eq;

fn test_ok() {
#[test]
fn tload_opcode() {
let code = bytecode! {
// Load transient storage slot 0
PUSH1(0x00u64)
Expand All @@ -152,7 +123,6 @@ mod tload_tests {
.handle_block(&block.eth_block, &block.geth_traces)
.unwrap();

println!("{:#?}", builder.block.txs()[0].steps());
let step = builder.block.txs()[0]
.steps()
.iter()
Expand Down Expand Up @@ -191,9 +161,4 @@ mod tload_tests {
)
);
}

#[test]
fn tload_opcode_impl_warm() {
test_ok()
}
}
2 changes: 2 additions & 0 deletions eth-types/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ pub enum Error {
InvalidMemoryPointer,
/// Error while trying to access an invalid/empty Storage key.
InvalidStorageKey,
/// Error while trying to access an invalid/empty Transient Storage key.
InvalidTransientStorageKey,
/// Error when an EvmWord is too big to be converted into a
/// `MemoryAddress`.
WordToMemAddr,
Expand Down
2 changes: 2 additions & 0 deletions eth-types/src/evm_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,13 @@ pub mod memory;
pub mod opcode_ids;
pub mod stack;
pub mod storage;
pub mod transient_storage;

pub use memory::{Memory, MemoryAddress};
pub use opcode_ids::OpcodeId;
pub use stack::{Stack, StackAddress};
pub use storage::Storage;
pub use transient_storage::TransientStorage;

/// According to EIP-3541, disallow new code starting with 0xEF to be deployed.
pub const INVALID_INIT_CODE_FIRST_BYTE: u8 = 0xef;
Expand Down
1 change: 0 additions & 1 deletion eth-types/src/evm_types/opcode_ids.rs
Original file line number Diff line number Diff line change
Expand Up @@ -918,7 +918,6 @@ impl OpcodeId {

impl From<u8> for OpcodeId {
fn from(value: u8) -> Self {
println!("from u8: {}", value);
match value {
0x00u8 => OpcodeId::STOP,
0x01u8 => OpcodeId::ADD,
Expand Down
67 changes: 67 additions & 0 deletions eth-types/src/evm_types/transient_storage.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
//! Doc this
use crate::{DebugWord, Error, ToBigEndian, Word};
use serde::{ser::SerializeMap, Serialize, Serializer};
use std::{collections::HashMap, fmt};

/// Represents a snapshot of the EVM stack state at a certain
/// execution step height.
#[derive(Clone, Eq, PartialEq)]
pub struct TransientStorage(pub HashMap<Word, Word>);

impl<T: Into<HashMap<Word, Word>>> From<T> for TransientStorage {
fn from(map: T) -> Self {
Self(map.into())
}
}

impl fmt::Debug for TransientStorage {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_map()
.entries(self.0.iter().map(|(k, v)| (DebugWord(k), DebugWord(v))))
.finish()
}
}

impl Serialize for TransientStorage {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let mut ser = serializer.serialize_map(Some(self.0.len()))?;
for (k, v) in self.0.iter() {
ser.serialize_entry(&hex::encode(k.to_be_bytes()), &hex::encode(v.to_be_bytes()))?;
}
ser.end()
}
}

impl Default for TransientStorage {
fn default() -> Self {
Self::empty()
}
}

impl TransientStorage {
/// Generate an empty instance of EVM TransientStorage.
pub fn empty() -> Self {
TransientStorage(HashMap::new())
}

/// Generate an new instance of EVM transient storage given a `HashMap<Word, Word>`.
pub fn new(map: HashMap<Word, Word>) -> Self {
Self::from(map)
}

/// Get the word for a given key in the EVM transient storage
pub fn get(&self, key: &Word) -> Option<&Word> {
self.0.get(key)
}

/// Get the word for a given key in the EVM transient storage. Returns error if key
/// is not found.
pub fn get_or_err(&self, key: &Word) -> Result<Word, Error> {
self.get(key)
.cloned()
.ok_or(Error::InvalidTransientStorageKey)
}
}

0 comments on commit 1c1cd7e

Please sign in to comment.