anvil_zksync_core/
bootloader_debug.rs

1use std::sync::{Arc, RwLock};
2use zksync_multivm::{
3    interface::tracer::VmExecutionStopReason, tracers::dynamic::vm_1_5_2::DynTracer,
4    IntoOldVmTracer,
5};
6
7use zksync_multivm::interface::storage::WriteStorage;
8use zksync_multivm::tracers::old::OldTracers;
9use zksync_multivm::vm_latest::{
10    constants::BOOTLOADER_HEAP_PAGE, BootloaderState, HistoryMode, SimpleMemory, VmTracer,
11    ZkSyncVmState,
12};
13use zksync_types::U256;
14
15/// Magic value that we put in bootloader.yul at the beginning of the debug section - to detect that
16/// debugger was enabled.
17const DEBUG_START_SENTINEL: u64 = 1337;
18
19// Taken from bootloader.yul (MAX_MEM_SIZE)
20const MAX_MEMORY_BYTES: usize = 63_800_000;
21
22// Taken from Systemconfig.json
23const MAX_TRANSACTIONS: usize = 10000;
24
25const RESULTS_BYTES_OFFSET: usize = MAX_MEMORY_BYTES - MAX_TRANSACTIONS * 32;
26
27const VM_HOOKS_PARAMS: usize = 3;
28
29const VM_HOOKS_START: usize = RESULTS_BYTES_OFFSET - (VM_HOOKS_PARAMS + 1) * 32;
30
31const DEBUG_SLOTS: usize = 32;
32const DEBUG_START_BYTE: usize = VM_HOOKS_START - DEBUG_SLOTS * 32;
33
34const DEBUG_START_SLOT: usize = DEBUG_START_BYTE / 32;
35
36/// Struct that represents the additional debug information that we can get from bootloader.
37/// Bootloader puts them in a special memory region after each transaction, and we can load them with this struct.
38
39#[derive(Debug, Clone)]
40pub struct BootloaderDebug {
41    /// Amount of gas that user attached to the transaction.
42    pub total_gas_limit_from_user: U256,
43    /// If provided more gas than the system can support. (this 'reserved gas' will not be used and simply refunded at the end).
44    pub reserved_gas: U256,
45    /// Amount of gas that user has to pay for each pubdata byte.
46    pub gas_per_pubdata: U256,
47    /// Amount of gas left after intrinsic (block creation) fees.
48    pub gas_limit_after_intrinsic: U256,
49    /// Amount of gas left after account validation.
50    pub gas_after_validation: U256,
51    /// Amount of gas spent on actual function execution.
52    pub gas_spent_on_execution: U256,
53
54    /// Gas spent on factory dependencies and bytecode preparation.
55    pub gas_spent_on_bytecode_preparation: U256,
56
57    /// Amount of refund computed by the system.
58    pub refund_computed: U256,
59    /// Amount of refund provided by the operator (it might be larger than refund computed - for example due to pubdata compression).
60    pub refund_by_operator: U256,
61
62    /// Fixed amount of gas for each transaction.
63    pub intrinsic_overhead: U256,
64
65    // Closing a block has a non-trivial cost for the operator (they have to run the prover, and commit results to L1).
66    // That's why we have to judge how much a given transaction is contributing the operator closer to sealing the block.
67    /// The maximum amount that operator could have requested.
68    pub required_overhead: U256,
69
70    /// How much did operator request for the block.
71    pub operator_overhead: U256,
72
73    /// The amount of the overhead that transaction length it responsible for.
74    pub overhead_for_length: U256,
75    /// The amount of the overhead that simply using a slot of the block is responsible for.
76    pub overhead_for_slot: U256,
77}
78
79/// The role of this tracer is to read the memory slots directly from bootloader memory at
80/// the end of VM execution - and put them into BootloaderDebug object.
81#[derive(Debug, Clone)]
82pub struct BootloaderDebugTracer {
83    pub result: Arc<RwLock<Result<BootloaderDebug, String>>>,
84}
85
86impl BootloaderDebugTracer {
87    pub fn new(result: Arc<RwLock<Result<BootloaderDebug, String>>>) -> Self {
88        Self { result }
89    }
90}
91
92impl<S, H: HistoryMode> DynTracer<S, SimpleMemory<H>> for BootloaderDebugTracer {}
93
94fn load_debug_slot<H: HistoryMode>(memory: &SimpleMemory<H>, slot: usize) -> U256 {
95    memory
96        .read_slot(BOOTLOADER_HEAP_PAGE as usize, DEBUG_START_SLOT + slot)
97        .value
98}
99
100impl<S: WriteStorage, H: HistoryMode> VmTracer<S, H> for BootloaderDebugTracer {
101    fn after_vm_execution(
102        &mut self,
103        state: &mut ZkSyncVmState<S, H>,
104        _bootloader_state: &BootloaderState,
105        _stop_reason: VmExecutionStopReason,
106    ) {
107        *self.result.write().unwrap() = BootloaderDebug::load_from_memory(&state.memory);
108    }
109}
110
111impl BootloaderDebug {
112    pub fn load_from_memory<H: HistoryMode>(memory: &SimpleMemory<H>) -> Result<Self, String> {
113        if load_debug_slot(memory, 0) != U256::from(DEBUG_START_SENTINEL) {
114            Err(
115                "Debug slot has wrong value. Probably bootloader slot mapping has changed."
116                    .to_owned(),
117            )
118        } else {
119            Ok(BootloaderDebug {
120                total_gas_limit_from_user: load_debug_slot(memory, 1),
121                reserved_gas: load_debug_slot(memory, 2),
122                gas_per_pubdata: load_debug_slot(memory, 3),
123                gas_limit_after_intrinsic: load_debug_slot(memory, 4),
124                gas_after_validation: load_debug_slot(memory, 5),
125                gas_spent_on_execution: load_debug_slot(memory, 6),
126                gas_spent_on_bytecode_preparation: load_debug_slot(memory, 7),
127                refund_computed: load_debug_slot(memory, 8),
128                refund_by_operator: load_debug_slot(memory, 9),
129                intrinsic_overhead: load_debug_slot(memory, 10),
130                operator_overhead: load_debug_slot(memory, 11),
131                required_overhead: load_debug_slot(memory, 12),
132                overhead_for_length: load_debug_slot(memory, 13),
133                overhead_for_slot: load_debug_slot(memory, 14),
134            })
135        }
136    }
137}
138
139//
140// The rest of the file contains stub tracer implementations for older VM versions.
141// Reasoning: `BootloaderDebugTracer` needs to implement `MultiVmTracer` to be compatible with era
142// abstractions such as `BatchExecutor` and `BatchExecutorFactory`.
143//
144
145impl<S, H: zksync_multivm::vm_1_4_1::HistoryMode>
146    zksync_multivm::tracers::dynamic::vm_1_4_1::DynTracer<
147        S,
148        zksync_multivm::vm_1_4_1::SimpleMemory<H>,
149    > for BootloaderDebugTracer
150{
151}
152
153impl<S: WriteStorage, H: zksync_multivm::vm_1_4_1::HistoryMode>
154    zksync_multivm::vm_1_4_1::VmTracer<S, H> for BootloaderDebugTracer
155{
156    fn after_vm_execution(
157        &mut self,
158        _state: &mut zksync_multivm::vm_1_4_1::ZkSyncVmState<S, H>,
159        _bootloader_state: &zksync_multivm::vm_1_4_1::BootloaderState,
160        _stop_reason: VmExecutionStopReason,
161    ) {
162        todo!()
163    }
164}
165
166impl<S, H: zksync_multivm::vm_1_4_2::HistoryMode>
167    zksync_multivm::tracers::dynamic::vm_1_4_1::DynTracer<
168        S,
169        zksync_multivm::vm_1_4_2::SimpleMemory<H>,
170    > for BootloaderDebugTracer
171{
172}
173
174impl<S: WriteStorage, H: zksync_multivm::vm_1_4_2::HistoryMode>
175    zksync_multivm::vm_1_4_2::VmTracer<S, H> for BootloaderDebugTracer
176{
177    fn after_vm_execution(
178        &mut self,
179        _state: &mut zksync_multivm::vm_1_4_2::ZkSyncVmState<S, H>,
180        _bootloader_state: &zksync_multivm::vm_1_4_2::BootloaderState,
181        _stop_reason: VmExecutionStopReason,
182    ) {
183        todo!()
184    }
185}
186
187impl<S: WriteStorage, H: zksync_multivm::vm_boojum_integration::HistoryMode>
188    zksync_multivm::tracers::dynamic::vm_1_4_0::DynTracer<
189        S,
190        zksync_multivm::vm_boojum_integration::SimpleMemory<H>,
191    > for BootloaderDebugTracer
192{
193}
194
195impl<S: WriteStorage, H: zksync_multivm::vm_boojum_integration::HistoryMode>
196    zksync_multivm::vm_boojum_integration::VmTracer<S, H> for BootloaderDebugTracer
197{
198    fn after_vm_execution(
199        &mut self,
200        _state: &mut zksync_multivm::vm_boojum_integration::ZkSyncVmState<S, H>,
201        _bootloader_state: &zksync_multivm::vm_boojum_integration::BootloaderState,
202        _stop_reason: VmExecutionStopReason,
203    ) {
204        todo!()
205    }
206}
207
208impl<S: WriteStorage, H: zksync_multivm::vm_refunds_enhancement::HistoryMode>
209    zksync_multivm::tracers::dynamic::vm_1_3_3::DynTracer<
210        S,
211        zksync_multivm::vm_refunds_enhancement::SimpleMemory<H>,
212    > for BootloaderDebugTracer
213{
214}
215
216impl<S: WriteStorage, H: zksync_multivm::vm_refunds_enhancement::HistoryMode>
217    zksync_multivm::vm_refunds_enhancement::VmTracer<S, H> for BootloaderDebugTracer
218{
219    fn after_vm_execution(
220        &mut self,
221        _state: &mut zksync_multivm::vm_refunds_enhancement::ZkSyncVmState<S, H>,
222        _bootloader_state: &zksync_multivm::vm_refunds_enhancement::BootloaderState,
223        _stop_reason: VmExecutionStopReason,
224    ) {
225        todo!()
226    }
227}
228
229impl<S: WriteStorage, H: zksync_multivm::vm_virtual_blocks::HistoryMode>
230    zksync_multivm::tracers::dynamic::vm_1_3_3::DynTracer<
231        S,
232        zksync_multivm::vm_virtual_blocks::SimpleMemory<H>,
233    > for BootloaderDebugTracer
234{
235}
236
237impl<H: zksync_multivm::vm_virtual_blocks::HistoryMode>
238    zksync_multivm::vm_virtual_blocks::ExecutionEndTracer<H> for BootloaderDebugTracer
239{
240}
241
242impl<S: WriteStorage, H: zksync_multivm::vm_virtual_blocks::HistoryMode>
243    zksync_multivm::vm_virtual_blocks::ExecutionProcessing<S, H> for BootloaderDebugTracer
244{
245}
246
247impl<S: WriteStorage, H: zksync_multivm::vm_virtual_blocks::HistoryMode>
248    zksync_multivm::vm_virtual_blocks::VmTracer<S, H> for BootloaderDebugTracer
249{
250}
251
252impl IntoOldVmTracer for BootloaderDebugTracer {
253    fn old_tracer(&self) -> OldTracers {
254        todo!()
255    }
256}