From 5c552ee23d29ceb09ef0e8e30e412190e7b8c673 Mon Sep 17 00:00:00 2001 From: Francesco Dainese Date: Mon, 26 Aug 2024 18:49:44 +0200 Subject: [PATCH 1/5] fix(zk): avoid observing log from staticcalls --- crates/cheatcodes/src/inspector.rs | 51 ++++++++++++++++-------------- 1 file changed, 27 insertions(+), 24 deletions(-) diff --git a/crates/cheatcodes/src/inspector.rs b/crates/cheatcodes/src/inspector.rs index f8954a882..5d8512a54 100644 --- a/crates/cheatcodes/src/inspector.rs +++ b/crates/cheatcodes/src/inspector.rs @@ -1395,32 +1395,35 @@ impl Cheatcodes { persisted_factory_deps: Some(&mut self.persisted_factory_deps), }; if let Ok(result) = foundry_zksync_core::vm::call::<_, DatabaseError>(call, ecx, ccx) { - if let Some(recorded_logs) = &mut self.recorded_logs { - recorded_logs.extend(result.logs.clone().into_iter().map(|log| Vm::Log { - topics: log.data.topics().to_vec(), - data: log.data.data.clone(), - emitter: log.address, - })); - } + // skip log processing for static calls + if !call.is_static { + if let Some(recorded_logs) = &mut self.recorded_logs { + recorded_logs.extend(result.logs.clone().into_iter().map(|log| Vm::Log { + topics: log.data.topics().to_vec(), + data: log.data.data.clone(), + emitter: log.address, + })); + } - // append console logs from zkEVM to the current executor's LogTracer - result.logs.iter().filter_map(decode_console_log).for_each(|decoded_log| { - executor.console_log( - &mut CheatsCtxt { - state: self, - ecx: &mut ecx.inner, - precompiles: &mut ecx.precompiles, - gas_limit: call.gas_limit, - caller: call.caller, - }, - decoded_log, - ); - }); + // append console logs from zkEVM to the current executor's LogTracer + result.logs.iter().filter_map(decode_console_log).for_each(|decoded_log| { + executor.console_log( + &mut CheatsCtxt { + state: self, + ecx: &mut ecx.inner, + precompiles: &mut ecx.precompiles, + gas_limit: call.gas_limit, + caller: call.caller, + }, + decoded_log, + ); + }); - // for each log in cloned logs call handle_expect_emit - if !self.expected_emits.is_empty() { - for log in result.logs { - expect::handle_expect_emit(self, &log); + // for each log in cloned logs call handle_expect_emit + if !self.expected_emits.is_empty() { + for log in result.logs { + expect::handle_expect_emit(self, &log); + } } } From 0d2a1165a203b68107cb97ca30ea9367824b3670 Mon Sep 17 00:00:00 2001 From: Francesco Dainese Date: Mon, 26 Aug 2024 19:28:16 +0200 Subject: [PATCH 2/5] test(zk): check not obversing staticcall logs --- crates/forge/tests/it/zk/cheats.rs | 2 +- testdata/zk/Cheatcodes.t.sol | 15 +++++++++++++-- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/crates/forge/tests/it/zk/cheats.rs b/crates/forge/tests/it/zk/cheats.rs index 98a3f066c..135e3c333 100644 --- a/crates/forge/tests/it/zk/cheats.rs +++ b/crates/forge/tests/it/zk/cheats.rs @@ -58,7 +58,7 @@ async fn test_zk_cheat_record_works() { #[tokio::test(flavor = "multi_thread")] async fn test_zk_cheat_expect_emit_works() { let runner = TEST_DATA_DEFAULT.runner_zksync(); - let filter = Filter::new("testExpectEmit|testExpectEmitOnCreate", "ZkCheatcodesTest", ".*"); + let filter = Filter::new("testExpectEmit", "ZkCheatcodesTest", ".*"); TestConfig::with_filter(runner, filter).evm_spec(SpecId::SHANGHAI).run().await; } diff --git a/testdata/zk/Cheatcodes.t.sol b/testdata/zk/Cheatcodes.t.sol index 6d66913da..ea6971734 100644 --- a/testdata/zk/Cheatcodes.t.sol +++ b/testdata/zk/Cheatcodes.t.sol @@ -53,12 +53,15 @@ contract Emitter { event EventConstructor(string message); event EventFunction(string message); + string public constant CONSTRUCTOR_MESSAGE = "constructor"; + string public constant FUNCTION_MESSAGE = "function"; + constructor() { - emit EventConstructor("constructor"); + emit EventConstructor(CONSTRUCTOR_MESSAGE); } function functionEmit() public { - emit EventFunction("function"); + emit EventFunction(FUNCTION_MESSAGE); } } @@ -157,6 +160,14 @@ contract ZkCheatcodesTest is DSTest { new Emitter(); } + function testExpectEmitIgnoresStaticCalls() public { + Emitter emitter = new Emitter(); + + vm.expectEmit(true, true, true, true); + emit EventFunction(emitter.FUNCTION_MESSAGE()); + emitter.functionEmit(); + } + function testZkCheatcodesValueFunctionMockReturn() public { InnerMock inner = new InnerMock(); // Send some funds to so it can pay for the inner call From 8cdea1e555c9a43eca573e13355d74b69e197d83 Mon Sep 17 00:00:00 2001 From: Francesco Dainese Date: Mon, 26 Aug 2024 20:30:22 +0200 Subject: [PATCH 3/5] fix(zk): passthru console.logs (but don't record) --- crates/cheatcodes/src/inspector.rs | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/crates/cheatcodes/src/inspector.rs b/crates/cheatcodes/src/inspector.rs index 5d8512a54..7236ac790 100644 --- a/crates/cheatcodes/src/inspector.rs +++ b/crates/cheatcodes/src/inspector.rs @@ -1395,6 +1395,20 @@ impl Cheatcodes { persisted_factory_deps: Some(&mut self.persisted_factory_deps), }; if let Ok(result) = foundry_zksync_core::vm::call::<_, DatabaseError>(call, ecx, ccx) { + // append console logs from zkEVM to the current executor's LogTracer + result.logs.iter().filter_map(decode_console_log).for_each(|decoded_log| { + executor.console_log( + &mut CheatsCtxt { + state: self, + ecx: &mut ecx.inner, + precompiles: &mut ecx.precompiles, + gas_limit: call.gas_limit, + caller: call.caller, + }, + decoded_log, + ); + }); + // skip log processing for static calls if !call.is_static { if let Some(recorded_logs) = &mut self.recorded_logs { @@ -1405,20 +1419,6 @@ impl Cheatcodes { })); } - // append console logs from zkEVM to the current executor's LogTracer - result.logs.iter().filter_map(decode_console_log).for_each(|decoded_log| { - executor.console_log( - &mut CheatsCtxt { - state: self, - ecx: &mut ecx.inner, - precompiles: &mut ecx.precompiles, - gas_limit: call.gas_limit, - caller: call.caller, - }, - decoded_log, - ); - }); - // for each log in cloned logs call handle_expect_emit if !self.expected_emits.is_empty() { for log in result.logs { @@ -1550,6 +1550,7 @@ impl Inspector for Cheatcodes { } fn log(&mut self, _interpreter: &mut Interpreter, _context: &mut EvmContext, log: &Log) { + tracing::error!(?log, "log call"); if !self.expected_emits.is_empty() { expect::handle_expect_emit(self, log); } From 4c366db3ddd0ba487cefea7c128da2d69af80d30 Mon Sep 17 00:00:00 2001 From: Francesco Dainese Date: Mon, 26 Aug 2024 21:01:28 +0200 Subject: [PATCH 4/5] test(zk): check console.log passthru --- testdata/zk/Cheatcodes.t.sol | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/testdata/zk/Cheatcodes.t.sol b/testdata/zk/Cheatcodes.t.sol index ea6971734..f8a3e5fa9 100644 --- a/testdata/zk/Cheatcodes.t.sol +++ b/testdata/zk/Cheatcodes.t.sol @@ -63,6 +63,10 @@ contract Emitter { function functionEmit() public { emit EventFunction(FUNCTION_MESSAGE); } + + function emitConsole(string memory message) public view { + console.log(message); + } } contract ZkCheatcodesTest is DSTest { @@ -235,6 +239,27 @@ contract ZkCheatcodesTest is DSTest { assertEq(entries[10].data, abi.encode("function")); // 11: EthToken } + + function testRecordConsoleLogsLikeEVM() public { + Emitter emitter = new Emitter(); + vm.makePersistent(address(emitter)); + + // ensure we are in zkvm + (bool _success, bytes memory _ret) = address(vm).call(abi.encodeWithSignature("zkVm(bool)", true)); + + vm.recordLogs(); + emitter.emitConsole("zkvm"); + Vm.Log[] memory zkvmEntries = vm.getRecordedLogs(); + + // ensure we are NOT in zkvm + (_success, _ret) = address(vm).call(abi.encodeWithSignature("zkVm(bool)", false)); + + vm.recordLogs(); + emitter.emitConsole("evm"); + Vm.Log[] memory evmEntries = vm.getRecordedLogs(); + + assertEq(zkvmEntries.length, evmEntries.length); + } } contract UsesCheatcodes { From 8616c2e1a7c51026fb283c005845fc1b1fee2bdc Mon Sep 17 00:00:00 2001 From: Francesco Dainese Date: Tue, 27 Aug 2024 18:14:44 +0200 Subject: [PATCH 5/5] chore: remove unnecessary log statement --- crates/cheatcodes/src/inspector.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/crates/cheatcodes/src/inspector.rs b/crates/cheatcodes/src/inspector.rs index 7236ac790..88d09bfba 100644 --- a/crates/cheatcodes/src/inspector.rs +++ b/crates/cheatcodes/src/inspector.rs @@ -1550,7 +1550,6 @@ impl Inspector for Cheatcodes { } fn log(&mut self, _interpreter: &mut Interpreter, _context: &mut EvmContext, log: &Log) { - tracing::error!(?log, "log call"); if !self.expected_emits.is_empty() { expect::handle_expect_emit(self, log); }