ethrex_levm/opcode_handlers/
block.rs1use std::mem;
17
18use crate::{
19 constants::LAST_AVAILABLE_BLOCK_LIMIT,
20 errors::{OpcodeResult, VMError},
21 gas_cost,
22 opcode_handlers::OpcodeHandler,
23 utils::*,
24 vm::VM,
25};
26use ethrex_common::U256;
27
28pub struct OpBlockHashHandler;
30impl OpcodeHandler for OpBlockHashHandler {
31 #[inline(always)]
32 fn eval(vm: &mut VM<'_>) -> Result<OpcodeResult, VMError> {
33 vm.current_call_frame
34 .increase_consumed_gas(gas_cost::BLOCKHASH)?;
35
36 #[expect(
40 clippy::arithmetic_side_effects,
41 reason = "subtraction is guarded by take_if range check"
42 )]
43 if let Some(block_number) = u64::try_from(vm.current_call_frame.stack.pop1()?)
44 .ok()
45 .take_if(|&mut block_number| {
46 block_number < vm.env.block_number
47 && vm.env.block_number - block_number <= LAST_AVAILABLE_BLOCK_LIMIT
48 })
49 {
50 #[expect(unsafe_code, reason = "safe")]
51 vm.current_call_frame.stack.push(unsafe {
52 let mut bytes = vm.db.store.get_block_hash(block_number)?.0;
53 bytes.reverse();
54 U256(mem::transmute_copy::<[u8; 32], [u64; 4]>(&bytes))
55 })?;
56 } else {
57 vm.current_call_frame.stack.push_zero()?;
58 }
59
60 Ok(OpcodeResult::Continue)
61 }
62}
63
64pub struct OpCoinbaseHandler;
66impl OpcodeHandler for OpCoinbaseHandler {
67 #[inline(always)]
68 fn eval(vm: &mut VM<'_>) -> Result<OpcodeResult, VMError> {
69 vm.current_call_frame
70 .increase_consumed_gas(gas_cost::COINBASE)?;
71
72 vm.current_call_frame
73 .stack
74 .push(address_to_word(vm.env.coinbase))?;
75
76 Ok(OpcodeResult::Continue)
77 }
78}
79
80pub struct OpTimestampHandler;
82impl OpcodeHandler for OpTimestampHandler {
83 #[inline(always)]
84 fn eval(vm: &mut VM<'_>) -> Result<OpcodeResult, VMError> {
85 vm.current_call_frame
86 .increase_consumed_gas(gas_cost::TIMESTAMP)?;
87
88 vm.current_call_frame.stack.push(vm.env.timestamp.into())?;
89
90 Ok(OpcodeResult::Continue)
91 }
92}
93
94pub struct OpNumberHandler;
96impl OpcodeHandler for OpNumberHandler {
97 #[inline(always)]
98 fn eval(vm: &mut VM<'_>) -> Result<OpcodeResult, VMError> {
99 vm.current_call_frame
100 .increase_consumed_gas(gas_cost::NUMBER)?;
101
102 vm.current_call_frame
103 .stack
104 .push(vm.env.block_number.into())?;
105
106 Ok(OpcodeResult::Continue)
107 }
108}
109
110pub struct OpPrevRandaoHandler;
112impl OpcodeHandler for OpPrevRandaoHandler {
113 #[inline(always)]
114 fn eval(vm: &mut VM<'_>) -> Result<OpcodeResult, VMError> {
115 vm.current_call_frame
116 .increase_consumed_gas(gas_cost::PREVRANDAO)?;
117
118 #[expect(unsafe_code, reason = "safe")]
121 vm.current_call_frame.stack.push(U256(unsafe {
122 let mut bytes = vm.env.prev_randao.unwrap_or_default().0;
123 bytes.reverse();
124 mem::transmute_copy::<[u8; 32], [u64; 4]>(&bytes)
125 }))?;
126
127 Ok(OpcodeResult::Continue)
128 }
129}
130
131pub struct OpGasLimitHandler;
133impl OpcodeHandler for OpGasLimitHandler {
134 #[inline(always)]
135 fn eval(vm: &mut VM<'_>) -> Result<OpcodeResult, VMError> {
136 vm.current_call_frame
137 .increase_consumed_gas(gas_cost::GASLIMIT)?;
138
139 vm.current_call_frame
140 .stack
141 .push(vm.env.block_gas_limit.into())?;
142
143 Ok(OpcodeResult::Continue)
144 }
145}
146
147pub struct OpChainIdHandler;
149impl OpcodeHandler for OpChainIdHandler {
150 #[inline(always)]
151 fn eval(vm: &mut VM<'_>) -> Result<OpcodeResult, VMError> {
152 vm.current_call_frame
153 .increase_consumed_gas(gas_cost::CHAINID)?;
154
155 vm.current_call_frame.stack.push(vm.env.chain_id)?;
156
157 Ok(OpcodeResult::Continue)
158 }
159}
160
161pub struct OpSelfBalanceHandler;
163impl OpcodeHandler for OpSelfBalanceHandler {
164 #[inline(always)]
165 fn eval(vm: &mut VM<'_>) -> Result<OpcodeResult, VMError> {
166 vm.current_call_frame
167 .increase_consumed_gas(gas_cost::SELFBALANCE)?;
168
169 let address = vm.current_call_frame.to;
170 let balance = vm.db.get_account(address)?.info.balance;
171
172 if let Some(recorder) = vm.db.bal_recorder.as_mut() {
175 recorder.record_touched_address(address);
176 }
177
178 vm.current_call_frame.stack.push(balance)?;
179
180 Ok(OpcodeResult::Continue)
181 }
182}
183
184pub struct OpBaseFeeHandler;
186impl OpcodeHandler for OpBaseFeeHandler {
187 #[inline(always)]
188 fn eval(vm: &mut VM<'_>) -> Result<OpcodeResult, VMError> {
189 vm.current_call_frame
190 .increase_consumed_gas(gas_cost::BASEFEE)?;
191
192 vm.current_call_frame.stack.push(vm.env.base_fee_per_gas)?;
194
195 Ok(OpcodeResult::Continue)
196 }
197}
198
199pub struct OpBlobHashHandler;
201impl OpcodeHandler for OpBlobHashHandler {
202 #[inline(always)]
203 fn eval(vm: &mut VM<'_>) -> Result<OpcodeResult, VMError> {
204 vm.current_call_frame
205 .increase_consumed_gas(gas_cost::BLOBHASH)?;
206
207 match usize::try_from(vm.current_call_frame.stack.pop1()?)
208 .ok()
209 .and_then(|index| vm.env.tx_blob_hashes.get(index))
210 {
211 Some(hash) =>
212 {
213 #[expect(unsafe_code, reason = "safe")]
214 vm.current_call_frame.stack.push(U256(unsafe {
215 let mut bytes = hash.0;
216 bytes.reverse();
217 mem::transmute_copy::<[u8; 32], [u64; 4]>(&bytes)
218 }))?
219 }
220 None => vm.current_call_frame.stack.push_zero()?,
221 }
222
223 Ok(OpcodeResult::Continue)
224 }
225}
226
227pub struct OpBlobBaseFeeHandler;
229impl OpcodeHandler for OpBlobBaseFeeHandler {
230 #[inline(always)]
231 fn eval(vm: &mut VM<'_>) -> Result<OpcodeResult, VMError> {
232 vm.current_call_frame
233 .increase_consumed_gas(gas_cost::BLOBBASEFEE)?;
234
235 vm.current_call_frame
236 .stack
237 .push(vm.env.base_blob_fee_per_gas)?;
238
239 Ok(OpcodeResult::Continue)
240 }
241}
242
243pub struct OpSlotNumHandler;
245impl OpcodeHandler for OpSlotNumHandler {
246 #[inline(always)]
247 fn eval(vm: &mut VM<'_>) -> Result<OpcodeResult, VMError> {
248 vm.current_call_frame
250 .increase_consumed_gas(gas_cost::SLOTNUM)?;
251
252 vm.current_call_frame.stack.push(vm.env.slot_number)?;
253
254 Ok(OpcodeResult::Continue)
255 }
256}