Skip to main content

revmc_builtins/
macros.rs

1#[allow(unused_macros)]
2macro_rules! tri {
3    ($e:expr) => {
4        match $e {
5            Ok(x) => x,
6            Err(_) => return InstructionResult::InvalidOperandOOG,
7        }
8    };
9}
10
11macro_rules! try_host {
12    ($e:expr) => {
13        match $e {
14            Some(x) => x,
15            None => return InstructionResult::FatalExternalError,
16        }
17    };
18}
19
20macro_rules! try_ir {
21    ($e:expr) => {
22        match $e {
23            InstructionResult::Stop => {}
24            ir => return ir,
25        }
26    };
27}
28
29macro_rules! gas {
30    ($ecx:expr, $gas:expr) => {
31        if !$ecx.gas.record_cost($gas) {
32            return InstructionResult::OutOfGas;
33        }
34    };
35}
36
37macro_rules! gas_opt {
38    ($ecx:expr, $gas:expr) => {
39        match $gas {
40            Some(gas) => gas!($ecx, gas),
41            None => return InstructionResult::OutOfGas,
42        }
43    };
44}
45
46/// Mirrors revm's `berlin_load_account!` macro.
47/// Loads account info with the cold-load-skip optimization: if remaining gas
48/// is less than the cold cost, skip the DB load and return OOG immediately.
49/// Charges both `warm_storage_read_cost` (which revm's instruction table charges
50/// as static gas) and `cold_account_additional_cost` if cold.
51macro_rules! berlin_load_account {
52    ($ecx:expr, $address:expr, $load_code:expr) => {{
53        use revm_context_interface::host::LoadError;
54        let cold_load_gas = $ecx.host.gas_params().cold_account_additional_cost();
55        let skip_cold_load = $ecx.gas.remaining() < cold_load_gas;
56        match $ecx.host.load_account_info_skip_cold_load($address, $load_code, skip_cold_load) {
57            Ok(account) => {
58                if account.is_cold {
59                    gas!($ecx, cold_load_gas);
60                }
61                account
62            }
63            Err(LoadError::ColdLoadSkipped) => return InstructionResult::OutOfGas,
64            Err(LoadError::DBError) => return InstructionResult::FatalExternalError,
65        }
66    }};
67}
68
69macro_rules! ensure_non_staticcall {
70    ($ecx:expr) => {
71        if $ecx.is_static {
72            return InstructionResult::StateChangeDuringStaticCall;
73        }
74    };
75}
76
77macro_rules! ensure_memory {
78    ($ecx:expr, $offset:expr, $len:expr) => {
79        try_ir!(ensure_memory($ecx, $offset, $len))
80    };
81}
82
83/// Same as `read_words_rev`, but returns the arguments in the order they were passed.
84macro_rules! read_words {
85    ($sp:expr, $($words:ident),+ $(,)?) => {
86        let rev![$($words),+] = unsafe { read_words_rev($sp) };
87    };
88}
89
90macro_rules! pop {
91    ($sp:expr; $($x:ident),* $(,)?) => {
92        $(
93            $sp = $sp.sub(1);
94            let $x = &mut *$sp;
95        )*
96    };
97}
98
99macro_rules! try_into_usize {
100    ($x:expr) => {
101        match $x.to_u256().as_limbs() {
102            x => {
103                if (x[0] > usize::MAX as u64) | (x[1] != 0) | (x[2] != 0) | (x[3] != 0) {
104                    return InstructionResult::InvalidOperandOOG;
105                }
106                x[0] as usize
107            }
108        }
109    };
110}
111
112// Credits: <https://github.com/AuroransSolis/rustconf-2023/blob/665a645d751dfe0e483261e3abca25ab4bb9e13a/reverse-tokens/src/main.rs>
113macro_rules! rev {
114	(@rev [$first:tt$(, $rest:tt)*] [$($rev:tt),*]) => {
115		rev! {
116			@rev [$($rest),*][$first $(, $rev)*]
117		}
118	};
119	(@rev [] [$($rev:tt),*]) => {
120		[$($rev)*] // NOTE: Extra `[]` to make this an array pattern.
121	};
122	($($tt:tt)+) => {
123		rev! {
124			@rev [$($tt),+] []
125		}
126	};
127}
128
129macro_rules! debug_unreachable {
130    ($($t:tt)*) => {
131        if cfg!(debug_assertions) {
132            unreachable!($($t)*);
133        } else {
134            unsafe { core::hint::unreachable_unchecked() };
135        }
136    };
137}
138
139macro_rules! assume {
140    ($e:expr $(,)?) => {
141        if !$e {
142            debug_unreachable!(stringify!($e));
143        }
144    };
145
146    ($e:expr, $($t:tt)+) => {
147        if !$e {
148            debug_unreachable!($($t)+);
149        }
150    };
151}