ethereum / execution-specs

Specification for the Execution Layer. Tracking network upgrades.
Creative Commons Zero v1.0 Universal
809 stars 223 forks source link

Implement Evm Trace #828

Closed gurukamath closed 9 months ago

gurukamath commented 10 months ago

(closes #624 )

What was wrong?

The specs don't currently implement the full evm trace.

Related to Issue #624

How was it fixed?

Implemented full evm trace and integrated it fully with t8n.

Cute Animal Picture

Put a link to a cute animal picture inside the parenthesis-->

gurukamath commented 10 months ago

Currently implemented the trace only for Shanghai. Will be ported to the other forks after review.

codecov-commenter commented 10 months ago

Codecov Report

Patch coverage: 74.03% and project coverage change: +0.03% :tada:

Comparison is base (adc6acf) 74.06% compared to head (753416e) 74.09%. Report is 8 commits behind head on master.

Additional details and impacted files ```diff @@ Coverage Diff @@ ## master #828 +/- ## ========================================== + Coverage 74.06% 74.09% +0.03% ========================================== Files 571 572 +1 Lines 31735 32018 +283 ========================================== + Hits 23503 23725 +222 - Misses 8232 8293 +61 ``` | [Flag](https://app.codecov.io/gh/ethereum/execution-specs/pull/828/flags?src=pr&el=flags&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=ethereum) | Coverage Δ | | |---|---|---| | [unittests](https://app.codecov.io/gh/ethereum/execution-specs/pull/828/flags?src=pr&el=flag&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=ethereum) | `74.09% <74.03%> (+0.03%)` | :arrow_up: | Flags with carried forward coverage won't be shown. [Click here](https://docs.codecov.io/docs/carryforward-flags?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=ethereum#carryforward-flags-in-the-pull-request-comment) to find out more. | [Files Changed](https://app.codecov.io/gh/ethereum/execution-specs/pull/828?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=ethereum) | Coverage Δ | | |---|---|---| | [src/ethereum/\_\_init\_\_.py](https://app.codecov.io/gh/ethereum/execution-specs/pull/828?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=ethereum#diff-c3JjL2V0aGVyZXVtL19faW5pdF9fLnB5) | `100.00% <ø> (ø)` | | | [src/ethereum/arrow\_glacier/fork.py](https://app.codecov.io/gh/ethereum/execution-specs/pull/828?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=ethereum#diff-c3JjL2V0aGVyZXVtL2Fycm93X2dsYWNpZXIvZm9yay5weQ==) | `0.00% <ø> (ø)` | | | [src/ethereum/arrow\_glacier/utils/message.py](https://app.codecov.io/gh/ethereum/execution-specs/pull/828?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=ethereum#diff-c3JjL2V0aGVyZXVtL2Fycm93X2dsYWNpZXIvdXRpbHMvbWVzc2FnZS5weQ==) | `0.00% <ø> (ø)` | | | [src/ethereum/arrow\_glacier/vm/\_\_init\_\_.py](https://app.codecov.io/gh/ethereum/execution-specs/pull/828?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=ethereum#diff-c3JjL2V0aGVyZXVtL2Fycm93X2dsYWNpZXIvdm0vX19pbml0X18ucHk=) | `0.00% <0.00%> (ø)` | | | [src/ethereum/arrow\_glacier/vm/gas.py](https://app.codecov.io/gh/ethereum/execution-specs/pull/828?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=ethereum#diff-c3JjL2V0aGVyZXVtL2Fycm93X2dsYWNpZXIvdm0vZ2FzLnB5) | `0.00% <0.00%> (ø)` | | | [.../ethereum/arrow\_glacier/vm/instructions/storage.py](https://app.codecov.io/gh/ethereum/execution-specs/pull/828?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=ethereum#diff-c3JjL2V0aGVyZXVtL2Fycm93X2dsYWNpZXIvdm0vaW5zdHJ1Y3Rpb25zL3N0b3JhZ2UucHk=) | `0.00% <0.00%> (ø)` | | | [...c/ethereum/arrow\_glacier/vm/instructions/system.py](https://app.codecov.io/gh/ethereum/execution-specs/pull/828?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=ethereum#diff-c3JjL2V0aGVyZXVtL2Fycm93X2dsYWNpZXIvdm0vaW5zdHJ1Y3Rpb25zL3N5c3RlbS5weQ==) | `0.00% <0.00%> (ø)` | | | [src/ethereum/arrow\_glacier/vm/interpreter.py](https://app.codecov.io/gh/ethereum/execution-specs/pull/828?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=ethereum#diff-c3JjL2V0aGVyZXVtL2Fycm93X2dsYWNpZXIvdm0vaW50ZXJwcmV0ZXIucHk=) | `0.00% <0.00%> (ø)` | | | [src/ethereum/berlin/fork.py](https://app.codecov.io/gh/ethereum/execution-specs/pull/828?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=ethereum#diff-c3JjL2V0aGVyZXVtL2Jlcmxpbi9mb3JrLnB5) | `93.85% <ø> (+0.02%)` | :arrow_up: | | [src/ethereum/berlin/utils/message.py](https://app.codecov.io/gh/ethereum/execution-specs/pull/828?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=ethereum#diff-c3JjL2V0aGVyZXVtL2Jlcmxpbi91dGlscy9tZXNzYWdlLnB5) | `96.00% <ø> (ø)` | | | ... and [97 more](https://app.codecov.io/gh/ethereum/execution-specs/pull/828?src=pr&el=tree-more&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=ethereum) | |

:umbrella: View full report in Codecov by Sentry.
:loudspeaker: Have feedback on the report? Share it here.

gurukamath commented 10 months ago

Since the evm tests fail for the forks before Shanghai, I have added a temporary if condition. This is just so we see all the tests passing in the CI. Once the Shanghai changes have been reviewed and are ported over to the other forks, this if condition goes away before merging all the changes with master.

gurukamath commented 10 months ago

Probably still here because you've only done Shanghai so far, but just in case, you'll want to remove this as well:

https://github.com/ethereum/execution-specs/blob/fade6e95726c9c0b47b779fd8873b5737fbea3b3/src/ethereum/__init__.py#L31-L37

Yes. This will also go after porting the changes to the other forks.

gurukamath commented 10 months ago

@SamWilsn @petertdavies Have updated the relevant bits based on your comments.

@danceratopz Have updated the tool to reflect specific output file names. Please verify.

danceratopz commented 10 months ago

@gurukamath Yes, if I apply #823 to this branch, it now works as expected with https://github.com/ethereum/execution-spec-tests/pull/289 as-is, thanks!

gurukamath commented 9 months ago

@SamWilsn @petertdavies Have ported the changes over to the older forks.

The main update from the earlier commits in this PR is that the refund calculation for SELFDESTRUCT is moved from the interpreter module into the opcode itself (mainly relevant to Berlin and before). This requires making the accounts_to_delete from the parent evm available to the child evm.

danceratopz commented 9 months ago

Hi @gurukamath, I took a deeper look at the traces generated from the current execution-spec-tests and diff'd the traces generated from geth 1.13.1-stable-3f40e65c and the ethereum-spec-evm from this branch (753416e7a70c43bc00c032e3e58ebd9570b7192c).

The traces are almost identical :partying_face: and only differ upon an error in execution. They fall into 2 categories.

  1. Missing exception message upon error. Here are examples of the 4 missing message types (here they are in ethereum/go-ethereum/core/vm/errors.go#L24@90d5bd85, I have no idea if they are standardized):
    • test_push0_stack_overflow_fork_Shanghai/1/trace-0-0xf8616cc40f214a4729758189c77720a6b672f29dcb62cd206a49ebacaf00e96f.jsonl
        1028,1029c1028,1029
        < {"pc":1028,"op":95,"gas":"0xd63f","gasCost":"0x2","memSize":0,"stack":["0x0", <full stack ommitted>, "0x0"],"depth":1,"refund":0,"opName":"PUSH0","error":"stack limit reached 1024 (1023)"}
        < {"output":"","gasUsed":"0x13498","error":"stack limit reached 1024 (1023)"}
        ---
        > {"pc":1028,"op":95,"gas":"0xd63f","gasCost":"0x2","memSize":0,"stack":["0x0", <full stack ommitted>, "0x0"],"depth":1,"refund":0,"opName":"PUSH0","error":""}
        > {"output":"","gasUsed":"0x13498","error":""}
    • test_create_opcode_initcode_fork_Shanghai_create2_over_limit_ones/1/trace-0-0xff8b41168839e22964df27b1810063b71235dd344b1473025c2c9473f380cd02.jsonl
        23c23
        < {"pc":17,"op":245,"gas":"0x4c151c","gasCost":"0x7d00","memSize":49184,"stack":["0x4c1527","0xdeadbeef","0xc001","0x0","0x0"],"depth":2,"refund":0,"opName":"CREATE2","error":"out of gas"}
        ---
        > {"pc":17,"op":245,"gas":"0x4c151c","gasCost":"0xad08","memSize":49184,"stack":["0x4c1527","0xdeadbeef","0xc001","0x0","0x0"],"depth":2,"refund":0,"opName":"CREATE2","error":""}
    • test_gas_usage_fork_Shanghai_too_little_execution_gas_49121_bytes/1/trace-0-0x1e4296b38ebdc740cd34f5b63602660f115815a352821261416a379a03054832.jsonl
        8c8
        < {"output":"00","gasUsed":"0xdf","error":"contract creation code storage out of gas"}
        ---
        > {"output":"","gasUsed":"0xdf","error":""}
    • test_withdrawing_to_precompiles_fork_Shanghai_precompile_9_amount_1/2/trace-0-0x3e9f556a7efc77edc7e00178f4c3d226633320d06a8289cce10d363f713f50a9.jsonl
        1c1
        < {"output":"","gasUsed":"0x13498","error":"invalid input length"}
        ---
        > {"output":"","gasUsed":"0x13498","error":""}
  2. Different reported gasCost upon an exception caused by initcode that is over the allowed limit when calling CREATE or CREATE2, the gas cost for the reverted transaction is, however, identical:
    • test_create_opcode_initcode_fork_Shanghai_create2_over_limit_ones/1/trace-0-0xff8b41168839e22964df27b1810063b71235dd344b1473025c2c9473f380cd02.jsonl
      23c23
      < {"pc":17,"op":245,"gas":"0x4c151c","gasCost":"0x7d00","memSize":49184,"stack":["0x4c1527","0xdeadbeef","0xc001","0x0","0x0"],"depth":2,"refund":0,"opName":"CREATE2","error":"out of gas"}
      ---
      > {"pc":17,"op":245,"gas":"0x4c151c","gasCost":"0xad08","memSize":49184,"stack":["0x4c1527","0xdeadbeef","0xc001","0x0","0x0"],"depth":2,"refund":0,"opName":"CREATE2","error":""}
gurukamath commented 9 months ago
  1. Missing exception message upon error. Here are examples of the 4 missing message types (here they are in ethereum/go-ethereum/core/vm/errors.go#L24@90d5bd85, I have no idea if they are standardized):

The specs do not currently emit comprehensive error messages. We are working on it and have an active issue ( see #795 )

  1. Different reported gasCost upon an exception caused by initcode that is over the allowed limit when calling CREATE or CREATE2, the gas cost for the reverted transaction is, however, identical:

    • test_create_opcode_initcode_fork_Shanghai_create2_over_limit_ones/1/trace-0-0xff8b41168839e22964df27b1810063b71235dd344b1473025c2c9473f380cd02.jsonl
      23c23
      < {"pc":17,"op":245,"gas":"0x4c151c","gasCost":"0x7d00","memSize":49184,"stack":["0x4c1527","0xdeadbeef","0xc001","0x0","0x0"],"depth":2,"refund":0,"opName":"CREATE2","error":"out of gas"}
      ---
      > {"pc":17,"op":245,"gas":"0x4c151c","gasCost":"0xad08","memSize":49184,"stack":["0x4c1527","0xdeadbeef","0xc001","0x0","0x0"],"depth":2,"refund":0,"opName":"CREATE2","error":""}

We are aware that in some cases where the opcode runs out of gas, geth and specs might emit different gas costs. In almost all such cases, I have found that geth emits only the static part of the gas cost. See this geth issue for more details.

However, I would also like to take a deeper look at this particular case just to make sure that it is a similar case. Would it be possible for you to provide the input json files for running this? Or alternatively, point me to the fixture in the tests repo that has this case?

danceratopz commented 9 months ago

Thanks for info and links.

However, I would also like to take a deeper look at this particular case just to make sure that it is a similar case. Would it be possible for you to provide the input json files for running this? Or alternatively, point me to the fixture in the tests repo that has this

Github wouldn't let me upload json or tgz - I'll send you the files another way.

In general, you could run this test case from ethereum/execution-spec-tests in isolation with:

fill tests/shanghai/eip3860_initcode/test_initcode.py::TestCreateInitcode::test_create_opcode_initcode[fork=Shanghai-create2-over_limit_ones] --evm-bin=/path/to/execution-specs/venv/bin/ethereum-spec-evm--output=output/
gurukamath commented 9 months ago

In general, you could run this test case from ethereum/execution-spec-tests in isolation with:

fill tests/shanghai/eip3860_initcode/test_initcode.py::TestCreateInitcode::test_create_opcode_initcode[fork=Shanghai-create2-over_limit_ones] --evm-bin=/path/to/execution-specs/venv/bin/ethereum-spec-evm--output=output/

@danceratopz I did look into this case and is similar to the scenario that I pointed out earlier. Geth figures out that the opcode is going to run out of gas due to large init code. For efficiency reasons, it then does not even bother to calculate the dynamic gas because it makes no difference. So it just emits the static part in the trace.

The specs on the other hand calculate all the components of the gas (static + dynamic) and emits that in the trace. I am not sure if there is a standard behaviour that is agreed upon in this case. At least, I couldn't find anything in EIP-3155. For greater context on such issues you can follow the issue on the geth repo that linked earlier. See here