Skip to content

Commit

Permalink
feat: (levm) Implement different call types (lambdaclass#583)
Browse files Browse the repository at this point in the history
**Motivation**

Implement `CALLCODE`, `DELEGATECALL` and `STATICCALL`

**Description**
- `CALL`, `STATICCALL`, `DELEGATECALL` and `CALLCODE` are similar but
have some key differences, for example:
1) `StaticCall` does the same as `Call`, but changes the config of the
`CallFrame` to be static
2) `DelegateCall` is used to execute code from another contract, but
changing the storage of the actual address. This is done by having an
`Option<Address>` in the `CallFrame`. `CallCode` does the same as
`DelegateCall` but changes value and msg_sender.
- Created the `generic_call` function to provide a standard on
performing calls.

more info in [EVM Deep
Dives](https://noxx.substack.com/p/evm-deep-dives-the-path-to-shadowy-a5f?utm_source=%2Fprofile%2F80455042-noxx&utm_medium=reader2&s=r)

Closes lambdaclass#530 
Closes lambdaclass#532 
Closes lambdaclass#534

---------

Co-authored-by: Paolo Belforte <[email protected]>
Co-authored-by: Paolo Belforte <[email protected]>
Co-authored-by: Juan Ignacio Medone Sabatini <[email protected]>
  • Loading branch information
4 people authored and emirongrr committed Nov 10, 2024
1 parent 31b7e27 commit 3fa62d6
Show file tree
Hide file tree
Showing 8 changed files with 612 additions and 155 deletions.
1 change: 1 addition & 0 deletions crates/levm/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ethtests
37 changes: 32 additions & 5 deletions crates/levm/src/call_frame.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,15 @@ pub struct Log {
pub data: Bytes,
}

#[derive(Debug, Clone, Default)]
#[derive(Debug, Clone, Default, PartialEq)]
pub struct CallFrame {
pub gas: U256,
pub pc: usize,
pub msg_sender: Address,
pub callee: Address,
pub bytecode: Bytes,
pub to: Address,
pub code_address: Address,
pub delegate: Option<Address>,
pub bytecode: Bytes,
pub msg_value: U256,
pub stack: Vec<U256>, // max 1024 in the future
pub memory: Memory,
Expand All @@ -34,15 +35,41 @@ pub struct CallFrame {
// where to store return data of subcall
pub return_data_offset: Option<usize>,
pub return_data_size: Option<usize>,
pub is_static: bool,
pub transient_storage: TransientStorage,
pub logs: Vec<Log>,
pub is_static: bool,
}

impl CallFrame {
pub fn new(bytecode: Bytes) -> Self {
pub fn new_from_bytecode(bytecode: Bytes) -> Self {
Self {
bytecode,
..Default::default()
}
}

#[allow(clippy::too_many_arguments)]
pub fn new(
gas: U256,
msg_sender: Address,
to: Address,
code_address: Address,
delegate: Option<Address>,
bytecode: Bytes,
msg_value: U256,
calldata: Bytes,
is_static: bool,
) -> Self {
Self {
gas,
msg_sender,
to,
code_address,
delegate,
bytecode,
msg_value,
calldata,
is_static,
..Default::default()
}
}
Expand Down
6 changes: 5 additions & 1 deletion crates/levm/src/memory.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::primitives::U256;

#[derive(Debug, Clone, Default)]
#[derive(Debug, Clone, Default, PartialEq)]
pub struct Memory {
data: Vec<u8>,
}
Expand All @@ -16,6 +16,10 @@ impl Memory {
Self { data: Vec::new() }
}

pub fn new_from_vec(data: Vec<u8>) -> Self {
Self { data }
}

fn resize(&mut self, offset: usize) {
if offset.next_multiple_of(32) > self.data.len() {
self.data.resize(offset.next_multiple_of(32), 0);
Expand Down
9 changes: 6 additions & 3 deletions crates/levm/src/opcodes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -158,11 +158,11 @@ pub enum Opcode {
// // System Operations
// CREATE = 0xF0,
CALL = 0xF1,
// CALLCODE = 0xF2,
CALLCODE = 0xF2,
RETURN = 0xF3,
// DELEGATECALL = 0xF4,
DELEGATECALL = 0xF4,
// CREATE2 = 0xF5,
// STATICCALL = 0xFA,
STATICCALL = 0xFA,
// REVERT = 0xFD,
// INVALID = 0xFE,
// SELFDESTRUCT = 0xFF,
Expand Down Expand Up @@ -301,7 +301,10 @@ impl From<u8> for Opcode {
x if x == Opcode::TLOAD as u8 => Opcode::TLOAD,
x if x == Opcode::TSTORE as u8 => Opcode::TSTORE,
0xF1 => Opcode::CALL,
0xF2 => Opcode::CALLCODE,
0xF3 => Opcode::RETURN,
0xF4 => Opcode::DELEGATECALL,
0xFA => Opcode::STATICCALL,
_ => panic!("Unknown opcode: 0x{:02X}", byte),
}
}
Expand Down
12 changes: 6 additions & 6 deletions crates/levm/src/operations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,11 +91,11 @@ pub enum Operation {
Log(u8),
// Create,
Call,
// CallCode,
CallCode,
Return,
// DelegateCall,
DelegateCall,
// Create2,
// StaticCall,
StaticCall,
// Revert,
// Invalid,
// SelfDestruct,
Expand Down Expand Up @@ -222,11 +222,11 @@ impl Operation {
Bytes::copy_from_slice(&[Opcode::LOG0 as u8 + n])
} // Operation::Create => Bytes::copy_from_slice(&[Opcode::CREATE as u8]),
Operation::Call => Bytes::copy_from_slice(&[Opcode::CALL as u8]),
// Operation::CallCode => Bytes::copy_from_slice(&[Opcode::CALLCODE as u8]),
Operation::CallCode => Bytes::copy_from_slice(&[Opcode::CALLCODE as u8]),
Operation::Return => Bytes::copy_from_slice(&[Opcode::RETURN as u8]),
// Operation::DelegateCall => Bytes::copy_from_slice(&[Opcode::DELEGATECALL as u8]),
Operation::DelegateCall => Bytes::copy_from_slice(&[Opcode::DELEGATECALL as u8]),
// Operation::Create2 => Bytes::copy_from_slice(&[Opcode::CREATE2 as u8]),
// Operation::StaticCall => Bytes::copy_from_slice(&[Opcode::STATICCALL as u8]),
Operation::StaticCall => Bytes::copy_from_slice(&[Opcode::STATICCALL as u8]),
// Operation::Revert => Bytes::copy_from_slice(&[Opcode::REVERT as u8]),
// Operation::Invalid => Bytes::copy_from_slice(&[Opcode::INVALID as u8]),
// Operation::SelfDestruct => Bytes::copy_from_slice(&[Opcode::SELFDESTRUCT as u8]),
Expand Down
2 changes: 1 addition & 1 deletion crates/levm/src/primitives.rs
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
pub use bytes::Bytes;
pub use ethereum_types::{Address, H160, H256, U256, U512};
pub use ethereum_types::{Address, H160, H256, H32, U256, U512};
Loading

0 comments on commit 3fa62d6

Please sign in to comment.