1use crate::GlobalStateInterface;
2
3macro_rules! forall_simple_opcodes {
4 ($m:ident) => {
5 $m!(Nop);
6 $m!(Add);
7 $m!(Sub);
8 $m!(And);
9 $m!(Or);
10 $m!(Xor);
11 $m!(ShiftLeft);
12 $m!(ShiftRight);
13 $m!(RotateLeft);
14 $m!(RotateRight);
15 $m!(Mul);
16 $m!(Div);
17 $m!(NearCall);
18 $m!(Jump);
19 $m!(Event);
20 $m!(L2ToL1Message);
21 $m!(Decommit);
22 $m!(This);
23 $m!(Caller);
24 $m!(CodeAddress);
25 $m!(ErgsLeft);
26 $m!(SP);
27 $m!(ContextMeta);
28 $m!(ContextU128);
29 $m!(SetContextU128);
30 $m!(IncrementTxNumber);
31 $m!(AuxMutating0);
32 $m!(PrecompileCall);
33 $m!(HeapRead);
34 $m!(HeapWrite);
35 $m!(AuxHeapRead);
36 $m!(AuxHeapWrite);
37 $m!(StaticMemoryRead);
38 $m!(StaticMemoryWrite);
39 $m!(PointerRead);
40 $m!(PointerAdd);
41 $m!(PointerSub);
42 $m!(PointerPack);
43 $m!(PointerShrink);
44 $m!(StorageRead);
45 $m!(StorageWrite);
46 $m!(TransientStorageRead);
47 $m!(TransientStorageWrite);
48 };
49}
50
51macro_rules! pub_struct {
52 ($x:ident) => {
53 #[doc = concat!("`", stringify!($x), "` opcode.")]
54 #[derive(Debug)]
55 pub struct $x;
56 };
57}
58
59pub mod opcodes {
61 use std::marker::PhantomData;
62
63 use super::{CallingMode, ReturnType};
64
65 forall_simple_opcodes!(pub_struct);
66
67 #[derive(Debug)]
69 pub struct FarCall<M: TypeLevelCallingMode>(PhantomData<M>);
70
71 #[derive(Debug)]
73 pub struct Ret<T: TypeLevelReturnType>(PhantomData<T>);
74
75 #[derive(Debug)]
77 pub struct Normal;
78
79 #[derive(Debug)]
81 pub struct Delegate;
82
83 #[derive(Debug)]
85 pub struct Mimic;
86
87 #[derive(Debug)]
89 pub struct Revert;
90
91 #[derive(Debug)]
93 pub struct Panic;
94
95 pub trait TypeLevelCallingMode {
97 const VALUE: CallingMode;
99 }
100
101 impl TypeLevelCallingMode for Normal {
102 const VALUE: CallingMode = CallingMode::Normal;
103 }
104
105 impl TypeLevelCallingMode for Delegate {
106 const VALUE: CallingMode = CallingMode::Delegate;
107 }
108
109 impl TypeLevelCallingMode for Mimic {
110 const VALUE: CallingMode = CallingMode::Mimic;
111 }
112
113 pub trait TypeLevelReturnType {
115 const VALUE: ReturnType;
117 }
118
119 impl TypeLevelReturnType for Normal {
120 const VALUE: ReturnType = ReturnType::Normal;
121 }
122
123 impl TypeLevelReturnType for Revert {
124 const VALUE: ReturnType = ReturnType::Revert;
125 }
126
127 impl TypeLevelReturnType for Panic {
128 const VALUE: ReturnType = ReturnType::Panic;
129 }
130}
131
132#[allow(missing_docs)]
134#[derive(PartialEq, Eq, Debug, Copy, Clone, Hash)]
135pub enum Opcode {
136 Nop,
137 Add,
138 Sub,
139 And,
140 Or,
141 Xor,
142 ShiftLeft,
143 ShiftRight,
144 RotateLeft,
145 RotateRight,
146 Mul,
147 Div,
148 NearCall,
149 FarCall(CallingMode),
150 Ret(ReturnType),
151 Jump,
152 Event,
153 L2ToL1Message,
154 Decommit,
155 This,
156 Caller,
157 CodeAddress,
158 ErgsLeft,
159 SP,
160 ContextMeta,
161 ContextU128,
162 SetContextU128,
163 IncrementTxNumber,
164 AuxMutating0,
165 PrecompileCall,
166 HeapRead,
167 HeapWrite,
168 AuxHeapRead,
169 AuxHeapWrite,
170 StaticMemoryRead,
171 StaticMemoryWrite,
172 PointerRead,
173 PointerAdd,
174 PointerSub,
175 PointerPack,
176 PointerShrink,
177 StorageRead,
178 StorageWrite,
179 TransientStorageRead,
180 TransientStorageWrite,
181}
182
183#[derive(PartialEq, Eq, Debug, Copy, Clone, Hash)]
185pub enum CallingMode {
186 Normal,
188 Delegate,
190 Mimic,
192}
193
194#[derive(PartialEq, Eq, Debug, Copy, Clone, Hash)]
196pub enum ReturnType {
197 Normal,
199 Revert,
201 Panic,
203}
204
205impl ReturnType {
206 pub fn is_failure(&self) -> bool {
208 *self != ReturnType::Normal
209 }
210}
211
212pub trait OpcodeType {
214 const VALUE: Opcode;
216}
217
218macro_rules! impl_opcode {
219 ($x:ident) => {
220 impl OpcodeType for opcodes::$x {
221 const VALUE: Opcode = Opcode::$x;
222 }
223 };
224}
225
226forall_simple_opcodes!(impl_opcode);
227
228impl<M: opcodes::TypeLevelCallingMode> OpcodeType for opcodes::FarCall<M> {
229 const VALUE: Opcode = Opcode::FarCall(M::VALUE);
230}
231
232impl<T: opcodes::TypeLevelReturnType> OpcodeType for opcodes::Ret<T> {
233 const VALUE: Opcode = Opcode::Ret(T::VALUE);
234}
235
236pub trait Tracer {
261 fn before_instruction<OP: OpcodeType, S: GlobalStateInterface>(&mut self, state: &mut S) {
265 let _ = state;
266 }
267 #[must_use]
275 fn after_instruction<OP: OpcodeType, S: GlobalStateInterface>(
276 &mut self,
277 state: &mut S,
278 ) -> ShouldStop {
279 let _ = state;
280 ShouldStop::Continue
281 }
282
283 fn on_extra_prover_cycles(&mut self, _stats: CycleStats) {}
287}
288
289#[derive(Debug)]
291pub enum ShouldStop {
292 Stop,
294 Continue,
296}
297
298impl ShouldStop {
299 #[must_use]
300 #[inline(always)]
301 fn merge(self, other: ShouldStop) -> ShouldStop {
302 match (self, other) {
303 (ShouldStop::Continue, ShouldStop::Continue) => ShouldStop::Continue,
304 _ => ShouldStop::Stop,
305 }
306 }
307}
308
309#[derive(Debug, Clone, Copy, PartialEq)]
311pub enum CycleStats {
312 Keccak256(u32),
314 Sha256(u32),
316 EcRecover(u32),
318 Secp256r1Verify(u32),
320 ModExp(u32),
322 EcAdd(u32),
324 EcMul(u32),
326 EcPairing(u32),
328 Decommit(u32),
330 StorageRead,
332 StorageWrite,
334}
335
336impl Tracer for () {}
338
339impl<A: Tracer, B: Tracer> Tracer for (A, B) {
341 fn before_instruction<OP: OpcodeType, S: GlobalStateInterface>(&mut self, state: &mut S) {
342 self.0.before_instruction::<OP, S>(state);
343 self.1.before_instruction::<OP, S>(state);
344 }
345
346 fn after_instruction<OP: OpcodeType, S: GlobalStateInterface>(
347 &mut self,
348 state: &mut S,
349 ) -> ShouldStop {
350 self.0
351 .after_instruction::<OP, S>(state)
352 .merge(self.1.after_instruction::<OP, S>(state))
353 }
354
355 fn on_extra_prover_cycles(&mut self, stats: CycleStats) {
356 self.0.on_extra_prover_cycles(stats);
357 self.1.on_extra_prover_cycles(stats);
358 }
359}
360
361#[cfg(test)]
362mod tests {
363 use super::{CallingMode, OpcodeType};
364 use crate::{opcodes, testonly::DummyState, GlobalStateInterface, Tracer};
365
366 struct FarCallCounter(usize);
367
368 impl Tracer for FarCallCounter {
369 fn before_instruction<OP: OpcodeType, S: GlobalStateInterface>(&mut self, _: &mut S) {
370 if let super::Opcode::FarCall(CallingMode::Normal) = OP::VALUE {
371 self.0 += 1;
372 }
373 }
374 }
375
376 #[test]
377 fn test_tracer() {
378 let mut tracer = FarCallCounter(0);
379
380 tracer.before_instruction::<opcodes::Nop, _>(&mut DummyState);
381 assert_eq!(tracer.0, 0);
382
383 tracer.before_instruction::<opcodes::FarCall<opcodes::Normal>, _>(&mut DummyState);
384 assert_eq!(tracer.0, 1);
385
386 tracer.before_instruction::<opcodes::FarCall<opcodes::Mimic>, _>(&mut DummyState);
387 assert_eq!(tracer.0, 1);
388 }
389
390 #[test]
391 fn test_aggregate_tracer() {
392 let mut tracer = (FarCallCounter(0), (FarCallCounter(0), FarCallCounter(0)));
393
394 tracer.before_instruction::<opcodes::Nop, _>(&mut DummyState);
395 assert_eq!(tracer.0 .0, 0);
396 assert_eq!(tracer.1 .0 .0, 0);
397 assert_eq!(tracer.1 .1 .0, 0);
398
399 tracer.before_instruction::<opcodes::FarCall<opcodes::Normal>, _>(&mut DummyState);
400 assert_eq!(tracer.0 .0, 1);
401 assert_eq!(tracer.1 .0 .0, 1);
402 assert_eq!(tracer.1 .1 .0, 1);
403 }
404}