Skip to content

Commit

Permalink
Add bytecode hash in interpreter bluealloy#1888 (bluealloy#1952)
Browse files Browse the repository at this point in the history
* add bytecode hash to interpreter

* fmt

* lazy setting bytecode_hash to prevent performance degradation

* move hash to extended bytecode

* remove trait bound

* Update crates/interpreter/src/interpreter/ext_bytecode.rs

* Update crates/interpreter/src/interpreter/ext_bytecode.rs

* Update crates/interpreter/src/interpreter/ext_bytecode.rs

* fix tests

* set hash for interpreter
  • Loading branch information
FredCoen authored Dec 31, 2024
1 parent d2a3b5b commit e3c7abf
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 22 deletions.
20 changes: 9 additions & 11 deletions crates/handler/src/frame.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use core::{cell::RefCell, cmp::min};
use handler_interface::{Frame, FrameOrResultGen, PrecompileProvider};
use interpreter::{
gas,
interpreter::{EthInterpreter, InstructionProvider},
interpreter::{EthInterpreter, ExtBytecode, InstructionProvider},
interpreter_types::{LoopControl, ReturnData, RuntimeFlag},
return_ok, return_revert, CallInputs, CallOutcome, CallValue, CreateInputs, CreateOutcome,
CreateScheme, EOFCreateInputs, EOFCreateKind, FrameInput, Gas, Host, InputsImpl,
Expand Down Expand Up @@ -147,8 +147,7 @@ where
.journal()
.load_account_code(inputs.bytecode_address)?;

// TODO : Request from foundry to get bytecode hash.
let _code_hash = account.info.code_hash();
let mut code_hash = account.info.code_hash();
let mut bytecode = account.info.code.clone().unwrap_or_default();

// ExtDelegateCall is not allowed to call non-EOF contracts.
Expand All @@ -164,13 +163,12 @@ where
}

if let Bytecode::Eip7702(eip7702_bytecode) = bytecode {
bytecode = context
let account = &context
.journal()
.load_account_code(eip7702_bytecode.delegated_address)?
.info
.code
.clone()
.unwrap_or_default();
.info;
bytecode = account.code.clone().unwrap_or_default();
code_hash = account.code_hash();
}

// Create interpreter and executes call and push new CallStackFrame.
Expand All @@ -188,7 +186,7 @@ where
depth,
Interpreter::new(
memory.clone(),
bytecode,
ExtBytecode::new_with_hash(bytecode, code_hash),
interpreter_input,
inputs.is_static,
false,
Expand Down Expand Up @@ -281,7 +279,7 @@ where
Err(e) => return return_error(e.into()),
};

let bytecode = Bytecode::new_legacy(inputs.init_code.clone());
let bytecode = ExtBytecode::new(Bytecode::new_legacy(inputs.init_code.clone()));

let interpreter_input = InputsImpl {
target_address: created_address,
Expand Down Expand Up @@ -412,7 +410,7 @@ where
depth,
Interpreter::new(
memory.clone(),
Bytecode::Eof(Arc::new(initcode)),
ExtBytecode::new(Bytecode::Eof(Arc::new(initcode))),
interpreter_input,
false,
true,
Expand Down
11 changes: 4 additions & 7 deletions crates/interpreter/src/interpreter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,6 @@ use crate::{
interpreter_types::*, table::CustomInstruction, Gas, Host, Instruction, InstructionResult,
InterpreterAction,
};
use bytecode::Bytecode;

use core::cell::RefCell;
pub use ext_bytecode::ExtBytecode;
pub use input::InputsImpl;
Expand Down Expand Up @@ -46,7 +44,7 @@ impl<EXT: Default, MG: MemoryGetter> Interpreter<EthInterpreter<EXT, MG>> {
/// Create new interpreter
pub fn new(
memory: Rc<RefCell<MG>>,
bytecode: Bytecode,
bytecode: ExtBytecode,
inputs: InputsImpl,
is_static: bool,
is_eof_init: bool,
Expand All @@ -59,8 +57,9 @@ impl<EXT: Default, MG: MemoryGetter> Interpreter<EthInterpreter<EXT, MG>> {
is_eof: bytecode.is_eof(),
is_eof_init,
};

Self {
bytecode: ExtBytecode::new(bytecode),
bytecode,
stack: Stack::new(),
return_data: ReturnDataImpl::default(),
memory,
Expand Down Expand Up @@ -289,16 +288,14 @@ mod tests {
use super::*;
use bytecode::Bytecode;
use primitives::{Address, Bytes, U256};
use specification::hardfork::SpecId;
use std::{cell::RefCell, rc::Rc};

#[test]
#[cfg(feature = "serde")]
fn test_interpreter_serde() {
let bytecode = Bytecode::new_raw(Bytes::from(&[0x60, 0x00, 0x60, 0x00, 0x01][..]));
let interpreter = Interpreter::<EthInterpreter>::new(
Rc::new(RefCell::new(SharedMemory::new())),
bytecode,
ExtBytecode::new(bytecode),
InputsImpl {
target_address: Address::ZERO,
caller_address: Address::ZERO,
Expand Down
48 changes: 45 additions & 3 deletions crates/interpreter/src/interpreter/ext_bytecode.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
use core::ops::Deref;

use bytecode::{
eof::TypesSection,
utils::{read_i16, read_u16},
Bytecode,
};
use primitives::Bytes;
use primitives::{Bytes, B256};

use super::{EofCodeInfo, EofContainer, EofData, Immediates, Jumps, LegacyBytecode};

Expand All @@ -13,11 +15,14 @@ mod serde;
#[derive(Debug)]
pub struct ExtBytecode {
base: Bytecode,
bytecode_hash: Option<B256>,
instruction_pointer: *const u8,
}

impl AsRef<Bytecode> for ExtBytecode {
fn as_ref(&self) -> &Bytecode {
impl Deref for ExtBytecode {
type Target = Bytecode;

fn deref(&self) -> &Self::Target {
&self.base
}
}
Expand All @@ -29,8 +34,31 @@ impl ExtBytecode {
Self {
base,
instruction_pointer,
bytecode_hash: None,
}
}

/// Creates new `ExtBytecode` with the given hash.
pub fn new_with_hash(base: Bytecode, hash: B256) -> Self {
let instruction_pointer = base.bytecode().as_ptr();
Self {
base,
instruction_pointer,
bytecode_hash: Some(hash),
}
}

/// Regenerates the bytecode hash.
pub fn regenerate_hash(&mut self) -> B256 {
let hash = self.base.hash_slow();
self.bytecode_hash = Some(hash);
hash
}

/// Returns the bytecode hash.
pub fn hash(&mut self) -> Option<B256> {
self.bytecode_hash
}
}

impl Jumps for ExtBytecode {
Expand Down Expand Up @@ -164,3 +192,17 @@ impl LegacyBytecode for ExtBytecode {
self.base.original_byte_slice()
}
}

#[cfg(test)]
mod tests {
use super::*;
use primitives::Bytes;

#[test]
fn test_with_hash_constructor() {
let bytecode = Bytecode::new_raw(Bytes::from(&[0x60, 0x00][..]));
let hash = bytecode.hash_slow();
let ext_bytecode = ExtBytecode::new_with_hash(bytecode.clone(), hash);
assert_eq!(ext_bytecode.bytecode_hash, Some(hash));
}
}
10 changes: 9 additions & 1 deletion crates/interpreter/src/interpreter/ext_bytecode/serde.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
use super::ExtBytecode;
use crate::interpreter::Jumps;
use primitives::B256;
use serde::{Deserialize, Deserializer, Serialize, Serializer};

#[derive(Serialize, Deserialize)]
struct ExtBytecodeSerde {
base: bytecode::Bytecode,
program_counter: usize,
bytecode_hash: Option<B256>,
}

impl Serialize for ExtBytecode {
Expand All @@ -16,6 +18,7 @@ impl Serialize for ExtBytecode {
ExtBytecodeSerde {
base: self.base.clone(),
program_counter: self.pc(),
bytecode_hash: self.bytecode_hash,
}
.serialize(serializer)
}
Expand All @@ -29,9 +32,14 @@ impl<'de> Deserialize<'de> for ExtBytecode {
let ExtBytecodeSerde {
base,
program_counter,
bytecode_hash,
} = ExtBytecodeSerde::deserialize(deserializer)?;

let mut bytecode = Self::new(base);
let mut bytecode = if let Some(hash) = bytecode_hash {
Self::new_with_hash(base, hash)
} else {
Self::new(base)
};

if program_counter >= bytecode.base.bytecode().len() {
panic!("serde pc: {program_counter} is greater than or equal to bytecode len");
Expand Down

0 comments on commit e3c7abf

Please sign in to comment.