Skip to content

feat(zkevm): add log opcode worst case #1745

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

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

LouisTsai-Csie
Copy link
Collaborator

@LouisTsai-Csie LouisTsai-Csie commented Jun 15, 2025

🗒️ Description

Create Benchmark for LOG Opcode

This PR introduces a benchmark for the LOG opcode in the EVM. The LOG operation includes multiple fields: offset, size, and up to N topics depending on the variant (LOG0 through LOG4).

Gas Cost Calculation

Using LOG0 as an example, the gas cost for the LOG operation is computed as:

  • Static gas: 375
  • Dynamic gas:dynamic_gas = 375 * topic_count + 8 * size + memory_expansion_cost

To minimize gas costs:

  • Use zero size to avoid dynamic gas from memory access.
  • Use PUSH0 (which costs 2 bytes) for pushing values to the stack, as it’s cheaper than other operation like PUSH1 (3 bytes with an immediate) or DUP1 (3 bytes).

Using PUSH0 is also more space-efficient, since it avoids including immediate values and reduces bytecode size.

Benchmark Bytecode Pattern

A minimal loopable pattern for benchmarking LOGN looks like this:

JUMPDEST
PUSH0      ; offset
PUSH0      ; size
...        ; PUSH0 repeated N times for each topic
LOGN
...        ; repeatable pattern
PUSH0
JUMP

Using PUSH0 is also more space-efficient, since it avoids including immediate values and reduces bytecode size. This makes it preferable over DUP1 for setting up the stack for topics or memory offset/size.

🔗 Related Issues

Issue #1689

✅ Checklist

  • All: Set appropriate labels for the changes.
  • All: Considered squashing commits to improve commit history.
  • All: Added an entry to CHANGELOG.md.
  • All: Considered updating the online docs in the ./docs/ directory.
  • Tests: A PR with removal of converted JSON/YML blockchain tests from ethereum/tests have been opened.
  • Tests: Included the type and version of evm t8n tool used to locally execute test cases: e.g., ref with commit hash or geth 1.13.1-stable-3f40e65.
  • Tests: Ran mkdocs serve locally and verified the auto-generated docs for new tests in the Test Case Reference are correctly formatted.
  • Tests: For PRs implementing a missed test case, update the post-mortem document to add an entry the list.

@LouisTsai-Csie LouisTsai-Csie self-assigned this Jun 15, 2025
@LouisTsai-Csie LouisTsai-Csie marked this pull request as ready for review June 15, 2025 14:19
@LouisTsai-Csie LouisTsai-Csie added the scope:tests Scope: Changes EL client test cases in `./tests` label Jun 16, 2025
@LouisTsai-Csie LouisTsai-Csie requested review from jochem-brouwer and jsign and removed request for jochem-brouwer June 16, 2025 09:19
Copy link
Member

@jochem-brouwer jochem-brouwer left a comment

Choose a reason for hiding this comment

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

This test looks fine to me, it tests all LOG opcodes and runs those all as much as possible. However, I think we should also add these situations:

  • Log data length is nonzero
  • Log data length + data is nonzero (here we have to initialize the memory to something non-zero)
  • The topics are nonzero

I am not sure because I am not deep into zkEVM, is calculating the logsBloom part of the scope of the EVM (and would thus add extra logic/cycles) @jsign? If this is indeed part of it (either logsBloom or calculating receiptTrie or both) then those tests should be added for zkEVM (can be done in a different PR).

Those tests are also nice benchmark tests for non-zkEVM also 😄 👍

Will not explicitly approve for now.

@LouisTsai-Csie
Copy link
Collaborator Author

Thanks for comment, I do not know logsBloom and receiptTrie before, i will review some documentation for them

@jsign
Copy link
Collaborator

jsign commented Jun 16, 2025

This test looks fine to me, it tests all LOG opcodes and runs those all as much as possible. However, I think we should also add these situations:

  • Log data length is nonzero
  • Log data length + data is nonzero (here we have to initialize the memory to something non-zero)
  • The topics are nonzero

I am not sure because I am not deep into zkEVM, is calculating the logsBloom part of the scope of the EVM (and would thus add extra logic/cycles) @jsign? If this is indeed part of it (either logsBloom or calculating receiptTrie or both) then those tests should be added for zkEVM (can be done in a different PR).

Those tests are also nice benchmark tests for non-zkEVM also 😄 👍

Will not explicitly approve for now.

Yep, calculating logsBloom/receipts is part of proving -- so I agree that it is useful to cover the cases you mentioned.

Copy link
Collaborator

@jsign jsign left a comment

Choose a reason for hiding this comment

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

Looking good! Reg @jochem-brouwer suggestion to cover non-zero scenarios (which I agree are useful), I'll let you decide if those might be worked in this PR or in a separate one -- for now leaving an approval if it is the latter.

Just left one comment for your consideration.



@pytest.mark.parametrize(
"opcode,topic_count",
Copy link
Collaborator

Choose a reason for hiding this comment

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

Maybe we can remove the topic_count parameter, and derive it from opcode - Op.LOG0?
Mainly because combinations like Op.LOG0, 1 or Op.LOG3, 4 would never make sense?

Copy link
Member

Choose a reason for hiding this comment

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

I like this suggestion 😄

Copy link
Member

@marioevz marioevz left a comment

Choose a reason for hiding this comment

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

LGTM, just one suggestion that is in line with the comments from previous reviewers, thanks!

env = Environment()
max_code_size = fork.max_code_size()

iter_code = Op.PUSH0 * (2 + topic_count) + opcode
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
iter_code = Op.PUSH0 * (2 + topic_count) + opcode
iter_code = Op.PUSH0 * len(opcode.kwargs) + opcode

And you can remove the topic_count parameter.

@LouisTsai-Csie LouisTsai-Csie marked this pull request as draft June 17, 2025 10:55
@marioevz
Copy link
Member

For the mypy error, I think if you rebase to main it should be gone, I just fixed that in another PR.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature:zkevm scope:tests Scope: Changes EL client test cases in `./tests`
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants