1use primitive_types::{H160, U256};
2use zksync_vm2_interface::{HeapId, Tracer};
3
4use crate::{
5 addressing_modes::Addressable,
6 callframe::{Callframe, CallframeSnapshot},
7 fat_pointer::FatPointer,
8 heap::Heaps,
9 page_ids::{first_dynamic_base_page, next_page_group},
10 predication::Flags,
11 program::Program,
12 stack::Stack,
13 world_diff::Snapshot,
14 World,
15};
16
17#[derive(Debug)]
19pub(crate) struct State<T, W> {
20 pub(crate) registers: [U256; 16],
21 pub(crate) register_pointer_flags: u16,
22 pub(crate) flags: Flags,
23 pub(crate) current_frame: Callframe<T, W>,
24 pub(crate) previous_frames: Vec<Callframe<T, W>>,
27 pub(crate) heaps: Heaps,
28 pub(crate) transaction_number: u16,
29 pub(crate) context_u128: u128,
30 pub(crate) next_base_page: u32,
31 pub(crate) dst1_was_updated: bool,
35}
36
37impl<T, W> State<T, W> {
38 pub(crate) fn new(
39 address: H160,
40 caller: H160,
41 calldata: &[u8],
42 gas: u32,
43 program: Program<T, W>,
44 world_before_this_frame: Snapshot,
45 stack: Box<Stack>,
46 ) -> Self {
47 let mut registers: [U256; 16] = Default::default();
48 registers[1] = FatPointer {
49 memory_page: HeapId::FIRST_CALLDATA,
50 offset: 0,
51 start: 0,
52 length: u32::try_from(calldata.len()).expect("calldata length overflow"),
53 }
54 .into_u256();
55
56 Self {
57 registers,
58 register_pointer_flags: 1 << 1, flags: Flags::new(false, false, false),
60 current_frame: Callframe::new(
61 address,
62 address,
63 caller,
64 program,
65 stack,
66 HeapId::FIRST,
67 HeapId::FIRST_AUX,
68 HeapId::FIRST_CALLDATA,
69 gas,
70 0,
71 0,
72 false,
73 false,
74 world_before_this_frame,
75 ),
76 previous_frames: vec![],
77
78 heaps: Heaps::new(calldata),
79
80 transaction_number: 0,
81 context_u128: 0,
82 next_base_page: first_dynamic_base_page(),
83 dst1_was_updated: false,
84 }
85 }
86
87 #[inline(always)]
88 pub(crate) fn use_gas(&mut self, amount: u32) -> Result<(), ()> {
89 if self.current_frame.gas >= amount {
90 self.current_frame.gas -= amount;
91 Ok(())
92 } else {
93 self.current_frame.gas = 0;
94 Err(())
95 }
96 }
97
98 pub(crate) fn set_context_u128(&mut self, value: u128) {
99 self.context_u128 = value;
100 }
101
102 pub(crate) fn get_context_u128(&self) -> u128 {
103 self.current_frame.context_u128
104 }
105
106 pub(crate) const fn next_base_page(&self) -> u32 {
107 self.next_base_page
108 }
109
110 pub(crate) fn allocate_base_page(&mut self) -> u32 {
115 let base_page = self.next_base_page;
116 self.next_base_page = next_page_group(self.next_base_page);
117 base_page
118 }
119}
120
121impl<T: Tracer, W: World<T>> State<T, W> {
122 pub(crate) fn total_unspent_gas(&self) -> u32 {
124 self.current_frame.gas
125 + self
126 .previous_frames
127 .iter()
128 .map(Callframe::contained_gas)
129 .sum::<u32>()
130 }
131
132 pub(crate) fn snapshot(&self) -> StateSnapshot {
133 StateSnapshot {
134 registers: self.registers,
135 register_pointer_flags: self.register_pointer_flags,
136 flags: self.flags.clone(),
137 bootloader_frame: self.current_frame.snapshot(),
138 bootloader_heap_snapshot: self.heaps.snapshot(),
139 dynamic_heap_groups: self.heaps.dynamic_len(),
140 transaction_number: self.transaction_number,
141 context_u128: self.context_u128,
142 next_base_page: self.next_base_page,
143 }
144 }
145
146 pub(crate) fn rollback(
147 &mut self,
148 snapshot: StateSnapshot,
149 mut is_heap_pinned: impl FnMut(HeapId) -> bool,
150 ) {
151 let StateSnapshot {
152 registers,
153 register_pointer_flags,
154 flags,
155 bootloader_frame,
156 bootloader_heap_snapshot,
157 dynamic_heap_groups,
158 transaction_number,
159 context_u128,
160 next_base_page,
161 } = snapshot;
162
163 for heap in self.current_frame.rollback(bootloader_frame) {
164 if !is_heap_pinned(heap) {
165 self.heaps.deallocate(heap);
166 }
167 }
168 self.heaps.rollback(bootloader_heap_snapshot);
169
170 self.heaps.truncate_dynamic_to(dynamic_heap_groups);
175
176 self.registers = registers;
177 self.register_pointer_flags = register_pointer_flags;
178 self.flags = flags;
179 self.transaction_number = transaction_number;
180 self.context_u128 = context_u128;
181 self.next_base_page = next_base_page;
182
183 self.dst1_was_updated = false;
187 }
188
189 pub(crate) fn delete_history(&mut self) {
190 self.heaps.delete_history();
191 }
192}
193
194impl<T, W> Clone for State<T, W> {
195 fn clone(&self) -> Self {
196 Self {
197 registers: self.registers,
198 register_pointer_flags: self.register_pointer_flags,
199 flags: self.flags.clone(),
200 current_frame: self.current_frame.clone(),
201 previous_frames: self.previous_frames.clone(),
202 heaps: self.heaps.clone(),
203 transaction_number: self.transaction_number,
204 context_u128: self.context_u128,
205 next_base_page: self.next_base_page,
206 dst1_was_updated: self.dst1_was_updated,
207 }
208 }
209}
210
211impl<T, W> PartialEq for State<T, W> {
212 fn eq(&self, other: &Self) -> bool {
213 self.registers == other.registers
216 && self.register_pointer_flags == other.register_pointer_flags
217 && self.flags == other.flags
218 && self.transaction_number == other.transaction_number
219 && self.context_u128 == other.context_u128
220 && self.next_base_page == other.next_base_page
221 && self.current_frame == other.current_frame
222 && self.previous_frames == other.previous_frames
223 && self.heaps == other.heaps
224 }
225}
226
227impl<T, W> Addressable for State<T, W> {
228 fn registers(&mut self) -> &mut [U256; 16] {
229 &mut self.registers
230 }
231
232 fn register_pointer_flags(&mut self) -> &mut u16 {
233 &mut self.register_pointer_flags
234 }
235
236 fn read_stack(&mut self, slot: u16) -> U256 {
237 self.current_frame.stack.get(slot)
238 }
239
240 fn write_stack(&mut self, slot: u16, value: U256) {
241 self.current_frame.stack.set(slot, value);
242 }
243
244 fn stack_pointer(&mut self) -> &mut u16 {
245 &mut self.current_frame.sp
246 }
247
248 fn read_stack_pointer_flag(&mut self, slot: u16) -> bool {
249 self.current_frame.stack.get_pointer_flag(slot)
250 }
251
252 fn set_stack_pointer_flag(&mut self, slot: u16) {
253 self.current_frame.stack.set_pointer_flag(slot);
254 }
255
256 fn clear_stack_pointer_flag(&mut self, slot: u16) {
257 self.current_frame.stack.clear_pointer_flag(slot);
258 }
259
260 fn mark_dst1_written(&mut self) {
261 self.dst1_was_updated = true;
262 }
263
264 fn code_page(&self) -> &[U256] {
265 self.current_frame.program.code_page()
266 }
267
268 fn in_kernel_mode(&self) -> bool {
269 self.current_frame.is_kernel
270 }
271}
272
273#[derive(Debug)]
274pub(crate) struct StateSnapshot {
275 registers: [U256; 16],
276 register_pointer_flags: u16,
277 flags: Flags,
278 bootloader_frame: CallframeSnapshot,
279 bootloader_heap_snapshot: (usize, usize),
280 dynamic_heap_groups: usize,
281 transaction_number: u16,
282 context_u128: u128,
283 next_base_page: u32,
284}