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(cheatcodes): Make expectEmit only work for the next call #4920

Merged
merged 15 commits into from
May 12, 2023
Prev Previous commit
Next Next commit
chore: fix additive behavior
Evalir committed May 11, 2023

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature.
commit fe2afecf4b4aa502f95de9cfbdab6b7bae166efd
14 changes: 11 additions & 3 deletions evm/src/executor/inspector/cheatcodes/expect.rs
Original file line number Diff line number Diff line change
@@ -127,14 +127,23 @@ pub fn handle_expect_emit(state: &mut Cheatcodes, log: RawLog, address: &Address
// We expect for emit checks to be filled as they're declared (from oldest to newest),
// so we fill them and push them to the back of the queue.
// If the user has properly filled all the emits, they'll end up in their original order.
// If not, we can detect this later and error out.
// If not, the queue will not be in the order the events will be intended to be filled,
// and we'll be able to later detect this and bail.

// First, we can return early if all events have been matched.
// This allows a contract to arbitrarily emit more events than expected (additive behavior),
// as long as all the previous events were matched in the order they were expected to be.
if !state.expected_emits.iter().any(|expected| !expected.found) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is the same as if state.expected_emits.iter().all(|expected| expected.found), right?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yep indeed

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done in d72a935 , waiting for ci

return
}

// if there's anything to fill, we need to pop back.
let event_to_fill_or_check =
if state.expected_emits.iter().any(|expected| expected.log.is_none()) {
state.expected_emits.pop_back()
// Else, if there are any events that are unmatched, we try to match to match them
// in the order declared, so we start popping from the front (like a queue).
} else {
// Else, we need to pop from the front in the order the events were added to the queue.
state.expected_emits.pop_front()
};

@@ -177,7 +186,6 @@ pub fn handle_expect_emit(state: &mut Cheatcodes, log: RawLog, address: &Address
event_to_fill_or_check.log = Some(log);
}
}

state.expected_emits.push_back(event_to_fill_or_check);
}

4 changes: 3 additions & 1 deletion evm/src/executor/inspector/cheatcodes/mod.rs
Original file line number Diff line number Diff line change
@@ -527,7 +527,6 @@ where
topics: &[B256],
data: &bytes::Bytes,
) {
// Match logs if `expectEmit` has been called
if !self.expected_emits.is_empty() {
handle_expect_emit(
self,
@@ -831,6 +830,9 @@ where
}

// Check if we have any leftover expected emits
// First, if any emits were found at the root call, then we its ok and we remove them.
self.expected_emits.retain(|expected| !expected.found);
// If not empty, we got mismatched emits
if !self.expected_emits.is_empty() {
return (
InstructionResult::Revert,