Skip to main content

zksync_vm2_interface/
state_interface.rs

1use primitive_types::{H160, U256};
2
3/// Public interface of the VM state. Encompasses both read and write methods.
4pub trait StateInterface {
5    /// Reads a register with the specified zero-based index. Returns a value together with a pointer flag.
6    fn read_register(&self, register: u8) -> (U256, bool);
7    /// Sets a register with the specified zero-based index
8    fn set_register(&mut self, register: u8, value: U256, is_pointer: bool);
9
10    /// Returns a mutable handle to the current call frame.
11    fn current_frame(&mut self) -> impl CallframeInterface + '_;
12    /// Returns the total number of call frames.
13    fn number_of_callframes(&self) -> usize;
14    /// Returns a mutable handle to a call frame with the specified index, where
15    /// zero is the current frame, one is the frame before that etc.
16    fn callframe(&mut self, n: usize) -> impl CallframeInterface + '_;
17
18    /// Reads a single byte from the specified heap at the specified 0-based offset.
19    fn read_heap_byte(&self, heap: HeapId, offset: u32) -> u8;
20    /// Reads an entire `U256` word in the big-endian order from the specified heap / `offset`
21    /// (which is the index of the most significant byte of the read value).
22    fn read_heap_u256(&self, heap: HeapId, offset: u32) -> U256;
23    /// Writes an entire `U256` word in the big-endian order to the specified heap at the specified `offset`
24    /// (which is the index of the most significant byte of the written value).
25    fn write_heap_u256(&mut self, heap: HeapId, offset: u32, value: U256);
26
27    /// Returns current execution flags.
28    fn flags(&self) -> Flags;
29    /// Sets current execution flags.
30    fn set_flags(&mut self, flags: Flags);
31
32    /// Returns the currently set 0-based transaction number.
33    fn transaction_number(&self) -> u16;
34    /// Sets the current transaction number.
35    fn set_transaction_number(&mut self, value: u16);
36
37    /// Returns the value of the context register.
38    fn context_u128_register(&self) -> u128;
39    /// Sets the value of the context register.
40    fn set_context_u128_register(&mut self, value: u128);
41
42    /// Iterates over storage slots read or written during VM execution.
43    fn get_storage_state(&self) -> impl Iterator<Item = ((H160, U256), U256)>;
44
45    /// Iterates over all transient storage slots set during VM execution.
46    fn get_transient_storage_state(&self) -> impl Iterator<Item = ((H160, U256), U256)>;
47    /// Gets value of the specified transient storage slot.
48    fn get_transient_storage(&self, address: H160, slot: U256) -> U256;
49    /// Sets value of the specified transient storage slot.
50    fn write_transient_storage(&mut self, address: H160, slot: U256, value: U256);
51
52    /// Iterates over events emitted during VM execution.
53    fn events(&self) -> impl Iterator<Item = Event>;
54    /// Iterates over L2-to-L1 logs emitted during VM execution.
55    fn l2_to_l1_logs(&self) -> impl Iterator<Item = L2ToL1Log>;
56
57    /// Gets the current amount of published pubdata.
58    fn pubdata(&self) -> i32;
59    /// Sets the current amount of published pubdata.
60    fn set_pubdata(&mut self, value: i32);
61}
62
63/// State interface with access to global state like storage.
64pub trait GlobalStateInterface: StateInterface {
65    /// Gets value of the specified storage slot.
66    fn get_storage(&mut self, address: H160, slot: U256) -> U256;
67}
68
69/// VM execution flags. See the EraVM reference for more details.
70#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
71pub struct Flags {
72    /// "Less than" flag.
73    pub less_than: bool,
74    /// "Equal" flag.
75    pub equal: bool,
76    /// "Greater than" flag.
77    pub greater: bool,
78}
79
80/// Public interface of an EraVM call frame.
81pub trait CallframeInterface {
82    /// Address of the storage context associated with this frame. For delegate calls, this address is inherited from the calling contract;
83    /// otherwise, it's the same as [`Self::code_address()`].
84    fn address(&self) -> H160;
85    /// Sets the address of the executing contract.
86    fn set_address(&mut self, address: H160);
87    /// Address of the contract being executed.
88    fn code_address(&self) -> H160;
89    /// Sets the address of the contract being executed. Does not cause the contract at the specified address get loaded per se, just updates
90    /// the value used internally by the VM (e.g., returned by the [`CodeAddress`](crate::opcodes::CodeAddress) opcode).
91    fn set_code_address(&mut self, address: H160);
92    /// Address of the calling contract. Respects delegate and mimic calls.
93    fn caller(&self) -> H160;
94    /// Sets the address of the calling contract.
95    fn set_caller(&mut self, address: H160);
96
97    /// Returns the current program counter (i.e., 0-based index of the instruction being executed).
98    /// During panic this returns `None`.
99    fn program_counter(&self) -> Option<u16>;
100    /// Sets the program counter.
101    /// The VM will execute an invalid instruction if you jump out of the program.
102    fn set_program_counter(&mut self, value: u16);
103
104    /// Returns the program counter that the parent frame should continue from if this frame fails.
105    fn exception_handler(&self) -> u16;
106    /// Sets the exception handler as specified [above](Self::exception_handler()).
107    fn set_exception_handler(&mut self, value: u16);
108
109    /// Checks whether the call is static.
110    fn is_static(&self) -> bool;
111    /// Checks whether the call is executed in kernel mode.
112    fn is_kernel(&self) -> bool;
113
114    /// Returns the remaining amount of gas.
115    fn gas(&self) -> u32;
116    /// Sets the remaining amount of gas.
117    fn set_gas(&mut self, new_gas: u32);
118
119    /// Returns the context value for this call. This context is accessible via [`ContextU128`](crate::opcodes::ContextU128) opcode.
120    fn context_u128(&self) -> u128;
121    /// Sets the context value for this call.
122    fn set_context_u128(&mut self, value: u128);
123
124    /// Checks whether this frame corresponds to a near call.
125    fn is_near_call(&self) -> bool;
126
127    /// Reads the specified stack slot. Returns a value together with a pointer flag.
128    fn read_stack(&self, index: u16) -> (U256, bool);
129    /// Sets the value and pointer flag for the specified stack slot.
130    fn write_stack(&mut self, index: u16, value: U256, is_pointer: bool);
131
132    /// Returns the stack pointer.
133    fn stack_pointer(&self) -> u16;
134    /// Sets the stack pointer.
135    fn set_stack_pointer(&mut self, value: u16);
136
137    /// Returns ID of the main heap used in this call.
138    fn heap(&self) -> HeapId;
139    /// Returns the main heap boundary (number of paid bytes).
140    fn heap_bound(&self) -> u32;
141    /// Sets the main heap boundary.
142    fn set_heap_bound(&mut self, value: u32);
143
144    /// Returns ID of the auxiliary heap used in this call.
145    fn aux_heap(&self) -> HeapId;
146    /// Returns the auxiliary heap boundary (number of paid bytes).
147    fn aux_heap_bound(&self) -> u32;
148    /// Sets the auxiliary heap boundary.
149    fn set_aux_heap_bound(&mut self, value: u32);
150
151    /// Reads a word from the bytecode of the executing contract.
152    fn read_contract_code(&self, slot: u16) -> U256;
153}
154
155/// Identifier of a VM heap.
156///
157/// EraVM docs sometimes refer to heaps as *heap pages*; docs in these crate don't to avoid confusion with internal heap structure.
158#[derive(Copy, Clone, PartialEq, Debug)]
159#[repr(transparent)] // Guarantees `HeapId` has the same layout as `u32`; relied on by `FatPointer` transmutes.
160pub struct HeapId(u32);
161
162impl HeapId {
163    /// Identifier of the calldata heap used by the first executed program (i.e., the bootloader).
164    pub const FIRST_CALLDATA: Self = Self(7);
165    /// Identifier of the heap used by the first executed program (i.e., the bootloader).
166    pub const FIRST: Self = Self(10);
167    /// Identifier of the auxiliary heap used by the first executed program (i.e., the bootloader)
168    pub const FIRST_AUX: Self = Self(11);
169
170    /// Only for dealing with external data structures, never use internally.
171    #[doc(hidden)]
172    pub const fn from_u32_unchecked(value: u32) -> Self {
173        Self(value)
174    }
175
176    /// Converts this ID to an integer value.
177    pub const fn as_u32(self) -> u32 {
178        self.0
179    }
180}
181
182/// Event emitted by EraVM.
183///
184/// vm2 records events only from the `EventWriter` system contract (`0x800d`), the sole contract
185/// that runs the `Event` opcode in practice. `zk_evm` instead records events from any emitter
186/// (keeping the emitter address) and filters down to the `EventWriter` later. Both yield the same
187/// event set, so there is no `address` field here — the originating contract is encoded in the
188/// event payload, as in `zk_evm`.
189#[derive(Debug, Clone, Copy, PartialEq)]
190pub struct Event {
191    /// Event key.
192    pub key: U256,
193    /// Event value.
194    pub value: U256,
195    /// Is this event first in a chain of events?
196    pub is_first: bool,
197    /// Shard identifier (currently, always set to 0).
198    pub shard_id: u8,
199    /// 0-based index of a transaction that has emitted this event.
200    pub tx_number: u16,
201}
202
203/// L2-to-L1 log emitted by EraVM.
204#[derive(Debug, Clone, Copy, PartialEq)]
205pub struct L2ToL1Log {
206    /// Log key.
207    pub key: U256,
208    /// Log value.
209    pub value: U256,
210    /// Is this a service log?
211    pub is_service: bool,
212    /// Address of the contract that has emitted this log.
213    pub address: H160,
214    /// Shard identifier (currently, always set to 0).
215    pub shard_id: u8,
216    /// 0-based index of a transaction that has emitted this event.
217    pub tx_number: u16,
218}
219
220#[cfg(test)]
221pub(crate) mod testonly {
222    use primitive_types::{H160, U256};
223
224    use super::{
225        CallframeInterface, Event, Flags, GlobalStateInterface, HeapId, L2ToL1Log, StateInterface,
226    };
227
228    #[derive(Debug)]
229    pub(crate) struct DummyState;
230
231    impl StateInterface for DummyState {
232        fn read_register(&self, _: u8) -> (U256, bool) {
233            unimplemented!()
234        }
235
236        fn set_register(&mut self, _: u8, _: U256, _: bool) {
237            unimplemented!()
238        }
239
240        fn current_frame(&mut self) -> impl CallframeInterface + '_ {
241            DummyState
242        }
243
244        fn number_of_callframes(&self) -> usize {
245            unimplemented!()
246        }
247
248        fn callframe(&mut self, _: usize) -> impl CallframeInterface + '_ {
249            DummyState
250        }
251
252        fn read_heap_byte(&self, _: HeapId, _: u32) -> u8 {
253            unimplemented!()
254        }
255
256        fn read_heap_u256(&self, _: HeapId, _: u32) -> U256 {
257            unimplemented!()
258        }
259
260        fn write_heap_u256(&mut self, _: HeapId, _: u32, _: U256) {
261            unimplemented!()
262        }
263
264        fn flags(&self) -> Flags {
265            unimplemented!()
266        }
267
268        fn set_flags(&mut self, _: Flags) {
269            unimplemented!()
270        }
271
272        fn transaction_number(&self) -> u16 {
273            unimplemented!()
274        }
275
276        fn set_transaction_number(&mut self, _: u16) {
277            unimplemented!()
278        }
279
280        fn context_u128_register(&self) -> u128 {
281            unimplemented!()
282        }
283
284        fn set_context_u128_register(&mut self, _: u128) {
285            unimplemented!()
286        }
287
288        fn get_storage_state(&self) -> impl Iterator<Item = ((H160, U256), U256)> {
289            std::iter::empty()
290        }
291
292        fn get_transient_storage_state(&self) -> impl Iterator<Item = ((H160, U256), U256)> {
293            std::iter::empty()
294        }
295
296        fn get_transient_storage(&self, _: H160, _: U256) -> U256 {
297            unimplemented!()
298        }
299
300        fn write_transient_storage(&mut self, _: H160, _: U256, _: U256) {
301            unimplemented!()
302        }
303
304        fn events(&self) -> impl Iterator<Item = Event> {
305            std::iter::empty()
306        }
307
308        fn l2_to_l1_logs(&self) -> impl Iterator<Item = L2ToL1Log> {
309            std::iter::empty()
310        }
311
312        fn pubdata(&self) -> i32 {
313            unimplemented!()
314        }
315
316        fn set_pubdata(&mut self, _: i32) {
317            unimplemented!()
318        }
319    }
320
321    impl GlobalStateInterface for DummyState {
322        fn get_storage(&mut self, _: H160, _: U256) -> U256 {
323            unimplemented!()
324        }
325    }
326
327    impl CallframeInterface for DummyState {
328        fn address(&self) -> H160 {
329            unimplemented!()
330        }
331
332        fn set_address(&mut self, _: H160) {
333            unimplemented!()
334        }
335
336        fn code_address(&self) -> H160 {
337            unimplemented!()
338        }
339
340        fn set_code_address(&mut self, _: H160) {
341            unimplemented!()
342        }
343
344        fn caller(&self) -> H160 {
345            unimplemented!()
346        }
347
348        fn set_caller(&mut self, _: H160) {
349            unimplemented!()
350        }
351
352        fn program_counter(&self) -> Option<u16> {
353            unimplemented!()
354        }
355
356        fn set_program_counter(&mut self, _: u16) {
357            unimplemented!()
358        }
359
360        fn exception_handler(&self) -> u16 {
361            unimplemented!()
362        }
363
364        fn set_exception_handler(&mut self, _: u16) {
365            unimplemented!()
366        }
367
368        fn is_static(&self) -> bool {
369            unimplemented!()
370        }
371
372        fn is_kernel(&self) -> bool {
373            unimplemented!()
374        }
375
376        fn gas(&self) -> u32 {
377            unimplemented!()
378        }
379
380        fn set_gas(&mut self, _: u32) {
381            unimplemented!()
382        }
383
384        fn context_u128(&self) -> u128 {
385            unimplemented!()
386        }
387
388        fn set_context_u128(&mut self, _: u128) {
389            unimplemented!()
390        }
391
392        fn is_near_call(&self) -> bool {
393            unimplemented!()
394        }
395
396        fn read_stack(&self, _: u16) -> (U256, bool) {
397            unimplemented!()
398        }
399
400        fn write_stack(&mut self, _: u16, _: U256, _: bool) {
401            unimplemented!()
402        }
403
404        fn stack_pointer(&self) -> u16 {
405            unimplemented!()
406        }
407
408        fn set_stack_pointer(&mut self, _: u16) {
409            unimplemented!()
410        }
411
412        fn heap(&self) -> HeapId {
413            unimplemented!()
414        }
415
416        fn heap_bound(&self) -> u32 {
417            unimplemented!()
418        }
419
420        fn set_heap_bound(&mut self, _: u32) {
421            unimplemented!()
422        }
423
424        fn aux_heap(&self) -> HeapId {
425            unimplemented!()
426        }
427
428        fn aux_heap_bound(&self) -> u32 {
429            unimplemented!()
430        }
431
432        fn set_aux_heap_bound(&mut self, _: u32) {
433            unimplemented!()
434        }
435
436        fn read_contract_code(&self, _: u16) -> U256 {
437            unimplemented!()
438        }
439    }
440}