1use yevm_base::{Acc, Int};
2
3use crate::{
4 Call,
5 evm::{Context, Evm, EvmResult, EvmYield, Fetch, HaltReason, mem_check_int},
6 state::State,
7};
8
9pub fn address(evm: &mut Evm, ctx: &Context, _: &Call, _: &mut dyn State) -> EvmResult<()> {
10 evm.gas_charge(2)?;
11 let r = ctx.this.to();
12 evm.push(r)?;
13 Ok(())
14}
15
16pub fn balance<S: State>(evm: &mut Evm, _: &Context, _: &Call, state: &mut S) -> EvmResult<()> {
17 evm.gas_charge(100)?;
18 let [acc] = evm.peek()?;
19 let acc: Acc = acc.to();
20 let Some(balance) = state.balance(&acc) else {
21 return Err(EvmYield::Fetch(Fetch::Balance(acc)));
22 };
23
24 if state.is_cold_acc(&acc) {
25 evm.warm_acc(&acc);
26 evm.gas_charge(2_500)?;
27 }
28 evm.push(balance)?;
29 if let Some(step) = evm.step.as_mut() {
30 step.debug.push(format!("BALANCE: {balance:?}"));
31 }
32 Ok(())
33}
34
35pub fn origin(evm: &mut Evm, ctx: &Context, _: &Call, _: &mut dyn State) -> EvmResult<()> {
36 evm.gas_charge(2)?;
37 evm.push(ctx.origin.to())?;
38 Ok(())
39}
40
41pub fn caller(evm: &mut Evm, _: &Context, call: &Call, _: &mut dyn State) -> EvmResult<()> {
42 evm.gas_charge(2)?;
43 let caller = call.by;
44 evm.push(caller.to())?;
45 if let Some(step) = evm.step.as_mut() {
46 step.debug.push(format!("CALLER: {caller:?}"));
47 }
48 Ok(())
49}
50
51pub fn callvalue(evm: &mut Evm, _: &Context, call: &Call, _: &mut dyn State) -> EvmResult<()> {
52 evm.gas_charge(2)?;
53 evm.push(call.eth)?;
54 Ok(())
55}
56
57pub fn calldataload(evm: &mut Evm, _: &Context, call: &Call, _: &mut dyn State) -> EvmResult<()> {
58 evm.gas_charge(3)?;
59 let [offset] = evm.peek_usize()?;
60 let mut word = [0u8; 32];
61 if offset < call.data.0.len() {
62 let copy = (call.data.0.len() - offset).min(32);
63 word[..copy].copy_from_slice(&call.data.0[offset..offset + copy]);
64 }
65 evm.push(yevm_base::Int::from(&word[..]))?;
66 Ok(())
67}
68
69pub fn calldatasize(evm: &mut Evm, _: &Context, call: &Call, _: &mut dyn State) -> EvmResult<()> {
70 evm.gas_charge(2)?;
71 evm.push(call.data.0.len().into())?;
72 Ok(())
73}
74
75pub fn calldatacopy(evm: &mut Evm, _: &Context, call: &Call, _: &mut dyn State) -> EvmResult<()> {
76 evm.gas_charge(3)?;
77 let [dest_offset, offset, size] = evm.peek::<3>()?;
78 mem_check_int(dest_offset, size)?;
79 let (dest_offset, size) = (dest_offset.as_usize(), size.as_usize());
80 evm.mem_expand(dest_offset, size)?;
81 evm.gas_charge(3 * size.div_ceil(32) as i64)?;
82 let data_len = call.data.0.len();
83 let (lo, hi) = if offset >= Int::from(data_len) {
84 (data_len, data_len)
85 } else {
86 let o = offset.as_usize();
87 let h = o.saturating_add(size).min(data_len);
88 (o.min(data_len), h)
89 };
90 let len = (lo..hi).len();
91 if len > 0 {
92 let data = &call.data.0[lo..hi];
93 evm.mem_put(dest_offset, len, data)?;
94 }
95 if len < size {
96 let pad = size - (lo..hi).len();
97 let data = vec![0; pad];
98 evm.mem_put(dest_offset + len, size - len, &data)?;
99 }
100 Ok(())
101}
102
103pub fn codesize(evm: &mut Evm, _: &Context, _: &Call, _: &mut dyn State) -> EvmResult<()> {
104 evm.gas_charge(2)?;
105 let size = evm.code.len();
106 evm.push(size.into())?;
107 Ok(())
108}
109
110pub fn codecopy(evm: &mut Evm, _: &Context, _: &Call, _: &mut dyn State) -> EvmResult<()> {
111 evm.gas_charge(3)?;
112 let [dest_offset, offset, size] = evm.peek::<3>()?;
113 mem_check_int(dest_offset, size)?;
114 let (dest_offset, size) = (dest_offset.as_usize(), size.as_usize());
115 evm.mem_expand(dest_offset, size)?;
116 evm.gas_charge(3 * size.div_ceil(32) as i64)?;
117 let code_len = evm.code.len();
118 let (lo, hi) = if offset >= Int::from(code_len) {
120 (code_len, code_len)
121 } else {
122 let o = offset.as_usize();
123 let h = o.saturating_add(size).min(code_len);
124 (o.min(code_len), h)
125 };
126 let len = (lo..hi).len();
127 let mut ret = vec![0u8; size];
128 ret[0..len].copy_from_slice(&evm.code[lo..hi]);
129 evm.mem_put(dest_offset, size, &ret)?;
130 Ok(())
131}
132
133pub fn gasprice(evm: &mut Evm, _: &Context, _: &Call, _: &mut dyn State) -> EvmResult<()> {
134 evm.gas_charge(2)?;
135 evm.push(evm.gas_price)?;
136 Ok(())
137}
138
139pub fn extcodesize<S: State>(evm: &mut Evm, _: &Context, _: &Call, state: &mut S) -> EvmResult<()> {
140 evm.gas_charge(100)?;
141 let [acc] = evm.peek()?;
142 let acc: Acc = acc.to();
143 let Some((code, _)) = state.code(&acc) else {
144 return Err(EvmYield::Fetch(Fetch::Code(acc)));
145 };
146 if state.is_cold_acc(&acc) {
147 evm.warm_acc(&acc);
148 evm.gas_charge(2_500)?;
149 }
150 evm.push(code.0.len().into())?;
151 Ok(())
152}
153
154pub fn extcodecopy<S: State>(evm: &mut Evm, _: &Context, _: &Call, state: &mut S) -> EvmResult<()> {
155 evm.gas_charge(100)?;
156 let [acc, dest_offset, offset, size] = evm.peek()?;
157 let acc: Acc = acc.to();
158 mem_check_int(dest_offset, size)?;
159 let (dest_offset, size) = (dest_offset.as_usize(), size.as_usize());
160
161 let Some((code, _)) = state.code(&acc) else {
162 return Err(EvmYield::Fetch(Fetch::Code(acc)));
163 };
164 if state.is_cold_acc(&acc) {
165 evm.warm_acc(&acc);
166 evm.gas_charge(2_500)?;
167 }
168 evm.mem_expand(dest_offset, size)?;
169 evm.gas_charge(3 * size.div_ceil(32) as i64)?;
170
171 let code_len = code.0.len();
172 let (lo, hi) = if offset >= Int::from(code_len) {
173 (code_len, code_len)
174 } else {
175 let o = offset.as_usize();
176 let h = o.saturating_add(size).min(code_len);
177 (o.min(code_len), h)
178 };
179 let len = (lo..hi).len();
180 if len > 0 {
181 let data = &code.0[lo..hi];
182 evm.mem_put(dest_offset, len, data)?;
183 }
184 if len < size {
185 let pad = size - (lo..hi).len();
186 let data = vec![0; pad];
187 evm.mem_put(dest_offset + len, size - len, &data)?;
188 }
189 Ok(())
190}
191
192pub fn returndatasize(evm: &mut Evm, _: &Context, _: &Call, _: &mut dyn State) -> EvmResult<()> {
193 evm.gas_charge(2)?;
194 evm.push(evm.ret.len().into())?;
195 Ok(())
196}
197
198pub fn returndatacopy(evm: &mut Evm, _: &Context, _: &Call, _: &mut dyn State) -> EvmResult<()> {
199 evm.gas_charge(3)?;
200 let [dest_offset, offset, size] = evm.peek::<3>()?;
201 mem_check_int(offset, size)?;
202 mem_check_int(dest_offset, size)?;
203 let ret_len = evm.ret.len();
207 let ret_len_int = Int::from(ret_len);
208 let (offset_u, size_u) = (offset.as_usize(), size.as_usize());
209 let ok_fast = offset_u
210 .checked_add(size_u)
211 .map(|end| end <= ret_len)
212 .unwrap_or(false);
213 if !ok_fast {
214 let add = yevm_base::math::lift(|[a, b]| a + b);
215 let gt = yevm_base::math::lift(|[a, b]| {
216 if a > b {
217 yevm_base::math::U256::ONE
218 } else {
219 yevm_base::math::U256::ZERO
220 }
221 });
222 let end = add([offset, size]);
223 if !gt([end, ret_len_int]).is_zero() {
224 return Err(EvmYield::Halt(HaltReason::BadCopyRange));
225 }
226 }
227 let (dest_offset, offset, size) = (dest_offset.as_usize(), offset.as_usize(), size.as_usize());
228 evm.gas_charge(3 * size.div_ceil(32) as i64)?;
229
230 let ret_len = evm.ret.len();
231 let (lo, copy_len) = if offset >= ret_len {
232 (ret_len, 0)
233 } else {
234 let copy_len = size.min(ret_len - offset);
235 (offset, copy_len)
236 };
237 if copy_len > 0 {
238 let data = evm.ret[lo..lo + copy_len].to_vec();
239 evm.mem_put(dest_offset, copy_len, &data)?;
240 }
241 if copy_len < size {
242 let pad = size - copy_len;
243 let data = vec![0; pad];
244 evm.mem_put(dest_offset + copy_len, pad, &data)?;
245 }
246 Ok(())
247}
248
249pub fn extcodehash<S: State>(evm: &mut Evm, _: &Context, _: &Call, state: &mut S) -> EvmResult<()> {
250 evm.gas_charge(100)?;
251 let [acc] = evm.peek()?;
252 let acc: Acc = acc.to();
253 let Some(account) = state.acc(&acc) else {
254 return Err(EvmYield::Fetch(Fetch::Code(acc)));
255 };
256 if state.is_cold_acc(&acc) {
257 evm.warm_acc(&acc);
258 evm.gas_charge(2_500)?;
259 }
260 let hash = if account.code.0.0.is_empty() && account.nonce.is_zero() && account.value.is_zero()
262 {
263 Int::ZERO
264 } else if account.code.1.is_zero() && account.code.0.0.is_empty() {
265 yevm_misc::keccak256(&[])
267 } else {
268 account.code.1
269 };
270 evm.push(hash)?;
271 Ok(())
272}
273
274pub fn blockhash<S: State>(evm: &mut Evm, _: &Context, _: &Call, state: &mut S) -> EvmResult<()> {
275 evm.gas_charge(20)?;
276 let [number] = evm.peek()?;
277 let number = number.as_u64();
278 let current = evm.head.number.as_u64();
279 if number >= current || current - number > 256 {
281 evm.push(Int::ZERO)?;
282 return Ok(());
283 }
284 let Some(head) = state.head(number) else {
285 return Err(EvmYield::Fetch(Fetch::BlockHash(number)));
286 };
287 evm.push(head.hash)?;
288 Ok(())
289}
290
291pub fn coinbase(evm: &mut Evm, _: &Context, _: &Call, _: &mut dyn State) -> EvmResult<()> {
292 evm.gas_charge(2)?;
293 evm.push(evm.head.coinbase.to())?;
294 Ok(())
295}
296
297pub fn timestamp(evm: &mut Evm, _: &Context, _: &Call, _: &mut dyn State) -> EvmResult<()> {
298 evm.gas_charge(2)?;
299 evm.push(evm.head.timestamp)?;
300 Ok(())
301}
302
303pub fn number(evm: &mut Evm, _: &Context, _: &Call, _: &mut dyn State) -> EvmResult<()> {
304 evm.gas_charge(2)?;
305 evm.push(evm.head.number.to())?;
306 Ok(())
307}
308
309pub fn prevrandao(evm: &mut Evm, _: &Context, _: &Call, _: &mut dyn State) -> EvmResult<()> {
310 evm.gas_charge(2)?;
311 evm.push(evm.head.prevrandao)?;
312 Ok(())
313}
314
315pub fn gaslimit(evm: &mut Evm, _: &Context, _: &Call, _: &mut dyn State) -> EvmResult<()> {
316 evm.gas_charge(2)?;
317 evm.push(evm.head.gas_limit)?;
318 Ok(())
319}
320
321pub fn chainid(evm: &mut Evm, _: &Context, _: &Call, _: &mut dyn State) -> EvmResult<()> {
322 evm.gas_charge(2)?;
323 evm.push(evm.chain_id)?;
324 Ok(())
325}
326
327pub fn selfbalance<S: State>(
328 evm: &mut Evm,
329 ctx: &Context,
330 _: &Call,
331 state: &mut S,
332) -> EvmResult<()> {
333 evm.gas_charge(5)?;
334 let acc: Acc = ctx.this;
335 let Some(balance) = state.balance(&acc) else {
336 return Err(EvmYield::Fetch(Fetch::Balance(acc)));
337 };
338 evm.push(balance)?;
339 Ok(())
340}
341
342pub fn basefee(evm: &mut Evm, _: &Context, _: &Call, _: &mut dyn State) -> EvmResult<()> {
343 evm.gas_charge(2)?;
344 evm.push(evm.head.base_fee)?;
345 Ok(())
346}
347
348pub fn blobhash(evm: &mut Evm, _: &Context, _: &Call, _: &mut dyn State) -> EvmResult<()> {
349 evm.gas_charge(3)?;
350 let [index] = evm.peek()?;
351 let hash = index
352 .as_usize_checked()
353 .and_then(|i| evm.blob_hashes.get(i))
354 .copied()
355 .unwrap_or(Int::ZERO);
356 evm.push(hash)?;
357 Ok(())
358}
359
360pub fn blobbasefee(evm: &mut Evm, _: &Context, _: &Call, _: &mut dyn State) -> EvmResult<()> {
361 evm.gas_charge(2)?;
362 evm.push(Int::ONE)?;
373 Ok(())
374}