Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(vm): Prestate tracer implementation #1306

Merged
merged 54 commits into from
Mar 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
1acf89e
prestate tracer
Jrigada Feb 27, 2024
746ebfe
prestate tracer with tests first iteration
Jrigada Feb 29, 2024
73905d3
`Merge branch 'main' of https://github.com/Jrigada/zksync-era into fe…
Jrigada Feb 29, 2024
1579b6b
zk fmt
Jrigada Feb 29, 2024
7fa2b0d
zk spell
Jrigada Mar 1, 2024
f65bd70
missing docs
Jrigada Mar 1, 2024
915a7d7
linter
Jrigada Mar 1, 2024
669b66a
remove unused imports
Jrigada Mar 1, 2024
5e26988
fmt
Jrigada Mar 1, 2024
d1ede97
Merge branch 'main' into feat-jrigada-prestate-tracer-implementation
Jrigada Mar 1, 2024
956a750
Merge branch 'main' into feat-jrigada-prestate-tracer-implementation
Jrigada Mar 1, 2024
67ac0b3
linter
Jrigada Mar 1, 2024
1903948
Merge branch 'feat-jrigada-prestate-tracer-implementation' of github.…
Jrigada Mar 1, 2024
0a470b8
Merge branch 'main' into feat-jrigada-prestate-tracer-implementation
Jrigada Mar 1, 2024
ab094ce
Merge branch 'main' into feat-jrigada-prestate-tracer-implementation
Jrigada Mar 4, 2024
227c5ce
move to before_execution
Jrigada Mar 4, 2024
7ac9f0c
Merge branch 'main' into feat-jrigada-prestate-tracer-implementation
Jrigada Mar 4, 2024
55b4c4b
linter
Jrigada Mar 4, 2024
2bbd935
Merge branch 'feat-jrigada-prestate-tracer-implementation' of github.…
Jrigada Mar 4, 2024
618accb
Merge branch 'main' into feat-jrigada-prestate-tracer-implementation
Jrigada Mar 5, 2024
4c28403
Merge branch 'main' into feat-jrigada-prestate-tracer-implementation
Jrigada Mar 5, 2024
dbc5430
Merge branch 'main' into feat-jrigada-prestate-tracer-implementation
Jrigada Mar 5, 2024
55b6a26
fix prestate addition of accounts
Jrigada Mar 6, 2024
0fc5d60
Merge branch 'main' into feat-jrigada-prestate-tracer-implementation
Jrigada Mar 6, 2024
f6e9ac7
spellcheck
Jrigada Mar 6, 2024
06875cb
Merge branch 'feat-jrigada-prestate-tracer-implementation' of github.…
Jrigada Mar 6, 2024
6424eeb
fix intermediate variables
Jrigada Mar 7, 2024
dfb22f1
Merge branch 'main' into feat-jrigada-prestate-tracer-implementation
Jrigada Mar 7, 2024
555a09d
Merge branch 'main' into feat-jrigada-prestate-tracer-implementation
Jrigada Mar 7, 2024
bd8cbfd
Merge branch 'main' into feat-jrigada-prestate-tracer-implementation
Jrigada Mar 8, 2024
dc7e356
previous vm integration
Jrigada Mar 11, 2024
3ce1fef
previous vm integration
Jrigada Mar 11, 2024
3a94ecf
Merge branch 'main' into feat-jrigada-prestate-tracer-implementation
Jrigada Mar 11, 2024
f4d8cdc
Merge branch 'main' into feat-jrigada-prestate-tracer-implementation
Jrigada Mar 12, 2024
0d1c382
move process storage for prestate logic to avoid repetition
Jrigada Mar 12, 2024
15a6574
Merge branch 'main' into feat-jrigada-prestate-tracer-implementation
Jrigada Mar 12, 2024
2360e66
Merge branch 'main' into feat-jrigada-prestate-tracer-implementation
Jrigada Mar 13, 2024
d96c470
storageAccess trait
Jrigada Mar 13, 2024
5a176f1
remove unused imports
Jrigada Mar 13, 2024
17dd2fb
Merge branch 'main' into feat-jrigada-prestate-tracer-implementation
Jrigada Mar 13, 2024
5283f64
remove unnecesary set_initial_value function
Jrigada Mar 14, 2024
aaa4fcc
Merge branch 'feat-jrigada-prestate-tracer-implementation' of github.…
Jrigada Mar 14, 2024
2ff7c09
Merge branch 'main' into feat-jrigada-prestate-tracer-implementation
Jrigada Mar 14, 2024
801f3d5
Merge branch 'main' into feat-jrigada-prestate-tracer-implementation
Jrigada Mar 14, 2024
4346de0
Merge branch 'main' into feat-jrigada-prestate-tracer-implementation
Jrigada Mar 15, 2024
1094d91
remove read_keys from the versions of vm that does not need them
Jrigada Mar 17, 2024
39dc18c
Merge branch 'main' into feat-jrigada-prestate-tracer-implementation
Jrigada Mar 17, 2024
68ecfe4
Merge branch 'main' into feat-jrigada-prestate-tracer-implementation
Jrigada Mar 18, 2024
ec4c40e
remove initial_values
Jrigada Mar 19, 2024
0b3033c
remove initial_values
Jrigada Mar 19, 2024
f5ce49b
remove initial_values
Jrigada Mar 19, 2024
d0fee57
Merge branch 'main' into feat-jrigada-prestate-tracer-implementation
Jrigada Mar 19, 2024
ce9eb75
remove dead code annotation and collect vec
Jrigada Mar 19, 2024
7d8792a
remove collect vec
Jrigada Mar 19, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions core/lib/multivm/src/tracers/mod.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
pub mod call_tracer;
mod multivm_dispatcher;
pub mod old_tracers;
pub mod prestate_tracer;
pub mod storage_invocation;
pub mod validator;

pub use call_tracer::CallTracer;
pub use multivm_dispatcher::TracerDispatcher;
pub use prestate_tracer::PrestateTracer;
pub use storage_invocation::StorageInvocations;
167 changes: 167 additions & 0 deletions core/lib/multivm/src/tracers/prestate_tracer/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
use std::{collections::HashMap, fmt, sync::Arc};

use once_cell::sync::OnceCell;
use zksync_state::{StoragePtr, WriteStorage};
use zksync_types::{
get_code_key, get_nonce_key, web3::signing::keccak256, AccountTreeId, Address, StorageKey,
StorageValue, H160, H256, L2_ETH_TOKEN_ADDRESS, U256,
};
use zksync_utils::{address_to_h256, h256_to_u256};

pub mod vm_1_4_1;
pub mod vm_latest;
pub mod vm_refunds_enhancement;
pub mod vm_virtual_blocks;

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Account {
pub balance: Option<U256>,
pub code: Option<U256>,
pub nonce: Option<U256>,
pub storage: Option<HashMap<H256, H256>>,
}

impl fmt::Display for Account {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
writeln!(f, "{{")?;
if let Some(balance) = self.balance {
writeln!(f, " balance: \"0x{:x}\",", balance)?;
}
if let Some(code) = &self.code {
writeln!(f, " code: \"{}\",", code)?;
}
if let Some(nonce) = self.nonce {
writeln!(f, " nonce: {},", nonce)?;
}
if let Some(storage) = &self.storage {
writeln!(f, " storage: {{")?;
for (key, value) in storage.iter() {
writeln!(f, " {}: \"{}\",", key, value)?;
}
writeln!(f, " }}")?;
}
writeln!(f, "}}")
}
}

type State = HashMap<Address, Account>;

#[derive(Debug, Clone)]
pub struct PrestateTracer {
pub pre: State,
pub post: State,
pub config: PrestateTracerConfig,
pub result: Arc<OnceCell<(State, State)>>,
Jrigada marked this conversation as resolved.
Show resolved Hide resolved
}

impl PrestateTracer {
pub fn new(diff_mode: bool, result: Arc<OnceCell<(State, State)>>) -> Self {
Self {
pre: Default::default(),
post: Default::default(),
config: PrestateTracerConfig { diff_mode },
result,
}
}
}

#[derive(Debug, Clone)]
pub struct PrestateTracerConfig {
diff_mode: bool,
}

pub fn process_modified_storage_keys<S>(
prestate: State,
storage: &StoragePtr<S>,
) -> HashMap<H160, Account>
where
S: WriteStorage,
{
let cloned_storage = &storage.clone();
let mut initial_storage_ref = cloned_storage.as_ref().borrow_mut();

initial_storage_ref
.modified_storage_keys()
.clone()
.iter()
.filter(|k| !prestate.contains_key(k.0.account().address()))
.map(|k| {
(
*(k.0.account().address()),
Account {
balance: Some(h256_to_u256(
initial_storage_ref.read_value(&get_balance_key(k.0.account())),
)),
code: Some(h256_to_u256(
initial_storage_ref.read_value(&get_code_key(k.0.account().address())),
)),
nonce: Some(h256_to_u256(
initial_storage_ref.read_value(&get_nonce_key(k.0.account().address())),
)),
storage: Some(get_storage_if_present(
k.0.account(),
initial_storage_ref.modified_storage_keys(),
)),
},
)
})
.collect::<State>()
}

fn get_balance_key(account: &AccountTreeId) -> StorageKey {
let address_h256 = address_to_h256(account.address());
let bytes = [address_h256.as_bytes(), &[0; 32]].concat();
let balance_key: H256 = keccak256(&bytes).into();
StorageKey::new(AccountTreeId::new(L2_ETH_TOKEN_ADDRESS), balance_key)
}

fn get_storage_if_present(
account: &AccountTreeId,
modified_storage_keys: &HashMap<StorageKey, StorageValue>,
) -> HashMap<H256, H256> {
//check if there is a Storage Key struct with an account field that matches the account and return the key as the key and the Storage Value as the value
modified_storage_keys
.iter()
.filter(|(k, _)| k.account() == account)
.map(|(k, v)| (*k.key(), *v))
.collect()
}

fn process_result(result: &Arc<OnceCell<(State, State)>>, mut pre: State, post: State) {
pre.retain(|k, v| {
if let Some(post_v) = post.get(k) {
if v != post_v {
return true;
}
}
false
});
result.set((pre, post)).unwrap();
}

fn get_account_data<T: StorageAccess>(
account_key: &StorageKey,
state: &T,
storage: &HashMap<StorageKey, StorageValue>,
) -> (Address, Account) {
let address = *(account_key.account().address());
let balance = state.read_from_storage(&get_balance_key(account_key.account()));
let code = state.read_from_storage(&get_code_key(account_key.account().address()));
let nonce = state.read_from_storage(&get_nonce_key(account_key.account().address()));
let storage = get_storage_if_present(account_key.account(), storage);

(
address,
Account {
balance: Some(balance),
code: Some(code),
nonce: Some(nonce),
storage: Some(storage),
},
)
}

// Define a trait that abstracts storage access
trait StorageAccess {
fn read_from_storage(&self, key: &StorageKey) -> U256;
}
59 changes: 59 additions & 0 deletions core/lib/multivm/src/tracers/prestate_tracer/vm_1_4_1/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
use zk_evm_1_4_1::tracing::{BeforeExecutionData, VmLocalStateData};
use zksync_state::{StoragePtr, WriteStorage};
use zksync_types::StorageKey;

use super::{
get_account_data, process_modified_storage_keys, process_result, PrestateTracer, State,
StorageAccess,
};
use crate::{
interface::dyn_tracers::vm_1_4_1::DynTracer,
tracers::prestate_tracer::U256,
vm_1_4_1::{BootloaderState, HistoryMode, SimpleMemory, VmTracer, ZkSyncVmState},
};
impl<S: WriteStorage, H: HistoryMode> DynTracer<S, SimpleMemory<H>> for PrestateTracer {
fn before_execution(
&mut self,
_state: VmLocalStateData<'_>,
_data: BeforeExecutionData,
_memory: &SimpleMemory<H>,
storage: StoragePtr<S>,
) {
if self.config.diff_mode {
self.pre
.extend(process_modified_storage_keys(self.pre.clone(), &storage));
}
}
}

impl<S: WriteStorage, H: HistoryMode> VmTracer<S, H> for PrestateTracer {
fn after_vm_execution(
&mut self,
state: &mut ZkSyncVmState<S, H>,
_bootloader_state: &BootloaderState,
_stop_reason: crate::interface::tracer::VmExecutionStopReason,
) {
let modified_storage_keys = state.storage.storage.inner().get_modified_storage_keys();
if self.config.diff_mode {
self.post = modified_storage_keys
.iter()
.map(|k| get_account_data(k.0, state, &modified_storage_keys))
.collect::<State>();
} else {
let read_keys = &state.storage.read_keys;
let map = read_keys.inner().clone();
let res = map
.iter()
.map(|k| get_account_data(k.0, state, &modified_storage_keys))
.collect::<State>();
self.post = res;
}
process_result(&self.result, self.pre.clone(), self.post.clone());
}
}

impl<S: zksync_state::WriteStorage, H: HistoryMode> StorageAccess for ZkSyncVmState<S, H> {
fn read_from_storage(&self, key: &StorageKey) -> U256 {
self.storage.storage.read_from_storage(key)
}
}
60 changes: 60 additions & 0 deletions core/lib/multivm/src/tracers/prestate_tracer/vm_latest/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
use zk_evm_1_4_1::tracing::{BeforeExecutionData, VmLocalStateData};
use zksync_state::{StoragePtr, WriteStorage};
use zksync_types::StorageKey;

use super::{
get_account_data, process_modified_storage_keys, process_result, PrestateTracer, State,
StorageAccess,
};
use crate::{
interface::dyn_tracers::vm_1_4_1::DynTracer,
tracers::prestate_tracer::U256,
vm_latest::{BootloaderState, HistoryMode, SimpleMemory, VmTracer, ZkSyncVmState},
};

impl<S: WriteStorage, H: HistoryMode> DynTracer<S, SimpleMemory<H>> for PrestateTracer {
fn before_execution(
&mut self,
_state: VmLocalStateData<'_>,
_data: BeforeExecutionData,
_memory: &SimpleMemory<H>,
storage: StoragePtr<S>,
) {
if self.config.diff_mode {
self.pre
.extend(process_modified_storage_keys(self.pre.clone(), &storage));
}
}
}

impl<S: WriteStorage, H: HistoryMode> VmTracer<S, H> for PrestateTracer {
fn after_vm_execution(
&mut self,
state: &mut ZkSyncVmState<S, H>,
_bootloader_state: &BootloaderState,
_stop_reason: crate::interface::tracer::VmExecutionStopReason,
) {
let modified_storage_keys = state.storage.storage.inner().get_modified_storage_keys();
if self.config.diff_mode {
self.post = modified_storage_keys
.iter()
.map(|k| get_account_data(k.0, state, &modified_storage_keys))
.collect::<State>();
} else {
let read_keys = &state.storage.read_keys;
let map = read_keys.inner().clone();
let res = map
.iter()
.map(|k| get_account_data(k.0, state, &modified_storage_keys))
.collect::<State>();
self.post = res;
}
process_result(&self.result, self.pre.clone(), self.post.clone());
}
}

impl<S: zksync_state::WriteStorage, H: HistoryMode> StorageAccess for ZkSyncVmState<S, H> {
fn read_from_storage(&self, key: &StorageKey) -> U256 {
self.storage.storage.read_from_storage(key)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
use std::collections::HashMap;

use zk_evm_1_3_3::tracing::{BeforeExecutionData, VmLocalStateData};
use zksync_state::{StoragePtr, WriteStorage};
use zksync_types::{StorageKey, H256};

use super::{
get_account_data, process_modified_storage_keys, process_result, PrestateTracer, State,
StorageAccess,
};
use crate::{
interface::dyn_tracers::vm_1_3_3::DynTracer,
tracers::prestate_tracer::U256,
vm_refunds_enhancement::{BootloaderState, HistoryMode, SimpleMemory, VmTracer, ZkSyncVmState},
};

impl<S: WriteStorage, H: HistoryMode> DynTracer<S, SimpleMemory<H>> for PrestateTracer {
fn before_execution(
Jrigada marked this conversation as resolved.
Show resolved Hide resolved
&mut self,
_state: VmLocalStateData<'_>,
_data: BeforeExecutionData,
_memory: &SimpleMemory<H>,
storage: StoragePtr<S>,
) {
if self.config.diff_mode {
self.pre
.extend(process_modified_storage_keys(self.pre.clone(), &storage));
}
}
}

impl<S: WriteStorage, H: HistoryMode> VmTracer<S, H> for PrestateTracer {
fn after_vm_execution(
&mut self,
state: &mut ZkSyncVmState<S, H>,
_bootloader_state: &BootloaderState,
_stop_reason: crate::interface::tracer::VmExecutionStopReason,
) {
let modified_storage_keys = state.storage.storage.inner().get_modified_storage_keys();
if self.config.diff_mode {
self.post = modified_storage_keys
.iter()
.map(|k| get_account_data(k.0, state, &modified_storage_keys))
.collect::<State>();
} else {
let read_keys: &HashMap<StorageKey, H256> = &state
.storage
.storage
.inner()
.get_ptr()
.borrow()
.read_storage_keys()
.iter()
.map(|(k, v)| (*k, *v))
.collect();
let res = read_keys
.iter()
.map(|k| get_account_data(k.0, state, &modified_storage_keys))
.collect::<State>();
self.post = res;
}
process_result(&self.result, self.pre.clone(), self.post.clone());
}
}

impl<S: zksync_state::WriteStorage, H: HistoryMode> StorageAccess for ZkSyncVmState<S, H> {
fn read_from_storage(&self, key: &StorageKey) -> U256 {
self.storage.storage.read_from_storage(key)
}
}
Loading
Loading