-
Notifications
You must be signed in to change notification settings - Fork 88
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(tests): PUSH* #975
base: main
Are you sure you want to change the base?
✨ feat(tests): PUSH* #975
Conversation
sender=pre.fund_eoa(), | ||
to=contract, | ||
gas_limit=500_000, | ||
protected=False if fork in [Frontier, Homestead] else True, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This snippet appears throughout the codebase. I would like to refactor it into a helper function to avoid repetition, but I fear this to be a pedantic optimization. Developers unaware of the helper function might end up repeating this code.
This snippet also reveals a fact: a transaction is a function of the fork in which its executed, since forks can influence how a transaction behaves. I believe pytest Transaction
class should have a fork field, which would allow the class to abstract fork-specific transaction mutations, like this one. I’m noting this for what it’s worth, not suggesting we should take action on it right now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good observation, a possible solution could to make tx
a pytest fixture (as pre
is right now) which would allow automatic setting of the protected
field based on the value of fork
(which is also a pytest fixture). tx
would have to be specified in the function arguments, as is pre
right now.
I would like to add this functionality anyway, I think it's a possible solution that would allow generalization of transactions for other chains, unlocking EEST for L2 EVM testing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thats a nice solution. I'm noting things that feels against the grain as I port more tests. Should we create an issue for this?
I don't understand how the contents of converted-ethereum-tests.txt is ordered. Do I just add this at the end of the file? |
Yup, just tack it on at the end 🙃 This is the current limitation that I mentioned in the call. We could make this file structured instead of using plain text, but I think an even better solution would be to add a @pytest.mark.ported_from("src/GeneralStateTestsFiller/VMTests/vmTests/pushFiller.yml", "ref=ff138a31ffd109b5ef0d5dd735a8914a60d95fe7") This would even allow us to create a dedicated section in the docs, for example, that lists tests ported from ethereum/tests. Open to suggestions on this. I think the only source of ported tests would be ethereum/tests? But we could think about adding other metadata tags such as "fuzz", "gentest", "bug", etc. |
Yep! This would be really nice.
Perhaps we can add a generic "meta" marker that lets you add arbitrary metadata? |
Co-authored-by: danceratopz <[email protected]>
@raxhvl: Sometimes it can be tricky to get coverage parity, please reach out to @winsvega if you can't see anything obvious and need some pointers. An example, although not applicable here, is if you port a YAML test with Yul Code to a Python test using execution-spec-tests/tests/homestead/coverage/test_coverage.py Lines 16 to 29 in 5cf1f24
|
Thanks @danceratopz Let me give it a shot. I'm sure this will take some time, but I hope to pick up some learnings for future reference. If I get to a standstill, I will reach out to @winsvega. |
I spent last week trying to understand how coverage works, and why its failing here. TL;DR: The current test uses fewer opcodes to achieve the same result. Previous strategyThe base test is parameterized using calldata. Here is a simplified pseudocode of how it works: for calldata in [0..1f]:
call(
gas=gas(), address=add(0x1000,calldata(4)), value=0, argOffset=0, argSize=0,
returnOffset=0, returnSize=0
) Full bytecode:
In this setup, the each calldata is mapped to a contract address, which focuses on a single Call data containing a (redundant) function selector + destination contract address: 0x693c61390000000000000000000000000000000000000000000000000000000000000000 Current strategyIn the current approach, a unique contract is deployed for each PUSH opcode at the to address, eliminating the need for routing. Parameterization is handled directly by pytest. Why coverage failsThe absence of a routing mechanism in the current test causes coverage failures. The simplified structure of the test means that opcodes like This is inherently because of the difference in test strategies: parameterization using EVM vs parameterization using pytest. Larger pictureThe base test employs a relatively complex strategy. Two areas of complexity include:
Moreover, we should aim to test with a minimal set of opcodes—in this case, With pytest now handling parameterization, the complex routing logic is no longer necessary. I'm still very new to this, so its quite likely that I'm missing an important piece here. But this is my understanding of the problem. |
Yes, we have already some basic coverage that is applied by default. In test_all_opcodes.py. But the goal of coverage here is to check that at least no lines lost after converting the test. Reading the coverage report already helped me to find out a few bugs where I relied that code works, but it didn't |
🗒️ Description
Introduces tests for
PUSH*
opcodes ported fromethereum/tests
.🔗 Related Issues
closes #974
✅ Checklist
mkdocs serve
locally and verified the auto-generated docs for new tests in the Test Case Reference are correctly formatted.