diff --git a/crates/interpreter/src/instructions/host.rs b/crates/interpreter/src/instructions/host.rs index eea5dc20a5..20a2bcfe6c 100644 --- a/crates/interpreter/src/instructions/host.rs +++ b/crates/interpreter/src/instructions/host.rs @@ -5,7 +5,6 @@ use crate::{ Host, InstructionResult, SStoreResult, }; use core::cmp::min; -use revm_primitives::{BLOCKHASH_SERVE_WINDOW, BLOCKHASH_STORAGE_ADDRESS, BLOCK_HASH_HISTORY}; use std::vec::Vec; pub fn balance(interpreter: &mut Interpreter, host: &mut H) { @@ -108,36 +107,11 @@ pub fn blockhash(interpreter: &mut Interpreter, ho pop_top!(interpreter, number); let block_number = host.env().block.number; - - match block_number.checked_sub(*number) { - // blockhash should push zero if number is same as current block number. - Some(diff) if !diff.is_zero() => { - let diff = as_usize_saturated!(diff); - - if SPEC::enabled(PRAGUE) && diff <= BLOCKHASH_SERVE_WINDOW { - let index = number.wrapping_rem(U256::from(BLOCKHASH_SERVE_WINDOW)); - let Some((value, _)) = host.sload(BLOCKHASH_STORAGE_ADDRESS, index) else { - interpreter.instruction_result = InstructionResult::FatalExternalError; - return; - }; - *number = value; - return; - } else if diff <= BLOCK_HASH_HISTORY { - let Some(hash) = host.block_hash(*number) else { - interpreter.instruction_result = InstructionResult::FatalExternalError; - return; - }; - *number = U256::from_be_bytes(hash.0); - return; - } - } - _ => { - // If blockhash is requested for the current block, the hash should be 0, so we fall - // through. - } - } - - *number = U256::ZERO; + let Some(hash) = host.block_hash(block_number) else { + interpreter.instruction_result = InstructionResult::FatalExternalError; + return; + }; + *number = U256::from_be_bytes(hash.0); } pub fn sload(interpreter: &mut Interpreter, host: &mut H) { diff --git a/crates/revm/src/context.rs b/crates/revm/src/context.rs index 343dfcf985..f3c776a01c 100644 --- a/crates/revm/src/context.rs +++ b/crates/revm/src/context.rs @@ -8,11 +8,15 @@ pub use context_precompiles::{ }; pub use evm_context::EvmContext; pub use inner_evm_context::InnerEvmContext; +use revm_interpreter::as_usize_saturated; use crate::{ db::{Database, EmptyDB}, interpreter::{Host, LoadAccountResult, SStoreResult, SelfDestructResult}, - primitives::{Address, Bytecode, Env, HandlerCfg, Log, B256, U256}, + primitives::{ + Address, Bytecode, EVMError, Env, HandlerCfg, Log, B256, BLOCKHASH_SERVE_WINDOW, + BLOCKHASH_STORAGE_ADDRESS, BLOCK_HASH_HISTORY, PRAGUE, U256, + }, }; use std::boxed::Box; @@ -106,10 +110,40 @@ impl Host for Context { } fn block_hash(&mut self, number: U256) -> Option { - self.evm - .block_hash(number) - .map_err(|e| self.evm.error = Err(e)) - .ok() + let block_number = self.env().block.number; + + match block_number.checked_sub(number) { + // blockhash should push zero if number is same as current block number. + Some(diff) if !diff.is_zero() => { + let diff = as_usize_saturated!(diff); + + if diff <= BLOCK_HASH_HISTORY { + return self + .evm + .block_hash(number) + .map_err(|e| self.evm.error = Err(e)) + .ok(); + } + + if self.evm.journaled_state.spec.is_enabled_in(PRAGUE) + && diff <= BLOCKHASH_SERVE_WINDOW + { + let index = number.wrapping_rem(U256::from(BLOCKHASH_SERVE_WINDOW)); + return self + .evm + .db + .storage(BLOCKHASH_STORAGE_ADDRESS, index) + .map_err(|e| self.evm.error = Err(EVMError::Database(e))) + .ok() + .map(|v| v.into()); + } + } + _ => { + // If blockhash is requested for the current block, the hash should be 0, so we fall + // through. + } + } + Some(B256::ZERO) } fn load_account(&mut self, address: Address) -> Option {