Skip to main content

ethrex_levm/opcode_handlers/
logging.rs

1//! # Logging operations
2//!
3//! Includes the following opcodes:
4//!   - `LOG0` to `LOG4`
5
6use std::mem;
7
8use crate::{
9    errors::{ExceptionalHalt, OpcodeResult, VMError},
10    gas_cost,
11    memory::calculate_memory_size,
12    opcode_handlers::OpcodeHandler,
13    utils::size_offset_to_usize,
14    vm::VM,
15};
16use ethrex_common::{H256, U256, types::Log};
17
18/// Implementation for the `LOGn` opcodes.
19pub struct OpLogHandler<const N: usize>;
20impl<const N: usize> OpcodeHandler for OpLogHandler<N> {
21    #[inline(always)]
22    fn eval(vm: &mut VM<'_>) -> Result<OpcodeResult, VMError> {
23        if vm.current_call_frame.is_static {
24            return Err(ExceptionalHalt::OpcodeNotAllowedInStaticContext.into());
25        }
26
27        let [offset, len] = *vm.current_call_frame.stack.pop()?;
28        let topics = vm.current_call_frame.stack.pop::<N>()?.map(|topic| {
29            #[expect(unsafe_code)]
30            unsafe {
31                let mut hash = mem::transmute::<U256, H256>(topic);
32                hash.0.reverse();
33                hash
34            }
35        });
36        let (len, offset) = size_offset_to_usize(len, offset)?;
37
38        vm.current_call_frame.increase_consumed_gas(gas_cost::log(
39            calculate_memory_size(offset, len)?,
40            vm.current_call_frame.memory.len(),
41            len,
42            N,
43        )?)?;
44
45        let log = Log {
46            address: vm.current_call_frame.to,
47            topics: topics.into(),
48            data: vm.current_call_frame.memory.load_range(offset, len)?,
49        };
50        vm.tracer.log(&log)?;
51        vm.substate.add_log(log);
52
53        Ok(OpcodeResult::Continue)
54    }
55}