Add configurable-sized contract templates to use with EELS - #114
Add configurable-sized contract templates to use with EELS#114jochem-brouwer wants to merge 2 commits into
Conversation
780b55c to
c76c554
Compare
CPerezz
left a comment
There was a problem hiding this comment.
None of the templates were added to the CI to be tested.
See docs/SKILL.md:
"add a covering entity to examples/full-matrix-spec-feature.yaml so CI exercises it."
Other stale docs after the additions:
internal/specbuild/full_matrix_test.go:32— entity count pinned at 29docs/SKILL.md— "29-entity" appears three times (frontmatter description, "Read these first", "Canonical spec reference")
Also, can we please remove drastically the verbosity of the comments? It's a lot of LOC just wasted in AI slop. Not really adding a ton of value.
Another note, for unique_jumpdest, the entry JUMP targets code_size - 1. JUMPDEST validity requires the target not be push-data, but the embedded address bytes at 0x2C..0x40 are decoded as opcodes during analysis, and an address byte that happens to be a PUSHn swallows up to 32 following bytes.
At code_size: 0x41 the target (0x40) sits immediately after the address, so for a large fraction of derived addresses the entry jump is invalid and any CALL exceptionally halts.
| // TestBuildUniqueJumpdestInitcodeMatchesEESTSizes pins keccak256 of the | ||
| // size-adjustable initcode against execution-specs | ||
| // `JochemnetPredeployContractInitcode(code_size=...)` for sizes on both | ||
| // sides of the PUSH2→PUSH3 entry-encoding boundary at 0x010000. | ||
| // Regenerate from an execution-specs checkout: | ||
| // | ||
| // import sys; sys.path.insert(0, 'tests/benchmark') | ||
| // from helper.account_creator import JochemnetPredeployContractInitcode | ||
| // from execution_testing import keccak256 | ||
| // print(keccak256(bytes(JochemnetPredeployContractInitcode(code_size=CS))).hex()) | ||
| // | ||
| // If EEST changes the Python initcode shape, update these constants in | ||
| // lockstep — both sides must always agree byte-for-byte. | ||
| func TestBuildUniqueJumpdestInitcodeMatchesEESTSizes(t *testing.T) { | ||
| cases := []struct { | ||
| codeSize uint64 | ||
| keccak string | ||
| }{ | ||
| {0x41, "0x38c595a4df0631d8df37721abc62f2a2834f09c6019cc4e0cab1af5b6dab2e6b"}, | ||
| {0x100, "0xd925f01c3f4a9a5ce1d3bb1452d7ff2e020ed423b78a88261e6147eb0df586ce"}, | ||
| // Default size: same pin as TestBuildUniqueJumpdestInitcodeMatchesEEST. | ||
| {0x6000, "0xb9cdb9047474294c9743cf3944156c844bf91763de66271493caa07a3de77ec5"}, | ||
| // Largest PUSH2-encoded size (entry `PUSH2 0xFFFF; JUMP`). | ||
| {0x10000, "0xc255e15a2e24a89fd585858f4b20b46fe8eab3ce309d994be18f343f539823bb"}, | ||
| // First PUSH3-encoded size (entry `PUSH3 0x010000; JUMP`). | ||
| {0x10001, "0xfb6c8fdbd5b4f1624cb84a9fc37181e6aab74f3bbb0990f58e6d13c49cd8baf8"}, | ||
| {0x20000, "0xc03348b4fde3c0eed2f9707c8b003c62ae4752d85f36544d1a2ddad623114d07"}, | ||
| // The PUSH3-capped maximum. | ||
| {0x1000000, "0x51f4a0dab520358d8b1a8c641f318e3fefbf722c164807c11c1ee76504ffc5d2"}, | ||
| } | ||
| for _, c := range cases { | ||
| got := crypto.Keccak256Hash(BuildUniqueJumpdestInitcode(c.codeSize)).Hex() | ||
| if got != c.keccak { | ||
| t.Errorf("code_size=%#x: initcode keccak diverged from EEST: got %s want %s", | ||
| c.codeSize, got, c.keccak) | ||
| } | ||
| } | ||
| } |
There was a problem hiding this comment.
Upstream EELS emits PUSH1 where this code emits PUSH2
So the pinned hashes for 0x41 and 0x100 in this test cannot be reproduced from an upstream checkout today, despite the test comment's "Regenerate from an execution-specs checkout" instructions.
Sizes in (0x100, 0x1000000] happen to agree because minimal and fixed widths coincide there; max_same/max_diff match upstream master at all in-range sizes already, since StopJumpdestInitcode has no jump target.)
| Both `create2_deploys` and `create_preimage_deploys` accept an | ||
| optional `code_pattern:` parameter that opts into a named generator | ||
| producing per-derived-address byte-unique runtime. `code_pattern:` is | ||
| **mutually exclusive** with literal `runtime:` (and, on | ||
| `create2_deploys`, also with `initcode:`) — the pattern owns both. |
There was a problem hiding this comment.
"Both create2_deploys and create_preimage_deploys accept an optional code_pattern:" — it's three templates now.
I have to verify this, the address encoded here starts at Regarding PUSH1/PUSH2, we should ensure the produced code matches whatever a live network produces, so will fix this. We could also just ban sizes below 256, I think the interesting use cases are the Osaka size, the Amsterdam size, the empty contract, and maybe small unique contracts (64 bytes). Thanks for the review @CPerezz 😄 👍 Will address ASAP. |
Adds the templates which EELS introduced but which (size parameters) are missing here:
(ref: https://github.com/ethereum/execution-specs/blob/5fa5938b1ce01c661b3e9beaa403e4edddd11e1a/tests/benchmark/helper/account_creator.py#L303-L316)
In particular, the code size of the template can now be edited. Supports up to ~16MiB of contract size.
EELS might need: jochem-brouwer/execution-specs#4