Skip to main content

thalir_core/
instructions.rs

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}