From 81acfe3d12c01cac19719f822ad731221a308aed Mon Sep 17 00:00:00 2001 From: rakita Date: Fri, 12 Jul 2024 20:51:10 +0200 Subject: [PATCH] feat(EOF): Bytecode::new_raw supports EOF, new_raw_checked added (#1607) * feat(EOF): Bytecode::new_raw supports EOF, new_raw_checked added * Use from abbreviation --- bins/revme/src/cmd/evmrunner.rs | 18 ++++++--------- bins/revme/src/cmd/statetest/runner.rs | 11 +++------ crates/primitives/src/bytecode.rs | 19 ++++++++++++++- crates/primitives/src/bytecode/eof.rs | 32 +++++++++++++++++++++++++- crates/revm/src/builder.rs | 8 +++---- 5 files changed, 63 insertions(+), 25 deletions(-) diff --git a/bins/revme/src/cmd/evmrunner.rs b/bins/revme/src/cmd/evmrunner.rs index 50a75a8deb..86d3817a69 100644 --- a/bins/revme/src/cmd/evmrunner.rs +++ b/bins/revme/src/cmd/evmrunner.rs @@ -2,7 +2,7 @@ use revm::{ db::BenchmarkDB, inspector_handle_register, inspectors::TracerEip3155, - primitives::{Address, Bytecode, TxKind}, + primitives::{eof::EofDecodeError, Address, Bytecode, TxKind}, Evm, }; use std::io::Error as IoError; @@ -24,13 +24,9 @@ pub enum Errors { #[error("EVM Error")] EVMError, #[error(transparent)] - Io(IoError), -} - -impl From for Errors { - fn from(e: IoError) -> Self { - Errors::Io(e) - } + Io(#[from] IoError), + #[error(transparent)] + EofError(#[from] EofDecodeError), } /// Evm runner command allows running arbitrary evm bytecode. @@ -59,7 +55,7 @@ pub struct Cmd { } impl Cmd { - /// Run statetest command. + /// Run evm runner command. pub fn run(&self) -> Result<(), Errors> { let bytecode_str: Cow<'_, str> = if let Some(path) = &self.path { // check if path exists. @@ -78,9 +74,9 @@ impl Cmd { // BenchmarkDB is dummy state that implements Database trait. // the bytecode is deployed at zero address. let mut evm = Evm::builder() - .with_db(BenchmarkDB::new_bytecode(Bytecode::new_raw( + .with_db(BenchmarkDB::new_bytecode(Bytecode::new_raw_checked( bytecode.into(), - ))) + )?)) .modify_tx_env(|tx| { // execution globals block hash/gas_limit/coinbase/timestamp.. tx.caller = "0x0000000000000000000000000000000000000001" diff --git a/bins/revme/src/cmd/statetest/runner.rs b/bins/revme/src/cmd/statetest/runner.rs index 7ef6ab8833..5102ecae96 100644 --- a/bins/revme/src/cmd/statetest/runner.rs +++ b/bins/revme/src/cmd/statetest/runner.rs @@ -9,8 +9,8 @@ use revm::{ inspector_handle_register, inspectors::TracerEip3155, primitives::{ - calc_excess_blob_gas, keccak256, Bytecode, Bytes, EVMResultGeneric, Env, Eof, - ExecutionResult, SpecId, TxKind, B256, EOF_MAGIC_BYTES, + calc_excess_blob_gas, keccak256, Bytecode, Bytes, EVMResultGeneric, Env, ExecutionResult, + SpecId, TxKind, B256, }, Evm, State, }; @@ -258,12 +258,7 @@ pub fn execute_test_suite( let mut cache_state = revm::CacheState::new(false); for (address, info) in unit.pre { let code_hash = keccak256(&info.code); - let bytecode = match info.code.get(..2) { - Some(magic) if magic == &EOF_MAGIC_BYTES => { - Bytecode::Eof(Eof::decode(info.code.clone()).unwrap().into()) - } - _ => Bytecode::new_raw(info.code), - }; + let bytecode = Bytecode::new_raw(info.code); let acc_info = revm::primitives::AccountInfo { balance: info.balance, code_hash, diff --git a/crates/primitives/src/bytecode.rs b/crates/primitives/src/bytecode.rs index 75abcdd631..a3fe7c5373 100644 --- a/crates/primitives/src/bytecode.rs +++ b/crates/primitives/src/bytecode.rs @@ -1,6 +1,7 @@ pub mod eof; pub mod legacy; +use eof::EofDecodeError; pub use eof::{Eof, EOF_MAGIC, EOF_MAGIC_BYTES, EOF_MAGIC_HASH}; pub use legacy::{JumpTable, LegacyAnalyzedBytecode}; use std::sync::Arc; @@ -68,9 +69,25 @@ impl Bytecode { } /// Creates a new raw [`Bytecode`]. + /// + /// # Panics + /// + /// Panics if bytecode is EOF and has incorrect format. #[inline] pub fn new_raw(bytecode: Bytes) -> Self { - Self::LegacyRaw(bytecode) + Self::new_raw_checked(bytecode).expect("Expect correct EOF bytecode") + } + + /// Creates a new raw [`Bytecode`]. + /// + /// Returns an error on incorrect EOF format. + #[inline] + pub fn new_raw_checked(bytecode: Bytes) -> Result { + if bytecode.get(..2) == Some(&[0xEF, 00]) { + Ok(Self::Eof(Arc::new(Eof::decode(bytecode)?))) + } else { + Ok(Self::LegacyRaw(bytecode)) + } } /// Create new checked bytecode. diff --git a/crates/primitives/src/bytecode/eof.rs b/crates/primitives/src/bytecode/eof.rs index c4d9377f59..1e60120e6e 100644 --- a/crates/primitives/src/bytecode/eof.rs +++ b/crates/primitives/src/bytecode/eof.rs @@ -9,7 +9,7 @@ pub use types_section::TypesSection; use crate::{b256, bytes, Bytes, B256}; use core::cmp::min; -use std::{vec, vec::Vec}; +use std::{fmt, vec, vec::Vec}; /// Hash of EF00 bytes that is used for EXTCODEHASH when called from legacy bytecode. pub const EOF_MAGIC_HASH: B256 = @@ -157,6 +157,36 @@ pub enum EofDecodeError { TooManyContainerSections, } +impl fmt::Display for EofDecodeError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let s = match self { + EofDecodeError::MissingInput => "Short input while processing EOF", + EofDecodeError::MissingBodyWithoutData => "Short body while processing EOF", + EofDecodeError::DanglingData => "Body size is more than specified in the header", + EofDecodeError::InvalidTypesSection => "Invalid types section data", + EofDecodeError::InvalidTypesSectionSize => "Invalid types section size", + EofDecodeError::InvalidEOFMagicNumber => "Invalid EOF magic number", + EofDecodeError::InvalidEOFVersion => "Invalid EOF version", + EofDecodeError::InvalidTypesKind => "Invalid number for types kind", + EofDecodeError::InvalidCodeKind => "Invalid number for code kind", + EofDecodeError::InvalidTerminalByte => "Invalid terminal code", + EofDecodeError::InvalidDataKind => "Invalid data kind", + EofDecodeError::InvalidKindAfterCode => "Invalid kind after code", + EofDecodeError::MismatchCodeAndTypesSize => "Mismatch of code and types sizes", + EofDecodeError::NonSizes => "There should be at least one size", + EofDecodeError::ShortInputForSizes => "Missing size", + EofDecodeError::ZeroSize => "Size cant be zero", + EofDecodeError::TooManyCodeSections => "Invalid code number", + EofDecodeError::ZeroCodeSections => "Invalid number of code sections", + EofDecodeError::TooManyContainerSections => "Invalid container number", + }; + f.write_str(s) + } +} + +#[cfg(feature = "std")] +impl std::error::Error for EofDecodeError {} + #[cfg(test)] mod test { diff --git a/crates/revm/src/builder.rs b/crates/revm/src/builder.rs index 9fc89ebe65..fd4b31d089 100644 --- a/crates/revm/src/builder.rs +++ b/crates/revm/src/builder.rs @@ -460,7 +460,7 @@ mod test { #[test] fn simple_add_stateful_instruction() { - let code = Bytecode::new_raw([0xEF, 0x00].into()); + let code = Bytecode::new_raw([0xED, 0x00].into()); let code_hash = code.hash_slow(); let to_addr = address!("ffffffffffffffffffffffffffffffffffffffff"); @@ -493,7 +493,7 @@ mod test { // can insert the custom instruction as a boxed instruction handler .instruction_table - .insert_boxed(0xEF, custom_instruction); + .insert_boxed(0xED, custom_instruction); })) .build(); @@ -514,7 +514,7 @@ mod test { gas!(interp, CUSTOM_INSTRUCTION_COST); } - let code = Bytecode::new_raw([0xEF, 0x00].into()); + let code = Bytecode::new_raw([0xED, 0x00].into()); let code_hash = code.hash_slow(); let to_addr = address!("ffffffffffffffffffffffffffffffffffffffff"); @@ -525,7 +525,7 @@ mod test { }) .modify_tx_env(|tx| tx.transact_to = TxKind::Call(to_addr)) .append_handler_register(|handler| { - handler.instruction_table.insert(0xEF, custom_instruction) + handler.instruction_table.insert(0xED, custom_instruction) }) .build();