Skip to content

feat(tests): converting calldataload and calldatasize tests #1236

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

Merged
merged 1 commit into from
May 8, 2025

Conversation

pacrob
Copy link
Contributor

@pacrob pacrob commented Feb 19, 2025

🗒️ Description

🔗 Related Issues

✅ 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: All converted JSON/YML tests from ethereum/tests have been added to converted-ethereum-tests.txt.
  • Tests: A PR with removal of converted JSON/YML tests from ethereum/tests have been opened.
  • remove calldataload and calldatasize tests tests#1477
  • 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.
  • used geth version 1.15.2-stable-c8c62daf
  • Tests: Ran mkdocs serve locally and verified the auto-generated docs for new tests in the Test Case Reference are correctly formatted.

@pacrob pacrob force-pushed the calldata-tests branch 4 times, most recently from 91c493a to f6a91be Compare March 19, 2025 21:44
@pacrob pacrob marked this pull request as ready for review March 19, 2025 21:45
Account(storage={0x00: 0x11}),
),
(
b"\x1a\x84Q\xe6\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00!\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01",
Copy link
Contributor

Choose a reason for hiding this comment

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

is there better way to declare bytes ? more readable

Copy link
Contributor Author

Choose a reason for hiding this comment

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

shortened and labeled!

@winsvega
Copy link
Contributor

evmone build script failing

@pacrob
Copy link
Contributor Author

pacrob commented Mar 21, 2025

OK, I think it's gtg. Still getting coverage loss though. How can I see what's lost , and is there a solution? I think my previous PR had the same issue.

===============
COVERAGE REPORT
/tests/DIFF/index.html
New covered Lines: 180
New covered function Paths: 77

ERROR: coverage is lost!
Lost coverage Lines: 26
Lost coverage function Paths: 5

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.

Hey, some comments which I think should make the test a bit more EEST-like, but we might lose irrelevant coverage (Like the SHA3 function which is IMO is out-of-scope for these tests) but that's ok.

@pytest.mark.parametrize(
"args_size,sha3_len,storage",
[
("0002", "01", Account(storage={0x00: 0x02})),
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
("0002", "01", Account(storage={0x00: 0x02})),
("0002", "01", 0x02),

Similar comment to previous file, Account(storage=... can be defined inside the function to make the parametrization more readable.

)
)
)
tx_data = bytes.fromhex("1a8451e6" + "00" * 30 + args_size + "00" * 31 + sha3_len)
Copy link
Member

Choose a reason for hiding this comment

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

No need to encode this as call data to be decoded by the contract, args_size and sha3_len could be integers and they could be placed inside of the contract directly:

    to = pre.deploy_contract(
        code=(
            Op.MSTORE(offset=0x0, value=Op.SHA3(offset=0x0, size=sha3_len))
            + Op.CALL(
                gas=Op.SUB(Op.GAS(), 0x100),
                address=address,
                value=0x0,
                args_offset=0x0,
                args_size=args_size,
                ret_offset=0x0,
                ret_size=0x0,
            )
        )
    )

Although I'm having trouble understanding why the original test is using SHA3 in the first place since the memory contents are irrelevant, and my best guess is to just have a non-zero filled memory.

I think we should replace all of this with calldata just like the comment in test_calldataload.py, and also parametrize this function to test calldatasize at the top-level call (returns len(tx.data)) or a sub-level call (returns arg_size).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@marioevz I simplified it a bit, but I'm pretty sure it's still checking correctly. Anything I'm missing?

@pacrob pacrob force-pushed the calldata-tests branch 3 times, most recently from eb7658b to 982f52f Compare April 4, 2025 20:34
@winsvega
Copy link
Contributor

winsvega commented Apr 7, 2025

lets add push32, mstore8, add opcodes to default opcodes exempt from coverage check requirements.
it is in the file tests/homestead/coverage/test_coverage.py

@pacrob pacrob force-pushed the calldata-tests branch 2 times, most recently from 13ce646 to b07e05c Compare April 7, 2025 23:55
@pacrob
Copy link
Contributor Author

pacrob commented Apr 8, 2025

lets add push32, mstore8, add opcodes to default opcodes exempt from coverage check requirements. it is in the file tests/homestead/coverage/test_coverage.py

Not all fixed, but better. Thanks!

before:

ERROR: coverage is lost!
Lost coverage Lines: 34
Lost coverage function Paths: 11

after:

ERROR: coverage is lost!
Lost coverage Lines: 33
Lost coverage function Paths: 3

@pacrob
Copy link
Contributor Author

pacrob commented Apr 9, 2025

Latest coverage fail:

Lost coverage Lines: 56
Lost coverage function Paths: 9

Looking into it:

expected:

  • Lost 22 lines and 6 functions from lib/evmone due to no longer using keccak or calldataload in the calldatasize test
  • Lost 7 lines test/state/host.cpp, 3 lines and one function in test/state/host.cpp due to not including a value in the transaction in the calldatasize test.

unknown:

  • Lost 2 lines in evmc/include/evmc, showing that the test is no longer checking Prague. Why might that be happening?
  • Leaving 22 lines and 2 functions across mpt.cpp, state.cpp, and system_contracts.cpp. Not sure of source.

I'll keep poking, but if you know whether the last 2 can be fixed or should be ignored, let me know!

@winsvega
Copy link
Contributor

About sha3

I don't get what are the inputs for call in Oris test.
I suggest we debug original test, derrive the inputs and reproduce in python.

@spencer-tb spencer-tb changed the title converting calldataload and calldatasize tests feat(tests): converting calldataload and calldatasize tests Apr 14, 2025
@spencer-tb spencer-tb added scope:tests Scope: Changes EL client test cases in `./tests` port Related to porting ethereum/tests to EEST type:feat type: Feature and removed port Related to porting ethereum/tests to EEST labels Apr 14, 2025
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.

Hey, some comments, sorry about the back and forth but hopefully this is the last one :)

Comment on lines 53 to 65
address_b = pre.deploy_contract(
Om.MSTORE(calldata, 0x0)
+ Op.CALL(
gas=Op.SUB(Op.GAS(), 0x100),
address=address_a,
value=0x0,
args_offset=0x0,
args_size=len(calldata),
ret_offset=0x0,
ret_size=0x0,
)
)

to = pre.deploy_contract(
code=(
Op.ADD(0x1000, Op.CALLDATALOAD(offset=0x4))
+ Op.CALL(
gas=Op.SUB(Op.GAS(), 0x100),
address=address_b,
value=0x0,
args_offset=0x0,
args_size=0x0,
ret_offset=0x0,
ret_size=0x0,
)
+ Op.STOP
),
)
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
address_b = pre.deploy_contract(
Om.MSTORE(calldata, 0x0)
+ Op.CALL(
gas=Op.SUB(Op.GAS(), 0x100),
address=address_a,
value=0x0,
args_offset=0x0,
args_size=len(calldata),
ret_offset=0x0,
ret_size=0x0,
)
)
to = pre.deploy_contract(
code=(
Op.ADD(0x1000, Op.CALLDATALOAD(offset=0x4))
+ Op.CALL(
gas=Op.SUB(Op.GAS(), 0x100),
address=address_b,
value=0x0,
args_offset=0x0,
args_size=0x0,
ret_offset=0x0,
ret_size=0x0,
)
+ Op.STOP
),
)
to = pre.deploy_contract(
Om.MSTORE(calldata, 0x0)
+ Op.CALL(
gas=Op.SUB(Op.GAS(), 0x100),
address=address_a,
value=0x0,
args_offset=0x0,
args_size=len(calldata),
ret_offset=0x0,
ret_size=0x0,
)
)

Can be simplified like this.

It might result in a drop in coverage because we eliminate the use of the ADD opcode, but it's not the focus of the test so it's ok.

Reason behind these extra contracts in the original test is because the original yml hardcoded many contracts in the same test, but it's no longer necessary.

Copy link
Member

Choose a reason for hiding this comment

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

We could also do a variant of the test where the entry point is address_a to verify that Op.CALLDATALOAD behaves correctly when it's fetching data from the transaction's calldata.

@pytest.mark.parametrize("calldata_source", ["tx", "contract"])

And if calldata_source == "tx":

tx = Transaction(
        data=calldata,
        gas_limit=100_000,
        protected=fork >= Byzantium,
        sender=pre.fund_eoa(),
        to=address_a,
    )

And the to contract is omitted entirely.

Comment on lines 28 to 41
to = pre.deploy_contract(
code=(
Om.MSTORE(b"\x01" * args_size, 0x0)
+ Op.CALL(
gas=Op.SUB(Op.GAS(), 0x100),
address=address,
value=0x0,
args_offset=0x0,
args_size=args_size,
ret_offset=0x0,
ret_size=0x0,
)
)
)
Copy link
Member

Choose a reason for hiding this comment

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

Same comment as the other test where we can parametrize by calldata_source.

@pacrob pacrob force-pushed the calldata-tests branch 2 times, most recently from 6e2c9fa to e67cdd5 Compare May 5, 2025 18:56
@pacrob pacrob force-pushed the calldata-tests branch from e67cdd5 to 47abd75 Compare May 5, 2025 19:00
@pacrob pacrob force-pushed the calldata-tests branch from 47abd75 to 96a761a Compare May 5, 2025 19:02
@pacrob
Copy link
Contributor Author

pacrob commented May 5, 2025

Hey, @marioevz, I've addressed your recent feedback. Let me know if you have more!

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, thanks!

@marioevz
Copy link
Member

marioevz commented May 8, 2025

Checking the lost coverage and it's due of the following reasons:

  • Removal of SHA3 opcode.
  • Account deletion code branches.
  • Value transferring code branches.
    The lost coverage is not relevant to the test, so we can safely proceed to merge.

@marioevz marioevz merged commit 244852f into ethereum:main May 8, 2025
11 of 12 checks passed
@pacrob pacrob deleted the calldata-tests branch May 9, 2025 12:09
felix314159 pushed a commit to felix314159/execution-spec-tests that referenced this pull request May 12, 2025
felix314159 pushed a commit to felix314159/execution-spec-tests that referenced this pull request May 16, 2025
codeofcarson pushed a commit to codeofcarson/execution-spec-tests that referenced this pull request Jul 1, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
port Related to porting ethereum/tests to EEST scope:tests Scope: Changes EL client test cases in `./tests` type:feat type: Feature
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants