use vise::{Counter, Metrics};
use zksync_types::{L1BatchNumber, StorageKey, StorageValue, H256};
use crate::ReadStorage;
#[allow(clippy::struct_field_names)]
#[derive(Debug, Metrics)]
#[metrics(prefix = "shadow_storage")]
struct ShadowStorageMetrics {
read_value_mismatch: Counter,
is_write_initial_mismatch: Counter,
load_factory_dep_mismatch: Counter,
get_enumeration_index_mismatch: Counter,
}
#[vise::register]
static METRICS: vise::Global<ShadowStorageMetrics> = vise::Global::new();
#[derive(Debug)]
pub struct ShadowStorage<'a> {
source_storage: Box<dyn ReadStorage + 'a>,
to_check_storage: Box<dyn ReadStorage + 'a>,
metrics: &'a ShadowStorageMetrics,
l1_batch_number: L1BatchNumber,
}
impl<'a> ShadowStorage<'a> {
pub fn new(
source_storage: Box<dyn ReadStorage + 'a>,
to_check_storage: Box<dyn ReadStorage + 'a>,
l1_batch_number: L1BatchNumber,
) -> Self {
Self {
source_storage,
to_check_storage,
metrics: &METRICS,
l1_batch_number,
}
}
}
impl ReadStorage for ShadowStorage<'_> {
fn read_value(&mut self, key: &StorageKey) -> StorageValue {
let source_value = self.source_storage.as_mut().read_value(key);
let expected_value = self.to_check_storage.as_mut().read_value(key);
if source_value != expected_value {
self.metrics.read_value_mismatch.inc();
tracing::error!(
"read_value({key:?}) -- l1_batch_number={:?} -- expected source={source_value:?} \
to be equal to to_check={expected_value:?}",
self.l1_batch_number
);
}
source_value
}
fn is_write_initial(&mut self, key: &StorageKey) -> bool {
let source_value = self.source_storage.as_mut().is_write_initial(key);
let expected_value = self.to_check_storage.as_mut().is_write_initial(key);
if source_value != expected_value {
self.metrics.is_write_initial_mismatch.inc();
tracing::error!(
"is_write_initial({key:?}) -- l1_batch_number={:?} -- expected source={source_value:?} \
to be equal to to_check={expected_value:?}",
self.l1_batch_number
);
}
source_value
}
fn load_factory_dep(&mut self, hash: H256) -> Option<Vec<u8>> {
let source_value = self.source_storage.load_factory_dep(hash);
let expected_value = self.to_check_storage.load_factory_dep(hash);
if source_value != expected_value {
self.metrics.load_factory_dep_mismatch.inc();
tracing::error!(
"load_factory_dep({hash:?}) -- l1_batch_number={:?} -- expected source={source_value:?} \
to be equal to to_check={expected_value:?}",
self.l1_batch_number
);
}
source_value
}
fn get_enumeration_index(&mut self, key: &StorageKey) -> Option<u64> {
let source_value = self.source_storage.as_mut().get_enumeration_index(key);
let expected_value = self.to_check_storage.as_mut().get_enumeration_index(key);
if source_value != expected_value {
tracing::error!(
"get_enumeration_index({key:?}) -- l1_batch_number={:?} -- \
expected source={source_value:?} to be equal to to_check={expected_value:?}",
self.l1_batch_number
);
self.metrics.get_enumeration_index_mismatch.inc();
}
source_value
}
}