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

fix(zk): avoid observing log from staticcalls #547

Merged
merged 8 commits into from
Aug 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
27 changes: 15 additions & 12 deletions crates/cheatcodes/src/inspector.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1395,14 +1395,6 @@ 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,
}));
}

// 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(
Expand All @@ -1417,10 +1409,21 @@ impl Cheatcodes {
);
});

// 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);
// 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,
}));
}

// 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);
}
}
}

Expand Down
2 changes: 1 addition & 1 deletion crates/forge/tests/it/zk/cheats.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
40 changes: 38 additions & 2 deletions testdata/zk/Cheatcodes.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -53,12 +53,19 @@ 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);
}

function emitConsole(string memory message) public view {
console.log(message);
}
}

Expand Down Expand Up @@ -157,6 +164,14 @@ contract ZkCheatcodesTest is DSTest {
new Emitter();
}

function testExpectEmitIgnoresStaticCalls() public {
elfedy marked this conversation as resolved.
Show resolved Hide resolved
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
Expand Down Expand Up @@ -224,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 {
Expand Down