Skip to content

Commit

Permalink
fix(levm): initialization of transient storage (#1540)
Browse files Browse the repository at this point in the history
**Motivation**

Each time we moved to a new context, we were overwriting the previous
transient storage. Also add a check in `tstore` to see if the `tx` is
static.

**Description**

- Add a new parameter to `CallFrame::new()`. Now we can send the current
value of `transient_storage` to the subcontext.
- Check in `tstore` if the `tx` is static. In that case it must returns
an error.

We can also think about moving the `TransientStorage` from `CallFrame`
to the `Environment`, since it is a storage of the tx.

**Reference**
[EIP-1153](https://eips.ethereum.org/EIPS/eip-1153): _If the TSTORE
opcode is called within the context of a STATICCALL, it will result in
an exception instead of performing the modification. TLOAD is allowed
within the context of a STATICCALL._
  • Loading branch information
damiramirez authored Dec 20, 2024
1 parent be61c69 commit e6917e9
Show file tree
Hide file tree
Showing 6 changed files with 26 additions and 25 deletions.
1 change: 1 addition & 0 deletions cmd/ef_tests/levm/runner/levm_runner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ pub fn prepare_vm_for_tx(vector: &TestVector, test: &EFTest) -> Result<VM, EFTes
tx_max_fee_per_gas: tx.max_fee_per_gas,
tx_max_fee_per_blob_gas: tx.max_fee_per_blob_gas,
block_gas_limit: test.env.current_gas_limit,
transient_storage: HashMap::new(),
},
tx.value,
tx.data.clone(),
Expand Down
6 changes: 1 addition & 5 deletions crates/vm/levm/src/call_frame.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,7 @@ use crate::{
};
use bytes::Bytes;
use ethrex_core::{types::Log, Address, U256};
use std::collections::{HashMap, HashSet};

/// [EIP-1153]: https://eips.ethereum.org/EIPS/eip-1153#reference-implementation
pub type TransientStorage = HashMap<(Address, U256), U256>;
use std::collections::HashSet;

#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct Stack {
Expand Down Expand Up @@ -81,7 +78,6 @@ pub struct CallFrame {
pub sub_return_data: Bytes,
/// Indicates if current context is static (if it is, it can't change state)
pub is_static: bool,
pub transient_storage: TransientStorage,
pub logs: Vec<Log>,
/// Call stack current depth
pub depth: usize,
Expand Down
7 changes: 7 additions & 0 deletions crates/vm/levm/src/environment.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
use std::collections::HashMap;

use ethrex_core::{Address, H256, U256};

/// [EIP-1153]: https://eips.ethereum.org/EIPS/eip-1153#reference-implementation
pub type TransientStorage = HashMap<(Address, U256), U256>;

#[derive(Debug, Default, Clone)]
pub struct Environment {
/// The sender address of the transaction that originated
Expand All @@ -21,6 +26,7 @@ pub struct Environment {
pub tx_max_fee_per_gas: Option<U256>,
pub tx_max_fee_per_blob_gas: Option<U256>,
pub block_gas_limit: U256,
pub transient_storage: TransientStorage,
}

impl Environment {
Expand All @@ -43,6 +49,7 @@ impl Environment {
tx_max_fee_per_gas: Default::default(),
tx_max_fee_per_blob_gas: Default::default(),
block_gas_limit: Default::default(),
transient_storage: Default::default(),
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ impl VM {
self.increase_consumed_gas(current_call_frame, gas_cost::TLOAD)?;

let key = current_call_frame.stack.pop()?;
let value = current_call_frame
let value = self
.env
.transient_storage
.get(&(current_call_frame.msg_sender, key))
.cloned()
Expand All @@ -44,9 +45,13 @@ impl VM {
) -> Result<OpcodeSuccess, VMError> {
self.increase_consumed_gas(current_call_frame, gas_cost::TSTORE)?;

if current_call_frame.is_static {
return Err(VMError::OpcodeNotAllowedInStaticContext);
}

let key = current_call_frame.stack.pop()?;
let value = current_call_frame.stack.pop()?;
current_call_frame
self.env
.transient_storage
.insert((current_call_frame.msg_sender, key), value);

Expand Down
27 changes: 9 additions & 18 deletions crates/vm/levm/tests/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ use ethrex_levm::{
vm::{word_to_address, Storage, VM},
Environment,
};
use std::{collections::HashMap, sync::Arc};
use std::{borrow::BorrowMut, collections::HashMap, sync::Arc};

fn create_opcodes(size: usize, offset: usize, value_to_transfer: usize) -> Vec<Operation> {
vec![
Expand Down Expand Up @@ -3728,20 +3728,18 @@ fn transient_store() {

let mut vm = new_vm_with_ops(&operations).unwrap();

let current_call_frame = vm.current_call_frame_mut().unwrap();

assert!(current_call_frame.transient_storage.is_empty());
{
let env_mut = vm.env.borrow_mut();
assert!(env_mut.transient_storage.is_empty());
}

let mut current_call_frame = vm.call_frames.pop().unwrap();
vm.execute(&mut current_call_frame).unwrap();

let current_call_frame = vm.current_call_frame_mut().unwrap();
let msg_sender = current_call_frame.msg_sender;

assert_eq!(
*current_call_frame
.transient_storage
.get(&(current_call_frame.msg_sender, key))
.unwrap(),
*vm.env.transient_storage.get(&(msg_sender, key)).unwrap(),
value
)
}
Expand All @@ -3751,11 +3749,7 @@ fn transient_store_stack_underflow() {
let operations = [Operation::Tstore, Operation::Stop];

let mut vm = new_vm_with_ops(&operations).unwrap();
assert!(vm
.current_call_frame_mut()
.unwrap()
.transient_storage
.is_empty());
assert!(vm.env.transient_storage.is_empty());

let mut current_call_frame = vm.call_frames.pop().unwrap();
let tx_report = vm.execute(&mut current_call_frame).unwrap();
Expand All @@ -3781,10 +3775,7 @@ fn transient_load() {

let caller = vm.current_call_frame_mut().unwrap().msg_sender;

vm.current_call_frame_mut()
.unwrap()
.transient_storage
.insert((caller, key), value);
vm.env.transient_storage.insert((caller, key), value);

let mut current_call_frame = vm.call_frames.pop().unwrap();
vm.execute(&mut current_call_frame).unwrap();
Expand Down
1 change: 1 addition & 0 deletions crates/vm/vm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,7 @@ cfg_if::cfg_if! {
tx_max_fee_per_gas: tx.max_fee_per_gas().map(U256::from),
tx_max_fee_per_blob_gas: tx.max_fee_per_blob_gas().map(U256::from),
block_gas_limit: block_header.gas_limit.into(),
transient_storage: HashMap::new(),
};

let mut vm = VM::new(
Expand Down

0 comments on commit e6917e9

Please sign in to comment.