Skip to content

Commit

Permalink
refactor(api): Brush up VM storage overrides (matter-labs#2463)
Browse files Browse the repository at this point in the history
## What ❔

Brush up VM storage overrides as introduced in
matter-labs#1358.

## Why ❔

The overrides implementation looks overly complex and isn't correctly
localized by domain (located in the `state` crate, while the
functionality is API server-specific). This worsens maintainability.

## Checklist

- [x] PR title corresponds to the body of PR (we generate changelog
entries from PRs).
- [x] Tests for the changes have been added / updated.
- [x] Documentation comments have been added / updated.
- [x] Code has been formatted via `zk fmt` and `zk lint`.
  • Loading branch information
slowli authored Jul 24, 2024
1 parent 5eab94c commit 8cf8fc7
Show file tree
Hide file tree
Showing 10 changed files with 386 additions and 224 deletions.
9 changes: 0 additions & 9 deletions core/lib/state/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
use std::{cell::RefCell, collections::HashMap, fmt, rc::Rc};

use zksync_types::{
api::state_override::StateOverride,
get_known_code_key,
storage::{StorageKey, StorageValue},
H256,
Expand All @@ -30,7 +29,6 @@ pub use self::{
},
shadow_storage::ShadowStorage,
storage_factory::{BatchDiff, PgOrRocksdbStorage, ReadStorageFactory, RocksdbWithMemory},
storage_overrides::StorageOverrides,
storage_view::{StorageView, StorageViewCache, StorageViewMetrics},
witness::WitnessStorage,
};
Expand All @@ -42,7 +40,6 @@ mod postgres;
mod rocksdb;
mod shadow_storage;
mod storage_factory;
mod storage_overrides;
mod storage_view;
#[cfg(test)]
mod test_utils;
Expand Down Expand Up @@ -92,9 +89,3 @@ pub trait WriteStorage: ReadStorage {

/// Smart pointer to [`WriteStorage`].
pub type StoragePtr<S> = Rc<RefCell<S>>;

/// Functionality to override the storage state.
pub trait OverrideStorage {
/// Apply state override to the storage.
fn apply_state_override(&mut self, overrides: &StateOverride);
}
150 changes: 0 additions & 150 deletions core/lib/state/src/storage_overrides.rs
Original file line number Diff line number Diff line change
@@ -1,150 +0,0 @@
use std::{cell::RefCell, collections::HashMap, fmt, rc::Rc};

use zksync_types::{
api::state_override::{OverrideState, StateOverride},
get_code_key, get_nonce_key,
utils::{decompose_full_nonce, nonces_to_full_nonce, storage_key_for_eth_balance},
AccountTreeId, StorageKey, StorageValue, H256, U256,
};
use zksync_utils::{bytecode::hash_bytecode, h256_to_u256, u256_to_h256};

use crate::{OverrideStorage, ReadStorage};

/// A storage view that allows to override some of the storage values.
#[derive(Debug)]
pub struct StorageOverrides<S> {
storage_handle: S,
overridden_factory_deps: HashMap<H256, Vec<u8>>,
overridden_account_state: HashMap<AccountTreeId, HashMap<H256, H256>>,
overridden_account_state_diff: HashMap<AccountTreeId, HashMap<H256, H256>>,
overridden_balance: HashMap<StorageKey, U256>,
overridden_nonce: HashMap<StorageKey, U256>,
overridden_code: HashMap<StorageKey, H256>,
}

impl<S: ReadStorage + fmt::Debug> StorageOverrides<S> {
/// Creates a new storage view based on the underlying storage.
pub fn new(storage: S) -> Self {
Self {
storage_handle: storage,
overridden_factory_deps: HashMap::new(),
overridden_account_state: HashMap::new(),
overridden_account_state_diff: HashMap::new(),
overridden_balance: HashMap::new(),
overridden_nonce: HashMap::new(),
overridden_code: HashMap::new(),
}
}

/// Overrides a factory dependency code.
pub fn store_factory_dep(&mut self, hash: H256, code: Vec<u8>) {
self.overridden_factory_deps.insert(hash, code);
}

/// Overrides an account entire state.
pub fn override_account_state(&mut self, account: AccountTreeId, state: HashMap<H256, H256>) {
self.overridden_account_state.insert(account, state);
}

/// Overrides an account state diff.
pub fn override_account_state_diff(
&mut self,
account: AccountTreeId,
state_diff: HashMap<H256, H256>,
) {
self.overridden_account_state_diff
.insert(account, state_diff);
}

/// Make a Rc RefCell ptr to the storage
pub fn to_rc_ptr(self) -> Rc<RefCell<Self>> {
Rc::new(RefCell::new(self))
}
}

impl<S: ReadStorage + fmt::Debug> ReadStorage for StorageOverrides<S> {
fn read_value(&mut self, key: &StorageKey) -> StorageValue {
if let Some(balance) = self.overridden_balance.get(key) {
return u256_to_h256(*balance);
}
if let Some(code) = self.overridden_code.get(key) {
return *code;
}

if let Some(nonce) = self.overridden_nonce.get(key) {
return u256_to_h256(*nonce);
}

if let Some(account_state) = self.overridden_account_state.get(key.account()) {
if let Some(value) = account_state.get(key.key()) {
return *value;
}
return H256::zero();
}

if let Some(account_state_diff) = self.overridden_account_state_diff.get(key.account()) {
if let Some(value) = account_state_diff.get(key.key()) {
return *value;
}
}

self.storage_handle.read_value(key)
}

fn is_write_initial(&mut self, key: &StorageKey) -> bool {
self.storage_handle.is_write_initial(key)
}

fn load_factory_dep(&mut self, hash: H256) -> Option<Vec<u8>> {
self.overridden_factory_deps
.get(&hash)
.cloned()
.or_else(|| self.storage_handle.load_factory_dep(hash))
}

fn get_enumeration_index(&mut self, key: &StorageKey) -> Option<u64> {
self.storage_handle.get_enumeration_index(key)
}
}

impl<S: ReadStorage + fmt::Debug> OverrideStorage for StorageOverrides<S> {
fn apply_state_override(&mut self, state_override: &StateOverride) {
for (account, overrides) in state_override.iter() {
if let Some(balance) = overrides.balance {
let balance_key = storage_key_for_eth_balance(account);
self.overridden_balance.insert(balance_key, balance);
}

if let Some(nonce) = overrides.nonce {
let nonce_key = get_nonce_key(account);
let full_nonce = self.read_value(&nonce_key);
let (_, deployment_nonce) = decompose_full_nonce(h256_to_u256(full_nonce));
let new_full_nonce = nonces_to_full_nonce(nonce, deployment_nonce);
self.overridden_nonce.insert(nonce_key, new_full_nonce);
}

if let Some(code) = &overrides.code {
let code_key = get_code_key(account);
let code_hash = hash_bytecode(&code.0);
self.overridden_code.insert(code_key, code_hash);
self.store_factory_dep(code_hash, code.0.clone());
}

match &overrides.state {
Some(OverrideState::State(state)) => {
self.override_account_state(AccountTreeId::new(*account), state.clone());
}
Some(OverrideState::StateDiff(state_diff)) => {
for (key, value) in state_diff {
let account_state = self
.overridden_account_state_diff
.entry(AccountTreeId::new(*account))
.or_default();
account_state.insert(*key, *value);
}
}
None => {}
}
}
}
}
10 changes: 2 additions & 8 deletions core/lib/state/src/storage_view.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ use std::{
time::{Duration, Instant},
};

use zksync_types::{api::state_override::StateOverride, StorageKey, StorageValue, H256};
use zksync_types::{StorageKey, StorageValue, H256};

use crate::{OverrideStorage, ReadStorage, WriteStorage};
use crate::{ReadStorage, WriteStorage};

/// Metrics for [`StorageView`].
#[derive(Debug, Default, Clone, Copy)]
Expand Down Expand Up @@ -224,12 +224,6 @@ impl<S: ReadStorage + fmt::Debug> WriteStorage for StorageView<S> {
}
}

impl<S: ReadStorage + fmt::Debug + OverrideStorage> OverrideStorage for StorageView<S> {
fn apply_state_override(&mut self, state_override: &StateOverride) {
self.storage_handle.apply_state_override(state_override);
}
}

#[cfg(test)]
mod test {
use zksync_types::{AccountTreeId, Address, H256};
Expand Down
Loading

0 comments on commit 8cf8fc7

Please sign in to comment.