anvil_zksync_core/node/
storage_logs.rs

1use std::collections::HashMap;
2
3use crate::formatter::log::Formatter;
4use crate::formatter::pubdata_bytes::PubdataBytesInfo;
5
6use anvil_zksync_common::sh_println;
7use anvil_zksync_types::ShowStorageLogs;
8use zksync_multivm::interface::VmExecutionResultAndLogs;
9use zksync_types::h256_to_u256;
10use zksync_types::{
11    utils::storage_key_for_eth_balance,
12    writes::{
13        compression::compress_with_best_strategy, BYTES_PER_DERIVED_KEY,
14        BYTES_PER_ENUMERATION_INDEX,
15    },
16    StorageKey, BOOTLOADER_ADDRESS, SYSTEM_CONTEXT_ADDRESS,
17};
18use zksync_types::{StorageLogKind, StorageLogWithPreviousValue};
19
20fn is_storage_key_free(key: &StorageKey) -> bool {
21    key.address() == &SYSTEM_CONTEXT_ADDRESS
22        || *key == storage_key_for_eth_balance(&BOOTLOADER_ADDRESS)
23}
24
25fn compute_and_update_pubdata_cost(
26    cost_paid: &mut HashMap<StorageKey, u32>,
27    log_query: &StorageLogWithPreviousValue,
28) -> PubdataBytesInfo {
29    let storage_key = log_query.log.key;
30
31    if is_storage_key_free(&storage_key) {
32        PubdataBytesInfo::FreeSlot
33    } else {
34        // how many bytes it takes after compression.
35        let compressed_value_size = compress_with_best_strategy(
36            h256_to_u256(log_query.previous_value),
37            h256_to_u256(log_query.log.value),
38        )
39        .len() as u32;
40
41        let final_pubdata_cost = if log_query.log.kind == StorageLogKind::InitialWrite {
42            (BYTES_PER_DERIVED_KEY as u32) + compressed_value_size
43        } else {
44            (BYTES_PER_ENUMERATION_INDEX as u32) + compressed_value_size
45        };
46
47        let result = match cost_paid.get(&storage_key).copied() {
48            Some(already_paid) => {
49                let to_pay = final_pubdata_cost.saturating_sub(already_paid);
50                if to_pay > 0 {
51                    PubdataBytesInfo::AdditionalPayment(to_pay, final_pubdata_cost)
52                } else {
53                    PubdataBytesInfo::PaidAlready
54                }
55            }
56            None => PubdataBytesInfo::Paid(final_pubdata_cost),
57        };
58        cost_paid.insert(storage_key, final_pubdata_cost);
59        result
60    }
61}
62
63pub fn print_storage_logs_details(
64    show_storage_logs: ShowStorageLogs,
65    result: &VmExecutionResultAndLogs,
66) {
67    sh_println!("\n");
68    sh_println!(
69        "[Storage Logs] ({} entries)",
70        result.logs.storage_logs.len()
71    );
72
73    let mut cost_paid = HashMap::<StorageKey, u32>::default();
74
75    for (index, log_query) in result.logs.storage_logs.iter().enumerate() {
76        let pubdata_bytes_info = if matches!(
77            log_query.log.kind,
78            StorageLogKind::RepeatedWrite | StorageLogKind::InitialWrite
79        ) {
80            Some(compute_and_update_pubdata_cost(&mut cost_paid, log_query))
81        } else {
82            None
83        };
84
85        // Filter logs based on the selected storage log type
86        let should_print = match show_storage_logs {
87            ShowStorageLogs::Write => matches!(
88                log_query.log.kind,
89                StorageLogKind::RepeatedWrite | StorageLogKind::InitialWrite
90            ),
91            ShowStorageLogs::Paid => pubdata_bytes_info
92                .as_ref()
93                .map(|x| x.does_cost())
94                .unwrap_or_default(),
95            ShowStorageLogs::Read => log_query.log.kind == StorageLogKind::Read,
96            ShowStorageLogs::All => true,
97            _ => false,
98        };
99
100        if should_print {
101            let is_last = index == result.logs.storage_logs.len() - 1;
102            let mut formatter = Formatter::new();
103            formatter.print_storage_logs(log_query, pubdata_bytes_info, index + 1, is_last);
104        }
105    }
106}