ethrex_levm/opcode_handlers/
bitwise_comparison.rs1use crate::{
20 errors::{OpcodeResult, VMError},
21 gas_cost,
22 opcode_handlers::OpcodeHandler,
23 vm::VM,
24};
25use ethrex_common::U256;
26
27pub struct OpLtHandler;
29impl OpcodeHandler for OpLtHandler {
30 #[inline(always)]
31 fn eval(vm: &mut VM<'_>) -> Result<OpcodeResult, VMError> {
32 vm.current_call_frame.increase_consumed_gas(gas_cost::LT)?;
33
34 let (lhs, rhs) = vm.current_call_frame.stack.pop1_and_top_mut()?;
35 #[expect(clippy::as_conversions, reason = "safe")]
36 let res = (lhs < *rhs) as u64;
37 *rhs = res.into();
38
39 Ok(OpcodeResult::Continue)
40 }
41}
42
43pub struct OpGtHandler;
45impl OpcodeHandler for OpGtHandler {
46 #[inline(always)]
47 fn eval(vm: &mut VM<'_>) -> Result<OpcodeResult, VMError> {
48 vm.current_call_frame.increase_consumed_gas(gas_cost::GT)?;
49
50 let (lhs, rhs) = vm.current_call_frame.stack.pop1_and_top_mut()?;
51 #[expect(clippy::as_conversions, reason = "safe")]
52 let res = (lhs > *rhs) as u64;
53 *rhs = res.into();
54
55 Ok(OpcodeResult::Continue)
56 }
57}
58
59pub struct OpSLtHandler;
61impl OpcodeHandler for OpSLtHandler {
62 #[inline(always)]
63 fn eval(vm: &mut VM<'_>) -> Result<OpcodeResult, VMError> {
64 vm.current_call_frame.increase_consumed_gas(gas_cost::SLT)?;
65
66 let (lhs, slot) = vm.current_call_frame.stack.pop1_and_top_mut()?;
67 let rhs = *slot;
68 let lhs_sign = lhs.bit(255);
69 let rhs_sign = rhs.bit(255);
70
71 *slot = match (lhs_sign, rhs_sign) {
72 (false, true) => U256::zero(),
73 (true, false) => U256::one(),
74 #[expect(clippy::as_conversions, reason = "safe")]
75 _ => ((lhs < rhs) as u64).into(),
76 };
77
78 Ok(OpcodeResult::Continue)
79 }
80}
81
82pub struct OpSGtHandler;
84impl OpcodeHandler for OpSGtHandler {
85 #[inline(always)]
86 fn eval(vm: &mut VM<'_>) -> Result<OpcodeResult, VMError> {
87 vm.current_call_frame.increase_consumed_gas(gas_cost::SGT)?;
88
89 let (lhs, slot) = vm.current_call_frame.stack.pop1_and_top_mut()?;
90 let rhs = *slot;
91 let lhs_sign = lhs.bit(255);
92 let rhs_sign = rhs.bit(255);
93
94 *slot = match (lhs_sign, rhs_sign) {
95 (false, true) => U256::one(),
96 (true, false) => U256::zero(),
97 #[expect(clippy::as_conversions, reason = "safe")]
98 _ => ((lhs > rhs) as u64).into(),
99 };
100
101 Ok(OpcodeResult::Continue)
102 }
103}
104
105pub struct OpEqHandler;
107impl OpcodeHandler for OpEqHandler {
108 #[inline(always)]
109 fn eval(vm: &mut VM<'_>) -> Result<OpcodeResult, VMError> {
110 vm.current_call_frame.increase_consumed_gas(gas_cost::EQ)?;
111
112 let (lhs, rhs) = vm.current_call_frame.stack.pop1_and_top_mut()?;
113 #[expect(clippy::as_conversions, reason = "safe")]
114 let res = (lhs == *rhs) as u64;
115 *rhs = res.into();
116
117 Ok(OpcodeResult::Continue)
118 }
119}
120
121pub struct OpIsZeroHandler;
123impl OpcodeHandler for OpIsZeroHandler {
124 #[inline(always)]
125 fn eval(vm: &mut VM<'_>) -> Result<OpcodeResult, VMError> {
126 vm.current_call_frame
127 .increase_consumed_gas(gas_cost::ISZERO)?;
128
129 let slot = vm.current_call_frame.stack.top_mut()?;
131 #[expect(clippy::as_conversions, reason = "safe")]
132 let z = slot.is_zero() as u64;
133 *slot = z.into();
134
135 Ok(OpcodeResult::Continue)
136 }
137}
138
139pub struct OpAndHandler;
141impl OpcodeHandler for OpAndHandler {
142 #[inline(always)]
143 fn eval(vm: &mut VM<'_>) -> Result<OpcodeResult, VMError> {
144 vm.current_call_frame.increase_consumed_gas(gas_cost::AND)?;
145
146 let (lhs, rhs) = vm.current_call_frame.stack.pop1_and_top_mut()?;
147 *rhs = lhs & *rhs;
148
149 Ok(OpcodeResult::Continue)
150 }
151}
152
153pub struct OpOrHandler;
155impl OpcodeHandler for OpOrHandler {
156 #[inline(always)]
157 fn eval(vm: &mut VM<'_>) -> Result<OpcodeResult, VMError> {
158 vm.current_call_frame.increase_consumed_gas(gas_cost::OR)?;
159
160 let (lhs, rhs) = vm.current_call_frame.stack.pop1_and_top_mut()?;
161 *rhs = lhs | *rhs;
162
163 Ok(OpcodeResult::Continue)
164 }
165}
166
167pub struct OpXorHandler;
169impl OpcodeHandler for OpXorHandler {
170 #[inline(always)]
171 fn eval(vm: &mut VM<'_>) -> Result<OpcodeResult, VMError> {
172 vm.current_call_frame.increase_consumed_gas(gas_cost::XOR)?;
173
174 let (lhs, rhs) = vm.current_call_frame.stack.pop1_and_top_mut()?;
175 *rhs = lhs ^ *rhs;
176
177 Ok(OpcodeResult::Continue)
178 }
179}
180
181pub struct OpNotHandler;
183impl OpcodeHandler for OpNotHandler {
184 #[inline(always)]
185 fn eval(vm: &mut VM<'_>) -> Result<OpcodeResult, VMError> {
186 vm.current_call_frame.increase_consumed_gas(gas_cost::NOT)?;
187
188 let slot = vm.current_call_frame.stack.top_mut()?;
190 *slot = !*slot;
191
192 Ok(OpcodeResult::Continue)
193 }
194}
195
196pub struct OpByteHandler;
198impl OpcodeHandler for OpByteHandler {
199 #[inline(always)]
200 fn eval(vm: &mut VM<'_>) -> Result<OpcodeResult, VMError> {
201 vm.current_call_frame
202 .increase_consumed_gas(gas_cost::BYTE)?;
203
204 let (index, slot) = vm.current_call_frame.stack.pop1_and_top_mut()?;
205 let value = *slot;
206 *slot = match usize::try_from(index) {
207 #[expect(
208 clippy::arithmetic_side_effects,
209 reason = "x < 32 guard prevents overflow"
210 )]
211 Ok(x) if x < 32 => value.byte(31 - x).into(),
212 _ => U256::zero(),
213 };
214
215 Ok(OpcodeResult::Continue)
216 }
217}
218
219pub struct OpShlHandler;
221impl OpcodeHandler for OpShlHandler {
222 #[inline(always)]
223 fn eval(vm: &mut VM<'_>) -> Result<OpcodeResult, VMError> {
224 vm.current_call_frame.increase_consumed_gas(gas_cost::SHL)?;
225
226 let (shift_amount, slot) = vm.current_call_frame.stack.pop1_and_top_mut()?;
227 let value = *slot;
228 *slot = match u8::try_from(shift_amount) {
229 #[expect(clippy::arithmetic_side_effects, reason = "U256 shift by u8 is safe")]
230 Ok(shift_amount) => value << shift_amount,
231 Err(_) => U256::zero(),
232 };
233
234 Ok(OpcodeResult::Continue)
235 }
236}
237
238pub struct OpShrHandler;
240impl OpcodeHandler for OpShrHandler {
241 #[inline(always)]
242 fn eval(vm: &mut VM<'_>) -> Result<OpcodeResult, VMError> {
243 vm.current_call_frame.increase_consumed_gas(gas_cost::SHR)?;
244
245 let (shift_amount, slot) = vm.current_call_frame.stack.pop1_and_top_mut()?;
246 let value = *slot;
247 *slot = match u8::try_from(shift_amount) {
248 #[expect(clippy::arithmetic_side_effects, reason = "U256 shift by u8 is safe")]
249 Ok(shift_amount) => value >> shift_amount,
250 Err(_) => U256::zero(),
251 };
252
253 Ok(OpcodeResult::Continue)
254 }
255}
256
257pub struct OpSarHandler;
259impl OpcodeHandler for OpSarHandler {
260 #[inline(always)]
261 fn eval(vm: &mut VM<'_>) -> Result<OpcodeResult, VMError> {
262 vm.current_call_frame.increase_consumed_gas(gas_cost::SAR)?;
263
264 let (shift_amount, slot) = vm.current_call_frame.stack.pop1_and_top_mut()?;
265 let value = *slot;
266 #[expect(clippy::arithmetic_side_effects, reason = "U256 shift by u8 is safe")]
267 {
268 *slot = match (u8::try_from(shift_amount), value.bit(255)) {
269 (Ok(shift_amount), false) => value >> shift_amount,
270 (Ok(shift_amount), true) => !(!value >> shift_amount),
271 (Err(_), false) => U256::zero(),
272 (Err(_), true) => U256::MAX,
273 };
274 }
275
276 Ok(OpcodeResult::Continue)
277 }
278}