Skip to content

Commit

Permalink
fix(eof): fixture 2 tests (#1550)
Browse files Browse the repository at this point in the history
* eof fixes

* fix(eof): create initcode starting with 0xff00

* Include PragueEOF

* spec missing

* add helper function to get address

* clippy

* include box

* move EOF to PragueEOF
  • Loading branch information
rakita authored Jun 20, 2024
1 parent 6e7715a commit 09451cb
Show file tree
Hide file tree
Showing 21 changed files with 284 additions and 243 deletions.
2 changes: 1 addition & 1 deletion bins/revm-test/src/bin/burntpix/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ fn try_from_hex_to_u32(hex: &str) -> eyre::Result<u32> {
}

fn insert_account_info(cache_db: &mut CacheDB<EmptyDB>, addr: Address, code: Bytes) {
let code_hash = hex::encode(keccak256(code.clone()));
let code_hash = hex::encode(keccak256(&code));
let account_info = AccountInfo::new(
U256::from(0),
0,
Expand Down
2 changes: 2 additions & 0 deletions bins/revme/src/cmd/statetest/models/spec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ pub enum SpecName {
Shanghai,
Cancun,
Prague,
PragueEOF,
#[serde(other)]
Unknown,
}
Expand All @@ -46,6 +47,7 @@ impl SpecName {
Self::Shanghai => SpecId::SHANGHAI,
Self::Cancun => SpecId::CANCUN,
Self::Prague => SpecId::PRAGUE,
Self::PragueEOF => SpecId::PRAGUE_EOF,
Self::ByzantiumToConstantinopleAt5 | Self::Constantinople => {
panic!("Overridden with PETERSBURG")
}
Expand Down
58 changes: 45 additions & 13 deletions crates/interpreter/src/instruction_result.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ pub enum InstructionResult {
Revert = 0x10, // revert opcode
CallTooDeep,
OutOfFunds,
/// Revert if CREATE/CREATE2 starts with 0xEF00
CreateInitCodeStartingEF00,
/// Invalid EOF initcode,
InvalidEOFInitCode,

// Actions
CallOrCreate = 0x20,
Expand All @@ -29,7 +33,7 @@ pub enum InstructionResult {
OpcodeNotFound,
CallNotAllowedInsideStatic,
StateChangeDuringStaticCall,
InvalidFEOpcode,
InvalidEFOpcode,
InvalidJump,
NotActivated,
StackUnderflow,
Expand All @@ -53,6 +57,10 @@ pub enum InstructionResult {
EOFOpcodeDisabledInLegacy,
/// EOF function stack overflow
EOFFunctionStackOverflow,
/// Aux data overflow, new aux data is larger tha u16 max size.
EofAuxDataOverflow,
/// Aud data is smaller then already present data size.
EofAuxDataTooSmall,
}

impl From<SuccessReason> for InstructionResult {
Expand All @@ -77,7 +85,7 @@ impl From<HaltReason> for InstructionResult {
OutOfGasError::Precompile => Self::PrecompileOOG,
},
HaltReason::OpcodeNotFound => Self::OpcodeNotFound,
HaltReason::InvalidFEOpcode => Self::InvalidFEOpcode,
HaltReason::InvalidEFOpcode => Self::InvalidEFOpcode,
HaltReason::InvalidJump => Self::InvalidJump,
HaltReason::NotActivated => Self::NotActivated,
HaltReason::StackOverflow => Self::StackOverflow,
Expand All @@ -94,6 +102,9 @@ impl From<HaltReason> for InstructionResult {
HaltReason::CallNotAllowedInsideStatic => Self::CallNotAllowedInsideStatic,
HaltReason::OutOfFunds => Self::OutOfFunds,
HaltReason::CallTooDeep => Self::CallTooDeep,
HaltReason::EofAuxDataOverflow => Self::EofAuxDataOverflow,
HaltReason::EofAuxDataTooSmall => Self::EofAuxDataTooSmall,
HaltReason::EOFFunctionStackOverflow => Self::EOFFunctionStackOverflow,
#[cfg(feature = "optimism")]
HaltReason::FailedDeposit => Self::FatalExternalError,
}
Expand All @@ -114,7 +125,11 @@ macro_rules! return_ok {
#[macro_export]
macro_rules! return_revert {
() => {
InstructionResult::Revert | InstructionResult::CallTooDeep | InstructionResult::OutOfFunds
InstructionResult::Revert
| InstructionResult::CallTooDeep
| InstructionResult::OutOfFunds
| InstructionResult::InvalidEOFInitCode
| InstructionResult::CreateInitCodeStartingEF00
};
}

Expand All @@ -129,7 +144,7 @@ macro_rules! return_error {
| InstructionResult::OpcodeNotFound
| InstructionResult::CallNotAllowedInsideStatic
| InstructionResult::StateChangeDuringStaticCall
| InstructionResult::InvalidFEOpcode
| InstructionResult::InvalidEFOpcode
| InstructionResult::InvalidJump
| InstructionResult::NotActivated
| InstructionResult::StackUnderflow
Expand All @@ -146,6 +161,8 @@ macro_rules! return_error {
| InstructionResult::ReturnContractInNotInitEOF
| InstructionResult::EOFOpcodeDisabledInLegacy
| InstructionResult::EOFFunctionStackOverflow
| InstructionResult::EofAuxDataTooSmall
| InstructionResult::EofAuxDataOverflow
};
}

Expand All @@ -169,16 +186,24 @@ impl InstructionResult {
}
}

/// Internal result that are not ex
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum InternalResult {
/// Internal instruction that signals Interpreter should continue running.
InternalContinue,
/// Internal instruction that signals call or create.
InternalCallOrCreate,
/// Internal CREATE/CREATE starts with 0xEF00
CreateInitCodeStartingEF00,
}

#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum SuccessOrHalt {
Success(SuccessReason),
Revert,
Halt(HaltReason),
FatalExternalError,
/// Internal instruction that signals Interpreter should continue running.
InternalContinue,
/// Internal instruction that signals call or create.
InternalCallOrCreate,
Internal(InternalResult),
}

impl SuccessOrHalt {
Expand Down Expand Up @@ -222,12 +247,13 @@ impl SuccessOrHalt {
impl From<InstructionResult> for SuccessOrHalt {
fn from(result: InstructionResult) -> Self {
match result {
InstructionResult::Continue => Self::InternalContinue, // used only in interpreter loop
InstructionResult::Continue => Self::Internal(InternalResult::InternalContinue), // used only in interpreter loop
InstructionResult::Stop => Self::Success(SuccessReason::Stop),
InstructionResult::Return => Self::Success(SuccessReason::Return),
InstructionResult::SelfDestruct => Self::Success(SuccessReason::SelfDestruct),
InstructionResult::Revert => Self::Revert,
InstructionResult::CallOrCreate => Self::InternalCallOrCreate, // used only in interpreter loop
InstructionResult::CreateInitCodeStartingEF00 => Self::Revert,
InstructionResult::CallOrCreate => Self::Internal(InternalResult::InternalCallOrCreate), // used only in interpreter loop
InstructionResult::CallTooDeep => Self::Halt(HaltReason::CallTooDeep), // not gonna happen for first call
InstructionResult::OutOfFunds => Self::Halt(HaltReason::OutOfFunds), // Check for first call is done separately.
InstructionResult::OutOfGas => Self::Halt(HaltReason::OutOfGas(OutOfGasError::Basic)),
Expand All @@ -250,7 +276,7 @@ impl From<InstructionResult> for SuccessOrHalt {
InstructionResult::StateChangeDuringStaticCall => {
Self::Halt(HaltReason::StateChangeDuringStaticCall)
}
InstructionResult::InvalidFEOpcode => Self::Halt(HaltReason::InvalidFEOpcode),
InstructionResult::InvalidEFOpcode => Self::Halt(HaltReason::InvalidEFOpcode),
InstructionResult::InvalidJump => Self::Halt(HaltReason::InvalidJump),
InstructionResult::NotActivated => Self::Halt(HaltReason::NotActivated),
InstructionResult::StackUnderflow => Self::Halt(HaltReason::StackUnderflow),
Expand All @@ -267,10 +293,16 @@ impl From<InstructionResult> for SuccessOrHalt {
InstructionResult::CreateInitCodeSizeLimit => {
Self::Halt(HaltReason::CreateInitCodeSizeLimit)
}
// TODO (EOF) add proper Revert subtype.
InstructionResult::InvalidEOFInitCode => Self::Revert,
InstructionResult::FatalExternalError => Self::FatalExternalError,
InstructionResult::EOFOpcodeDisabledInLegacy => Self::Halt(HaltReason::OpcodeNotFound),
InstructionResult::EOFFunctionStackOverflow => Self::FatalExternalError,
InstructionResult::EOFFunctionStackOverflow => {
Self::Halt(HaltReason::EOFFunctionStackOverflow)
}
InstructionResult::ReturnContract => Self::Success(SuccessReason::EofReturnContract),
InstructionResult::EofAuxDataOverflow => Self::Halt(HaltReason::EofAuxDataOverflow),
InstructionResult::EofAuxDataTooSmall => Self::Halt(HaltReason::EofAuxDataTooSmall),
}
}
}
Expand Down Expand Up @@ -325,7 +357,7 @@ mod tests {
InstructionResult::OpcodeNotFound,
InstructionResult::CallNotAllowedInsideStatic,
InstructionResult::StateChangeDuringStaticCall,
InstructionResult::InvalidFEOpcode,
InstructionResult::InvalidEFOpcode,
InstructionResult::InvalidJump,
InstructionResult::NotActivated,
InstructionResult::StackUnderflow,
Expand Down
31 changes: 20 additions & 11 deletions crates/interpreter/src/instructions/contract.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
mod call_helpers;

pub use call_helpers::{calc_call_gas, get_memory_input_and_out_ranges, resize_memory};
use revm_primitives::{keccak256, BerlinSpec};

use crate::{
gas::{self, cost_per_word, EOF_CREATE_GAS, KECCAK256WORD},
interpreter::Interpreter,
primitives::{Address, Bytes, Eof, Spec, SpecId::*, U256},
primitives::{
eof::EofHeader, keccak256, Address, BerlinSpec, Bytes, Eof, Spec, SpecId::*, U256,
},
CallInputs, CallScheme, CallValue, CreateInputs, CreateScheme, EOFCreateInputs, Host,
InstructionResult, InterpreterAction, InterpreterResult, LoadAccountResult, MAX_INITCODE_SIZE,
};
Expand Down Expand Up @@ -67,7 +68,7 @@ pub fn eofcreate<H: Host + ?Sized>(interpreter: &mut Interpreter, _host: &mut H)
// Send container for execution container is preverified.
interpreter.instruction_result = InstructionResult::CallOrCreate;
interpreter.next_action = InterpreterAction::EOFCreate {
inputs: Box::new(EOFCreateInputs::new(
inputs: Box::new(EOFCreateInputs::new_opcode(
interpreter.contract.target_address,
created_address,
value,
Expand All @@ -92,10 +93,11 @@ pub fn return_contract<H: Host + ?Sized>(interpreter: &mut Interpreter, _host: &
.body
.container_section
.get(deploy_container_index as usize)
.expect("EOF is checked");
.expect("EOF is checked")
.clone();

// convert to EOF so we can check data section size.
let new_eof = Eof::decode(container.clone()).expect("Container is verified");
let (eof_header, _) = EofHeader::decode(&container).expect("valid EOF header");

let aux_slice = if aux_data_size != 0 {
let aux_data_offset = as_usize_or_fail!(interpreter, aux_data_offset);
Expand All @@ -108,20 +110,27 @@ pub fn return_contract<H: Host + ?Sized>(interpreter: &mut Interpreter, _host: &
&[]
};

let new_data_size = new_eof.body.data_section.len() + aux_slice.len();
let static_aux_size = eof_header.eof_size() - container.len();

// data_size - static_aux_size give us current data `container` size.
// and with aux_slice len we can calculate new data size.
let new_data_size = eof_header.data_size as usize - static_aux_size + aux_slice.len();
if new_data_size > 0xFFFF {
// aux data is too big
interpreter.instruction_result = InstructionResult::FatalExternalError;
interpreter.instruction_result = InstructionResult::EofAuxDataOverflow;
return;
}
if new_data_size < new_eof.header.data_size as usize {
if new_data_size < eof_header.data_size as usize {
// aux data is too small
interpreter.instruction_result = InstructionResult::FatalExternalError;
interpreter.instruction_result = InstructionResult::EofAuxDataTooSmall;
return;
}
let new_data_size = (new_data_size as u16).to_be_bytes();

// append data bytes
let output = [new_eof.raw(), aux_slice].concat().into();
let mut output = [&container, aux_slice].concat();
// set new data size in eof bytes as we know exact index.
output[eof_header.data_size_raw_i()..][..2].clone_from_slice(&new_data_size);
let output: Bytes = output.into();

let result = InstructionResult::ReturnContract;
interpreter.instruction_result = result;
Expand Down
2 changes: 1 addition & 1 deletion crates/interpreter/src/instructions/control.rs
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ pub fn stop<H: Host + ?Sized>(interpreter: &mut Interpreter, _host: &mut H) {

/// Invalid opcode. This opcode halts the execution.
pub fn invalid<H: Host + ?Sized>(interpreter: &mut Interpreter, _host: &mut H) {
interpreter.instruction_result = InstructionResult::InvalidFEOpcode;
interpreter.instruction_result = InstructionResult::InvalidEFOpcode;
}

/// Unknown opcode. This opcode halts the execution.
Expand Down
8 changes: 5 additions & 3 deletions crates/interpreter/src/interpreter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ pub use contract::Contract;
pub use shared_memory::{num_words, SharedMemory, EMPTY_SHARED_MEMORY};
pub use stack::{Stack, STACK_LIMIT};

use crate::EOFCreateOutcome;
use crate::{
gas, primitives::Bytes, push, push_b256, return_ok, return_revert, CallOutcome, CreateOutcome,
FunctionStack, Gas, Host, InstructionResult, InterpreterAction,
Expand Down Expand Up @@ -192,7 +191,7 @@ impl Interpreter {
}
}

pub fn insert_eofcreate_outcome(&mut self, create_outcome: EOFCreateOutcome) {
pub fn insert_eofcreate_outcome(&mut self, create_outcome: CreateOutcome) {
self.instruction_result = InstructionResult::Continue;
let instruction_result = create_outcome.instruction_result();

Expand All @@ -206,7 +205,10 @@ impl Interpreter {

match instruction_result {
InstructionResult::ReturnContract => {
push_b256!(self, create_outcome.address.into_word());
push_b256!(
self,
create_outcome.address.expect("EOF Address").into_word()
);
self.gas.erase_cost(create_outcome.gas().remaining());
self.gas.record_refund(create_outcome.gas().refunded());
}
Expand Down
4 changes: 1 addition & 3 deletions crates/interpreter/src/interpreter_action.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,12 @@ mod call_outcome;
mod create_inputs;
mod create_outcome;
mod eof_create_inputs;
mod eof_create_outcome;

pub use call_inputs::{CallInputs, CallScheme, CallValue};
pub use call_outcome::CallOutcome;
pub use create_inputs::{CreateInputs, CreateScheme};
pub use create_outcome::CreateOutcome;
pub use eof_create_inputs::EOFCreateInputs;
pub use eof_create_outcome::EOFCreateOutcome;
pub use eof_create_inputs::{EOFCreateInputs, EOFCreateKind};

use crate::InterpreterResult;
use std::boxed::Box;
Expand Down
Loading

0 comments on commit 09451cb

Please sign in to comment.