From 98f04bef99e800ece0f60aa829b0a81325cd1d2f Mon Sep 17 00:00:00 2001 From: Nisheeth Barthwal Date: Mon, 23 Dec 2024 17:32:55 +0100 Subject: [PATCH] reintroduce backend.inspect --- crates/evm/core/src/backend/cow.rs | 31 +++++- crates/evm/core/src/backend/mod.rs | 20 +++- crates/evm/core/src/backend/strategy.rs | 35 ++++++- crates/evm/evm/src/executors/mod.rs | 18 +--- crates/evm/evm/src/executors/strategy.rs | 116 ++++++++++------------- crates/script/src/broadcast.rs | 2 +- crates/script/src/runner.rs | 5 +- crates/strategy/zksync/src/backend.rs | 66 +++++++++++-- crates/strategy/zksync/src/cheatcode.rs | 5 +- crates/strategy/zksync/src/executor.rs | 91 +++++++++--------- crates/strategy/zksync/src/lib.rs | 2 +- crates/zksync/core/src/lib.rs | 4 + 12 files changed, 252 insertions(+), 143 deletions(-) diff --git a/crates/evm/core/src/backend/cow.rs b/crates/evm/core/src/backend/cow.rs index 1a38ec6e8..926943556 100644 --- a/crates/evm/core/src/backend/cow.rs +++ b/crates/evm/core/src/backend/cow.rs @@ -14,10 +14,13 @@ use alloy_rpc_types::TransactionRequest; use foundry_fork_db::DatabaseError; use revm::{ db::DatabaseRef, - primitives::{Account, AccountInfo, Bytecode, Env, EnvWithHandlerCfg, HashMap as Map, SpecId}, + primitives::{ + Account, AccountInfo, Bytecode, Env, EnvWithHandlerCfg, HashMap as Map, ResultAndState, + SpecId, + }, Database, DatabaseCommit, JournaledState, }; -use std::{borrow::Cow, collections::BTreeMap}; +use std::{any::Any, borrow::Cow, collections::BTreeMap}; /// A wrapper around `Backend` that ensures only `revm::DatabaseRef` functions are called. /// @@ -53,6 +56,30 @@ impl<'a> CowBackend<'a> { Self { backend: Cow::Borrowed(backend), is_initialized: false, spec_id: SpecId::LATEST } } + /// Executes the configured transaction of the `env` without committing state changes + /// + /// Note: in case there are any cheatcodes executed that modify the environment, this will + /// update the given `env` with the new values. + #[instrument(name = "inspect", level = "debug", skip_all)] + pub fn inspect( + &mut self, + env: &mut EnvWithHandlerCfg, + inspector: &mut I, + inspect_ctx: Box, + ) -> eyre::Result { + // this is a new call to inspect with a new env, so even if we've cloned the backend + // already, we reset the initialized state + self.is_initialized = false; + self.spec_id = env.handler_cfg.spec_id; + + self.backend.strategy.runner.clone().inspect( + self.backend.to_mut(), + env, + inspector, + inspect_ctx, + ) + } + pub fn new_borrowed(backend: &'a Backend) -> Self { Self { backend: Cow::Borrowed(backend), is_initialized: false, spec_id: SpecId::LATEST } } diff --git a/crates/evm/core/src/backend/mod.rs b/crates/evm/core/src/backend/mod.rs index b712f7c70..b21009c27 100644 --- a/crates/evm/core/src/backend/mod.rs +++ b/crates/evm/core/src/backend/mod.rs @@ -22,11 +22,12 @@ use revm::{ precompile::{PrecompileSpecId, Precompiles}, primitives::{ Account, AccountInfo, BlobExcessGasAndPrice, Bytecode, Env, EnvWithHandlerCfg, EvmState, - EvmStorageSlot, HashMap as Map, Log, SpecId, KECCAK_EMPTY, + EvmStorageSlot, HashMap as Map, Log, ResultAndState, SpecId, KECCAK_EMPTY, }, Database, DatabaseCommit, JournaledState, }; use std::{ + any::Any, collections::{BTreeMap, HashSet}, time::Instant, }; @@ -773,11 +774,26 @@ impl Backend { /// Initializes settings we need to keep track of. /// /// We need to track these mainly to prevent issues when switching between different evms - pub fn initialize(&mut self, env: &EnvWithHandlerCfg) { + pub(crate) fn initialize(&mut self, env: &EnvWithHandlerCfg) { self.set_caller(env.tx.caller); self.set_spec_id(env.handler_cfg.spec_id); } + /// Executes the configured test call of the `env` without committing state changes. + /// + /// Note: in case there are any cheatcodes executed that modify the environment, this will + /// update the given `env` with the new values. + #[instrument(name = "inspect", level = "debug", skip_all)] + pub fn inspect( + &mut self, + env: &mut EnvWithHandlerCfg, + inspector: &mut I, + inspect_ctx: Box, + ) -> eyre::Result { + self.initialize(env); + self.strategy.runner.clone().inspect(self, env, inspector, inspect_ctx) + } + /// Returns the `EnvWithHandlerCfg` with the current `spec_id` set. fn env_with_handler_cfg(&self, env: Env) -> EnvWithHandlerCfg { EnvWithHandlerCfg::new_with_spec_id(Box::new(env), self.inner.spec_id) diff --git a/crates/evm/core/src/backend/strategy.rs b/crates/evm/core/src/backend/strategy.rs index 1cdf78f33..2160da098 100644 --- a/crates/evm/core/src/backend/strategy.rs +++ b/crates/evm/core/src/backend/strategy.rs @@ -1,8 +1,15 @@ use std::{any::Any, fmt::Debug}; -use super::{BackendInner, Fork, ForkDB, ForkType, FoundryEvmInMemoryDB}; +use crate::InspectorExt; + +use super::{Backend, BackendInner, Fork, ForkDB, ForkType, FoundryEvmInMemoryDB}; use alloy_primitives::{Address, U256}; -use revm::{db::CacheDB, primitives::HashSet, DatabaseRef, JournaledState}; +use eyre::{Context, Result}; +use revm::{ + db::CacheDB, + primitives::{EnvWithHandlerCfg, HashSet, ResultAndState}, + DatabaseRef, JournaledState, +}; use serde::{Deserialize, Serialize}; pub struct BackendStrategyForkInfo<'a> { @@ -62,6 +69,14 @@ pub trait BackendStrategyRunner: Debug + Send + Sync + BackendStrategyRunnerExt fn new_cloned(&self) -> Box; + fn inspect( + &self, + backend: &mut Backend, + env: &mut EnvWithHandlerCfg, + inspector: &mut dyn InspectorExt, + inspect_ctx: Box, + ) -> Result; + /// When creating or switching forks, we update the AccountInfo of the contract fn update_fork_db( &self, @@ -121,6 +136,22 @@ impl BackendStrategyRunner for EvmBackendStrategyRunner { Box::new(self.clone()) } + fn inspect( + &self, + backend: &mut Backend, + env: &mut EnvWithHandlerCfg, + inspector: &mut dyn InspectorExt, + _inspect_ctx: Box, + ) -> Result { + let mut evm = crate::utils::new_evm_with_inspector(backend, env.clone(), inspector); + + let res = evm.transact().wrap_err("backend: failed while inspecting")?; + + env.env = evm.context.evm.inner.env; + + Ok(res) + } + fn update_fork_db( &self, _ctx: &mut dyn BackendStrategyContext, diff --git a/crates/evm/evm/src/executors/mod.rs b/crates/evm/evm/src/executors/mod.rs index 061f2ac11..b8a0a72b2 100644 --- a/crates/evm/evm/src/executors/mod.rs +++ b/crates/evm/evm/src/executors/mod.rs @@ -15,7 +15,6 @@ use alloy_primitives::{ map::{AddressHashMap, HashMap}, Address, Bytes, Log, U256, }; -use alloy_serde::OtherFields; use alloy_sol_types::{sol, SolCall}; use foundry_evm_core::{ backend::{Backend, BackendError, BackendResult, CowBackend, DatabaseExt, GLOBAL_FAIL_SLOT}, @@ -93,7 +92,7 @@ pub struct Executor { /// Whether `failed()` should be called on the test contract to determine if the test failed. legacy_assertions: bool, - strategy: ExecutorStrategy, + pub strategy: ExecutorStrategy, } impl Clone for Executor { @@ -258,11 +257,6 @@ impl Executor { self } - #[inline] - pub fn set_transaction_other_fields(&mut self, other_fields: OtherFields) { - self.strategy.runner.set_inspect_context(self.strategy.context.as_mut(), other_fields); - } - /// Deploys a contract and commits the new state to the underlying database. /// /// Executes a CREATE transaction with the contract `code` and persistent database state @@ -438,15 +432,12 @@ impl Executor { pub fn call_with_env(&self, mut env: EnvWithHandlerCfg) -> eyre::Result { let mut inspector = self.inspector().clone(); let mut backend = CowBackend::new_borrowed(self.backend()); - // this is a new call to inspect with a new env, so even if we've cloned the backend - // already, we reset the initialized state - backend.is_initialized = false; - backend.spec_id = env.spec_id(); - let result = self.strategy.runner.call_inspect( + let result = self.strategy.runner.call( self.strategy.context.as_ref(), &mut backend, &mut env, + &self.env, &mut inspector, )?; @@ -463,9 +454,8 @@ impl Executor { pub fn transact_with_env(&mut self, mut env: EnvWithHandlerCfg) -> eyre::Result { let mut inspector = self.inspector.clone(); let backend = &mut self.backend; - backend.initialize(&env); - let result_and_state = self.strategy.runner.transact_inspect( + let result_and_state = self.strategy.runner.transact( self.strategy.context.as_mut(), backend, &mut env, diff --git a/crates/evm/evm/src/executors/strategy.rs b/crates/evm/evm/src/executors/strategy.rs index e27f57ce0..2e935e690 100644 --- a/crates/evm/evm/src/executors/strategy.rs +++ b/crates/evm/evm/src/executors/strategy.rs @@ -2,20 +2,19 @@ use std::{any::Any, fmt::Debug}; use alloy_primitives::{Address, U256}; use alloy_serde::OtherFields; -use eyre::{Context, Result}; +use eyre::Result; use foundry_cheatcodes::strategy::{ CheatcodeInspectorStrategy, EvmCheatcodeInspectorStrategyRunner, }; -use foundry_evm_core::{ - backend::{strategy::BackendStrategy, BackendResult, DatabaseExt}, - InspectorExt, -}; +use foundry_evm_core::backend::{strategy::BackendStrategy, Backend, BackendResult, CowBackend}; use foundry_zksync_compiler::DualCompiledContracts; use revm::{ primitives::{Env, EnvWithHandlerCfg, ResultAndState}, DatabaseRef, }; +use crate::inspectors::InspectorStack; + use super::Executor; pub trait ExecutorStrategyContext: Debug + Send + Sync + Any { @@ -76,24 +75,25 @@ pub trait ExecutorStrategyRunner: Debug + Send + Sync + ExecutorStrategyExt { fn set_nonce(&self, executor: &mut Executor, address: Address, nonce: u64) -> BackendResult<()>; - fn set_inspect_context(&self, ctx: &mut dyn ExecutorStrategyContext, other_fields: OtherFields); - - fn call_inspect( + /// Execute a transaction and *WITHOUT* applying state changes. + fn call( &self, ctx: &dyn ExecutorStrategyContext, - db: &mut dyn DatabaseExt, + backend: &mut CowBackend<'_>, env: &mut EnvWithHandlerCfg, - inspector: &mut dyn InspectorExt, - ) -> eyre::Result; + executor_env: &EnvWithHandlerCfg, + inspector: &mut InspectorStack, + ) -> Result; - fn transact_inspect( + /// Execute a transaction and apply state changes. + fn transact( &self, ctx: &mut dyn ExecutorStrategyContext, - db: &mut dyn DatabaseExt, + backend: &mut Backend, env: &mut EnvWithHandlerCfg, - _executor_env: &EnvWithHandlerCfg, - inspector: &mut dyn InspectorExt, - ) -> eyre::Result; + executor_env: &EnvWithHandlerCfg, + inspector: &mut InspectorStack, + ) -> Result; fn new_backend_strategy(&self) -> BackendStrategy; fn new_cheatcode_inspector_strategy( @@ -123,6 +123,19 @@ pub trait ExecutorStrategyExt { ) -> Result<()> { Ok(()) } + + /// Sets the transaction context for the next [ExecutorStrategyRunner::call] or + /// [ExecutorStrategyRunner::transact]. This selects whether to run the transaction on zkEVM + /// or the EVM. + /// This is based if the [OtherFields] contains + /// [foundry_zksync_core::ZKSYNC_TRANSACTION_OTHER_FIELDS_KEY] with + /// [foundry_zksync_core::ZkTransactionMetadata]. + fn zksync_set_transaction_context( + &self, + _ctx: &mut dyn ExecutorStrategyContext, + _other_fields: OtherFields, + ) { + } } /// Implements [ExecutorStrategyRunner] for EVM. @@ -138,55 +151,6 @@ impl ExecutorStrategyRunner for EvmExecutorStrategyRunner { Box::new(self.clone()) } - fn set_inspect_context( - &self, - _ctx: &mut dyn ExecutorStrategyContext, - _other_fields: OtherFields, - ) { - } - - /// Executes the configured test call of the `env` without committing state changes. - /// - /// Note: in case there are any cheatcodes executed that modify the environment, this will - /// update the given `env` with the new values. - fn call_inspect( - &self, - _ctx: &dyn ExecutorStrategyContext, - db: &mut dyn DatabaseExt, - env: &mut EnvWithHandlerCfg, - inspector: &mut dyn InspectorExt, - ) -> eyre::Result { - let mut evm = crate::utils::new_evm_with_inspector(db, env.clone(), inspector); - - let res = evm.transact().wrap_err("backend: failed while inspecting")?; - - env.env = evm.context.evm.inner.env; - - Ok(res) - } - - /// Executes the configured test call of the `env` without committing state changes. - /// Modifications to the state are however allowed. - /// - /// Note: in case there are any cheatcodes executed that modify the environment, this will - /// update the given `env` with the new values. - fn transact_inspect( - &self, - _ctx: &mut dyn ExecutorStrategyContext, - db: &mut dyn DatabaseExt, - env: &mut EnvWithHandlerCfg, - _executor_env: &EnvWithHandlerCfg, - inspector: &mut dyn InspectorExt, - ) -> eyre::Result { - let mut evm = crate::utils::new_evm_with_inspector(db, env.clone(), inspector); - - let res = evm.transact().wrap_err("backend: failed while inspecting")?; - - env.env = evm.context.evm.inner.env; - - Ok(res) - } - fn set_balance( &self, executor: &mut Executor, @@ -214,6 +178,28 @@ impl ExecutorStrategyRunner for EvmExecutorStrategyRunner { Ok(()) } + fn call( + &self, + _ctx: &dyn ExecutorStrategyContext, + backend: &mut CowBackend<'_>, + env: &mut EnvWithHandlerCfg, + _executor_env: &EnvWithHandlerCfg, + inspector: &mut InspectorStack, + ) -> Result { + backend.inspect(env, inspector, Box::new(())) + } + + fn transact( + &self, + _ctx: &mut dyn ExecutorStrategyContext, + backend: &mut Backend, + env: &mut EnvWithHandlerCfg, + _executor_env: &EnvWithHandlerCfg, + inspector: &mut InspectorStack, + ) -> Result { + backend.inspect(env, inspector, Box::new(())) + } + fn new_backend_strategy(&self) -> BackendStrategy { BackendStrategy::new_evm() } diff --git a/crates/script/src/broadcast.rs b/crates/script/src/broadcast.rs index 3171baaba..ff6a00367 100644 --- a/crates/script/src/broadcast.rs +++ b/crates/script/src/broadcast.rs @@ -73,7 +73,7 @@ pub async fn send_transaction( ) -> Result { let zk_tx_meta = if let SendTransactionKind::Raw(tx, _) | SendTransactionKind::Unlocked(tx) = &mut kind { - foundry_strategy_zksync::get_zksync_transaction_metadata(&tx.other) + foundry_strategy_zksync::try_get_zksync_transaction_context(&tx.other) } else { None }; diff --git a/crates/script/src/runner.rs b/crates/script/src/runner.rs index 22b26446d..634785d37 100644 --- a/crates/script/src/runner.rs +++ b/crates/script/src/runner.rs @@ -257,7 +257,10 @@ impl ScriptRunner { other_fields: Option, ) -> Result { if let Some(other_fields) = other_fields { - self.executor.set_transaction_other_fields(other_fields); + self.executor.strategy.runner.zksync_set_transaction_context( + self.executor.strategy.context.as_mut(), + other_fields, + ); } if let Some(to) = to { diff --git a/crates/strategy/zksync/src/backend.rs b/crates/strategy/zksync/src/backend.rs index aadc55ef7..9e2439bad 100644 --- a/crates/strategy/zksync/src/backend.rs +++ b/crates/strategy/zksync/src/backend.rs @@ -1,8 +1,13 @@ use std::{any::Any, collections::hash_map::Entry}; use alloy_primitives::{map::HashMap, Address, U256}; -use foundry_evm::backend::strategy::{ - BackendStrategy, BackendStrategyContext, BackendStrategyRunnerExt, +use eyre::Result; +use foundry_evm::{ + backend::{ + strategy::{BackendStrategy, BackendStrategyContext, BackendStrategyRunnerExt}, + Backend, + }, + InspectorExt, }; use foundry_evm_core::backend::{ strategy::{ @@ -12,18 +17,37 @@ use foundry_evm_core::backend::{ BackendInner, Fork, ForkDB, FoundryEvmInMemoryDB, }; use foundry_zksync_core::{ - convert::ConvertH160, ACCOUNT_CODE_STORAGE_ADDRESS, IMMUTABLE_SIMULATOR_STORAGE_ADDRESS, - KNOWN_CODES_STORAGE_ADDRESS, L2_BASE_TOKEN_ADDRESS, NONCE_HOLDER_ADDRESS, + convert::ConvertH160, vm::ZkEnv, PaymasterParams, ACCOUNT_CODE_STORAGE_ADDRESS, + IMMUTABLE_SIMULATOR_STORAGE_ADDRESS, KNOWN_CODES_STORAGE_ADDRESS, L2_BASE_TOKEN_ADDRESS, + NONCE_HOLDER_ADDRESS, +}; +use revm::{ + db::CacheDB, + primitives::{EnvWithHandlerCfg, HashSet, ResultAndState}, + DatabaseRef, JournaledState, }; -use revm::{db::CacheDB, primitives::HashSet, DatabaseRef, JournaledState}; use serde::{Deserialize, Serialize}; use tracing::trace; +use zksync_types::H256; + +/// Represents additional data for ZK transactions. +#[derive(Clone, Debug, Default)] +pub struct ZksyncInspectContext { + /// Factory Deps for ZK transactions. + pub factory_deps: Vec>, + /// Paymaster data for ZK transactions. + pub paymaster_data: Option, + /// Zksync environment. + pub zk_env: ZkEnv, +} /// Context for [ZksyncBackendStrategyRunner]. -#[derive(Debug, Default, Clone, Serialize, Deserialize)] +#[derive(Debug, Default, Clone)] pub struct ZksyncBackendStrategyContext { /// Store storage keys per contract address for immutable variables. persistent_immutable_keys: HashMap>, + /// Store persisted factory dependencies. + persisted_factory_deps: HashMap>, } impl BackendStrategyContext for ZksyncBackendStrategyContext { @@ -55,6 +79,32 @@ impl BackendStrategyRunner for ZksyncBackendStrategyRunner { Box::new(self.clone()) } + fn inspect( + &self, + backend: &mut Backend, + env: &mut EnvWithHandlerCfg, + _inspector: &mut dyn InspectorExt, + inspect_ctx: Box, + ) -> Result { + let mut persisted_factory_deps = + get_context(backend.strategy.context.as_mut()).persisted_factory_deps.clone(); + + let inspect_ctx = get_inspect_context(inspect_ctx); + let result = foundry_zksync_core::vm::transact( + Some(&mut persisted_factory_deps), + Some(inspect_ctx.factory_deps), + inspect_ctx.paymaster_data, + env, + &inspect_ctx.zk_env, + backend, + ); + + let ctx = get_context(backend.strategy.context.as_mut()); + ctx.persisted_factory_deps = persisted_factory_deps; + + result + } + /// When creating or switching forks, we update the AccountInfo of the contract. fn update_fork_db( &self, @@ -367,3 +417,7 @@ impl ZksyncBackendMerge { fn get_context(ctx: &mut dyn BackendStrategyContext) -> &mut ZksyncBackendStrategyContext { ctx.as_any_mut().downcast_mut().expect("expected ZksyncBackendStrategyContext") } + +fn get_inspect_context(ctx: Box) -> Box { + ctx.downcast().expect("expected ZksyncInspectContext") +} diff --git a/crates/strategy/zksync/src/cheatcode.rs b/crates/strategy/zksync/src/cheatcode.rs index 08e6b886e..dc7ca43c0 100644 --- a/crates/strategy/zksync/src/cheatcode.rs +++ b/crates/strategy/zksync/src/cheatcode.rs @@ -34,7 +34,7 @@ use foundry_zksync_core::{ vm::ZkEnv, PaymasterParams, ZkPaymasterData, ZkTransactionMetadata, ACCOUNT_CODE_STORAGE_ADDRESS, CONTRACT_DEPLOYER_ADDRESS, DEFAULT_CREATE2_DEPLOYER_ZKSYNC, H256, KNOWN_CODES_STORAGE_ADDRESS, - L2_BASE_TOKEN_ADDRESS, NONCE_HOLDER_ADDRESS, + L2_BASE_TOKEN_ADDRESS, NONCE_HOLDER_ADDRESS, ZKSYNC_TRANSACTION_OTHER_FIELDS_KEY, }; use itertools::Itertools; use revm::{ @@ -55,9 +55,6 @@ use zksync_types::{ CURRENT_VIRTUAL_BLOCK_INFO_POSITION, SYSTEM_CONTEXT_ADDRESS, }; -/// Key used to set transaction metadata in other fields. -pub const ZKSYNC_TRANSACTION_OTHER_FIELDS_KEY: &str = "zksync"; - macro_rules! fmt_err { ($msg:literal $(,)?) => { Error::fmt(::std::format_args!($msg)) diff --git a/crates/strategy/zksync/src/executor.rs b/crates/strategy/zksync/src/executor.rs index 191ec4145..b13f52704 100644 --- a/crates/strategy/zksync/src/executor.rs +++ b/crates/strategy/zksync/src/executor.rs @@ -4,7 +4,7 @@ use alloy_zksync::provider::{zksync_provider, ZksyncProvider}; use eyre::Result; use foundry_evm::{ - backend::{BackendResult, DatabaseExt}, + backend::{Backend, BackendResult, CowBackend}, executors::{ strategy::{ EvmExecutorStrategyRunner, ExecutorStrategy, ExecutorStrategyContext, @@ -12,26 +12,24 @@ use foundry_evm::{ }, Executor, }, - InspectorExt, + inspectors::InspectorStack, }; use foundry_zksync_compiler::DualCompiledContracts; -use foundry_zksync_core::{vm::ZkEnv, ZkTransactionMetadata}; +use foundry_zksync_core::{vm::ZkEnv, ZkTransactionMetadata, ZKSYNC_TRANSACTION_OTHER_FIELDS_KEY}; use revm::{ - primitives::{Env, EnvWithHandlerCfg, HashMap, ResultAndState}, + primitives::{Env, EnvWithHandlerCfg, ResultAndState}, Database, }; -use zksync_types::H256; use crate::{ - backend::ZksyncBackendStrategyBuilder, - cheatcode::{ZksyncCheatcodeInspectorStrategyBuilder, ZKSYNC_TRANSACTION_OTHER_FIELDS_KEY}, + backend::{ZksyncBackendStrategyBuilder, ZksyncInspectContext}, + cheatcode::ZksyncCheatcodeInspectorStrategyBuilder, }; /// Defines the context for [ZksyncExecutorStrategyRunner]. #[derive(Debug, Default, Clone)] pub struct ZksyncExecutorStrategyContext { - inspect_context: Option, - persisted_factory_deps: HashMap>, + transaction_context: Option, dual_compiled_contracts: DualCompiledContracts, zk_env: ZkEnv, } @@ -73,16 +71,6 @@ impl ExecutorStrategyRunner for ZksyncExecutorStrategyRunner { Box::new(self.clone()) } - fn set_inspect_context( - &self, - ctx: &mut dyn ExecutorStrategyContext, - other_fields: OtherFields, - ) { - let ctx = get_context(ctx); - let maybe_context = get_zksync_transaction_metadata(&other_fields); - ctx.inspect_context = maybe_context; - } - fn set_balance( &self, executor: &mut Executor, @@ -131,52 +119,56 @@ impl ExecutorStrategyRunner for ZksyncExecutorStrategyRunner { ) } - fn call_inspect( + fn call( &self, ctx: &dyn ExecutorStrategyContext, - db: &mut dyn DatabaseExt, + backend: &mut CowBackend<'_>, env: &mut EnvWithHandlerCfg, - inspector: &mut dyn InspectorExt, + executor_env: &EnvWithHandlerCfg, + inspector: &mut InspectorStack, ) -> eyre::Result { - let ctx_zk = get_context_ref(ctx); - match ctx_zk.inspect_context.as_ref() { - None => self.evm.call_inspect(ctx, db, env, inspector), - Some(zk_tx) => foundry_zksync_core::vm::transact( - Some(&mut ctx_zk.persisted_factory_deps.clone()), - Some(zk_tx.factory_deps.clone()), - zk_tx.paymaster_data.clone(), + let ctx = get_context_ref(ctx); + + match ctx.transaction_context.as_ref() { + None => self.evm.call(ctx, backend, env, executor_env, inspector), + Some(zk_tx) => backend.inspect( env, - &ctx_zk.zk_env, - db, + inspector, + Box::new(ZksyncInspectContext { + factory_deps: zk_tx.factory_deps.clone(), + paymaster_data: zk_tx.paymaster_data.clone(), + zk_env: ctx.zk_env.clone(), + }), ), } } - fn transact_inspect( + fn transact( &self, ctx: &mut dyn ExecutorStrategyContext, - db: &mut dyn DatabaseExt, + backend: &mut Backend, env: &mut EnvWithHandlerCfg, executor_env: &EnvWithHandlerCfg, - inspector: &mut dyn InspectorExt, + inspector: &mut InspectorStack, ) -> eyre::Result { - let ctx_zk = get_context(ctx); + let ctx = get_context(ctx); - match ctx_zk.inspect_context.take() { - None => self.evm.transact_inspect(ctx, db, env, executor_env, inspector), + match ctx.transaction_context.take() { + None => self.evm.transact(ctx, backend, env, executor_env, inspector), Some(zk_tx) => { // apply fork-related env instead of cheatcode handler // since it won't be set by zkEVM env.block = executor_env.block.clone(); env.tx.gas_price = executor_env.tx.gas_price; - foundry_zksync_core::vm::transact( - Some(&mut ctx_zk.persisted_factory_deps), - Some(zk_tx.factory_deps), - zk_tx.paymaster_data, + backend.inspect( env, - &ctx_zk.zk_env, - db, + inspector, + Box::new(ZksyncInspectContext { + factory_deps: zk_tx.factory_deps, + paymaster_data: zk_tx.paymaster_data, + zk_env: ctx.zk_env.clone(), + }), ) } } @@ -233,10 +225,19 @@ impl ExecutorStrategyExt for ZksyncExecutorStrategyRunner { Ok(()) } + + fn zksync_set_transaction_context( + &self, + ctx: &mut dyn ExecutorStrategyContext, + other_fields: OtherFields, + ) { + let ctx = get_context(ctx); + let transaction_context = try_get_zksync_transaction_context(&other_fields); + ctx.transaction_context = transaction_context; + } } -/// Retrieve metadata for ZKsync tx. -pub fn get_zksync_transaction_metadata( +pub fn try_get_zksync_transaction_context( other_fields: &OtherFields, ) -> Option { other_fields diff --git a/crates/strategy/zksync/src/lib.rs b/crates/strategy/zksync/src/lib.rs index 344979a45..f85c19456 100644 --- a/crates/strategy/zksync/src/lib.rs +++ b/crates/strategy/zksync/src/lib.rs @@ -12,5 +12,5 @@ mod executor; pub use backend::ZksyncBackendStrategyRunner; pub use cheatcode::ZksyncCheatcodeInspectorStrategyRunner; pub use executor::{ - get_zksync_transaction_metadata, ZksyncExecutorStrategyBuilder, ZksyncExecutorStrategyRunner, + try_get_zksync_transaction_context, ZksyncExecutorStrategyBuilder, ZksyncExecutorStrategyRunner, }; diff --git a/crates/zksync/core/src/lib.rs b/crates/zksync/core/src/lib.rs index e6b15b428..3a1bbf881 100644 --- a/crates/zksync/core/src/lib.rs +++ b/crates/zksync/core/src/lib.rs @@ -84,6 +84,10 @@ pub struct ZkPaymasterData { pub input: Bytes, } +/// Key used to set transaction metadata in other fields of [WithOtherFields]. +/// This is used when broadcasting in a test, and when a script reads the broadcasted transactions. +pub const ZKSYNC_TRANSACTION_OTHER_FIELDS_KEY: &str = "zksync"; + /// Represents additional data for ZK transactions. #[derive(Clone, Debug, Default, Serialize, Deserialize)] #[serde(rename_all = "camelCase")]