1use crate::contract::EventId;
2use crate::types::Type;
3use crate::values::{Location, Value};
4use num_bigint::BigUint;
5use serde::{Deserialize, Serialize};
6
7#[derive(Debug, Clone, Serialize, Deserialize)]
8pub enum Instruction {
9 Add {
10 result: Value,
11 left: Value,
12 right: Value,
13 ty: Type,
14 },
15 Sub {
16 result: Value,
17 left: Value,
18 right: Value,
19 ty: Type,
20 },
21 Mul {
22 result: Value,
23 left: Value,
24 right: Value,
25 ty: Type,
26 },
27 Div {
28 result: Value,
29 left: Value,
30 right: Value,
31 ty: Type,
32 },
33 Mod {
34 result: Value,
35 left: Value,
36 right: Value,
37 ty: Type,
38 },
39 Pow {
40 result: Value,
41 base: Value,
42 exp: Value,
43 },
44
45 CheckedAdd {
46 result: Value,
47 left: Value,
48 right: Value,
49 ty: Type,
50 },
51 CheckedSub {
52 result: Value,
53 left: Value,
54 right: Value,
55 ty: Type,
56 },
57 CheckedMul {
58 result: Value,
59 left: Value,
60 right: Value,
61 ty: Type,
62 },
63 CheckedDiv {
64 result: Value,
65 left: Value,
66 right: Value,
67 ty: Type,
68 },
69
70 And {
71 result: Value,
72 left: Value,
73 right: Value,
74 },
75 Or {
76 result: Value,
77 left: Value,
78 right: Value,
79 },
80 Xor {
81 result: Value,
82 left: Value,
83 right: Value,
84 },
85 Not {
86 result: Value,
87 operand: Value,
88 },
89 Shl {
90 result: Value,
91 value: Value,
92 shift: Value,
93 },
94 Shr {
95 result: Value,
96 value: Value,
97 shift: Value,
98 },
99 Sar {
100 result: Value,
101 value: Value,
102 shift: Value,
103 },
104
105 Eq {
106 result: Value,
107 left: Value,
108 right: Value,
109 },
110 Ne {
111 result: Value,
112 left: Value,
113 right: Value,
114 },
115 Lt {
116 result: Value,
117 left: Value,
118 right: Value,
119 },
120 Gt {
121 result: Value,
122 left: Value,
123 right: Value,
124 },
125 Le {
126 result: Value,
127 left: Value,
128 right: Value,
129 },
130 Ge {
131 result: Value,
132 left: Value,
133 right: Value,
134 },
135
136 Select {
137 result: Value,
138 condition: Value,
139 then_val: Value,
140 else_val: Value,
141 },
142
143 Load {
144 result: Value,
145 location: Location,
146 },
147 Store {
148 location: Location,
149 value: Value,
150 },
151 Allocate {
152 result: Value,
153 ty: Type,
154 size: Size,
155 },
156 Copy {
157 dest: Location,
158 src: Location,
159 size: Value,
160 },
161
162 StorageLoad {
163 result: Value,
164 key: StorageKey,
165 },
166 StorageStore {
167 key: StorageKey,
168 value: Value,
169 },
170 StorageDelete {
171 key: StorageKey,
172 },
173
174 MappingLoad {
175 result: Value,
176 mapping: Value,
177 key: Value,
178 },
179 MappingStore {
180 mapping: Value,
181 key: Value,
182 value: Value,
183 },
184
185 ArrayLoad {
186 result: Value,
187 array: Value,
188 index: Value,
189 },
190 ArrayStore {
191 array: Value,
192 index: Value,
193 value: Value,
194 },
195 ArrayLength {
196 result: Value,
197 array: Value,
198 },
199 ArrayPush {
200 array: Value,
201 value: Value,
202 },
203 ArrayPop {
204 result: Value,
205 array: Value,
206 },
207
208 Call {
209 result: Value,
210 target: CallTarget,
211 args: Vec<Value>,
212 value: Option<Value>,
213 },
214 DelegateCall {
215 result: Value,
216 target: Value,
217 selector: Value,
218 args: Vec<Value>,
219 },
220 StaticCall {
221 result: Value,
222 target: Value,
223 selector: Value,
224 args: Vec<Value>,
225 },
226
227 Create {
228 result: Value,
229 code: Value,
230 value: Value,
231 },
232 Create2 {
233 result: Value,
234 code: Value,
235 salt: Value,
236 value: Value,
237 },
238
239 Selfdestruct {
240 beneficiary: Value,
241 },
242
243 GetContext {
244 result: Value,
245 var: ContextVariable,
246 },
247 GetBalance {
248 result: Value,
249 address: Value,
250 },
251 GetCode {
252 result: Value,
253 address: Value,
254 },
255 GetCodeSize {
256 result: Value,
257 address: Value,
258 },
259 GetCodeHash {
260 result: Value,
261 address: Value,
262 },
263
264 Keccak256 {
265 result: Value,
266 data: Value,
267 len: Value,
268 },
269 Sha256 {
270 result: Value,
271 data: Value,
272 len: Value,
273 },
274 Ripemd160 {
275 result: Value,
276 data: Value,
277 len: Value,
278 },
279 EcRecover {
280 result: Value,
281 hash: Value,
282 v: Value,
283 r: Value,
284 s: Value,
285 },
286
287 EmitEvent {
288 event: EventId,
289 topics: Vec<Value>,
290 data: Vec<Value>,
291 },
292
293 Cast {
294 result: Value,
295 value: Value,
296 to: Type,
297 },
298 ZeroExtend {
299 result: Value,
300 value: Value,
301 to: Type,
302 },
303 SignExtend {
304 result: Value,
305 value: Value,
306 to: Type,
307 },
308 Truncate {
309 result: Value,
310 value: Value,
311 to: Type,
312 },
313
314 Assert {
315 condition: Value,
316 message: String,
317 },
318 Require {
319 condition: Value,
320 message: String,
321 },
322 Revert {
323 message: String,
324 },
325
326 Assign {
327 result: Value,
328 value: Value,
329 },
330 Phi {
331 result: Value,
332 values: Vec<(BlockId, Value)>,
333 },
334
335 Jump {
336 target: BlockId,
337 args: Vec<Value>,
338 },
339 Branch {
340 condition: Value,
341 then_block: BlockId,
342 else_block: BlockId,
343 then_args: Vec<Value>,
344 else_args: Vec<Value>,
345 },
346 Return {
347 value: Option<Value>,
348 },
349
350 MemoryAlloc {
351 result: Value,
352 size: Value,
353 },
354 MemoryCopy {
355 dest: Value,
356 src: Value,
357 size: Value,
358 },
359 MemorySize {
360 result: Value,
361 },
362}
363
364#[derive(Debug, Clone, Serialize, Deserialize)]
365pub enum Size {
366 Static(usize),
367 Dynamic(Value),
368}
369
370#[derive(Debug, Clone, Serialize, Deserialize)]
371pub enum StorageKey {
372 Slot(BigUint),
373 Dynamic(Value),
374 Computed(Value),
375 MappingKey { base: BigUint, key: Value },
376 ArrayElement { base: BigUint, index: Value },
377}
378
379#[derive(Debug, Clone, Serialize, Deserialize)]
380pub enum CallTarget {
381 Internal(String),
382 External(Value),
383 Library(String),
384 Builtin(BuiltinFunction),
385}
386
387#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
388pub enum BuiltinFunction {
389 AddMod,
390 MulMod,
391 BlockHash,
392 GasLeft,
393}
394
395#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
396pub enum ContextVariable {
397 MsgSender,
398 MsgValue,
399 MsgData,
400 MsgSig,
401 BlockNumber,
402 BlockTimestamp,
403 BlockDifficulty,
404 BlockGasLimit,
405 BlockCoinbase,
406 ChainId,
407 BlockBaseFee,
408 TxOrigin,
409 TxGasPrice,
410 GasLeft,
411 ThisAddress,
412 ThisBalance,
413}
414
415use crate::block::BlockId;
416
417impl Instruction {
418 pub fn result(&self) -> Option<&Value> {
419 match self {
420 Instruction::Add { result, .. }
421 | Instruction::Sub { result, .. }
422 | Instruction::Mul { result, .. }
423 | Instruction::Div { result, .. }
424 | Instruction::Mod { result, .. }
425 | Instruction::Pow { result, .. }
426 | Instruction::CheckedAdd { result, .. }
427 | Instruction::CheckedSub { result, .. }
428 | Instruction::CheckedMul { result, .. }
429 | Instruction::CheckedDiv { result, .. }
430 | Instruction::And { result, .. }
431 | Instruction::Or { result, .. }
432 | Instruction::Xor { result, .. }
433 | Instruction::Not { result, .. }
434 | Instruction::Shl { result, .. }
435 | Instruction::Shr { result, .. }
436 | Instruction::Sar { result, .. }
437 | Instruction::Eq { result, .. }
438 | Instruction::Ne { result, .. }
439 | Instruction::Lt { result, .. }
440 | Instruction::Gt { result, .. }
441 | Instruction::Le { result, .. }
442 | Instruction::Ge { result, .. }
443 | Instruction::Load { result, .. }
444 | Instruction::Allocate { result, .. }
445 | Instruction::StorageLoad { result, .. }
446 | Instruction::MappingLoad { result, .. }
447 | Instruction::ArrayLoad { result, .. }
448 | Instruction::ArrayLength { result, .. }
449 | Instruction::ArrayPop { result, .. }
450 | Instruction::Call { result, .. }
451 | Instruction::DelegateCall { result, .. }
452 | Instruction::StaticCall { result, .. }
453 | Instruction::Create { result, .. }
454 | Instruction::Create2 { result, .. }
455 | Instruction::GetContext { result, .. }
456 | Instruction::GetBalance { result, .. }
457 | Instruction::GetCode { result, .. }
458 | Instruction::GetCodeSize { result, .. }
459 | Instruction::GetCodeHash { result, .. }
460 | Instruction::Keccak256 { result, .. }
461 | Instruction::Sha256 { result, .. }
462 | Instruction::Ripemd160 { result, .. }
463 | Instruction::EcRecover { result, .. }
464 | Instruction::Cast { result, .. }
465 | Instruction::ZeroExtend { result, .. }
466 | Instruction::SignExtend { result, .. }
467 | Instruction::Truncate { result, .. }
468 | Instruction::Assign { result, .. }
469 | Instruction::Phi { result, .. }
470 | Instruction::MemoryAlloc { result, .. }
471 | Instruction::MemorySize { result, .. } => Some(result),
472 _ => None,
473 }
474 }
475
476 pub fn is_state_changing(&self) -> bool {
477 matches!(
478 self,
479 Instruction::Store { .. }
480 | Instruction::StorageStore { .. }
481 | Instruction::StorageDelete { .. }
482 | Instruction::MappingStore { .. }
483 | Instruction::ArrayStore { .. }
484 | Instruction::ArrayPush { .. }
485 | Instruction::ArrayPop { .. }
486 | Instruction::Call { .. }
487 | Instruction::DelegateCall { .. }
488 | Instruction::Create { .. }
489 | Instruction::Create2 { .. }
490 | Instruction::Selfdestruct { .. }
491 | Instruction::EmitEvent { .. }
492 )
493 }
494
495 pub fn is_external_call(&self) -> bool {
496 matches!(
497 self,
498 Instruction::Call {
499 target: CallTarget::External(_),
500 ..
501 } | Instruction::DelegateCall { .. }
502 | Instruction::StaticCall { .. }
503 )
504 }
505
506 pub fn is_external_call_with_value(&self) -> bool {
507 matches!(
508 self,
509 Instruction::Call {
510 target: CallTarget::External(_),
511 value: Some(_),
512 ..
513 }
514 )
515 }
516
517 pub fn can_revert(&self) -> bool {
518 matches!(
519 self,
520 Instruction::Div { .. }
521 | Instruction::Mod { .. }
522 | Instruction::CheckedAdd { .. }
523 | Instruction::CheckedSub { .. }
524 | Instruction::CheckedMul { .. }
525 | Instruction::Assert { .. }
526 | Instruction::Require { .. }
527 | Instruction::Call { .. }
528 | Instruction::DelegateCall { .. }
529 | Instruction::StaticCall { .. }
530 | Instruction::Create { .. }
531 | Instruction::Create2 { .. }
532 )
533 }
534}