feat(test): add fast gas repricing and gas-map CLI tool#2331
feat(test): add fast gas repricing and gas-map CLI tool#2331Carsons-Eels wants to merge 12 commits intoethereum:forks/amsterdamfrom
Conversation
|
Amazing! Link related issue #1879 . |
|
There is a problem using this tool for repricing testing: eip-7904 reprices opcodes that currently share a Example: The repricing config operates at the I would suggest the {
"amsterdam": {
"DUP": 1000,
"SSTORE": 5000
},
"osaka": {
"CALL": 800
}
} |
97be373 to
73b88e3
Compare
We would need an intermediate mapping in each fork: GAS_LOW = 5
...
GAS_OPCODE_DIV = GAS_LOW
GAS_OPCODE_SDIV = GAS_LOW
GAS_OPCODE_MOD = GAS_LOWOnly then we would be able to target specific opcode prices with this tool. It feels necessary too, I don't think we plan on affecting other Opcodes when repricing only because they use the same constant predecessor. Should we open a precursor PR to create these new variables? |
|
I ran into this issue headfirst while implementing, and my decision at the time was to implement a simpler version that dealt only with the constants just to get the thing up and running. The problems with doing it per-opcode then were:
However, I think I misunderstood that we would not strictly need per-opcode repricing right from the outset, and by that time I was halfway done implementing and wanted to at least reach an island of sanity before planning a refactor. I also wasn't sure that this PR was the place to do that, and thought about kicking that to a different issue because, yeah, as you pointed out @marioevz, this requires a bunch of intermediate mapping that I wasn't sure was appropriate for this PR. I think a precursor PR is the way to go so that this PR has the pieces it needs to implement it properly. I'm happy to do that tomorrow after I fix the 5 test failures in the CI. |
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## forks/amsterdam #2331 +/- ##
===================================================
- Coverage 86.35% 86.32% -0.03%
===================================================
Files 599 600 +1
Lines 36904 36961 +57
Branches 3771 3777 +6
===================================================
+ Hits 31868 31908 +40
- Misses 4485 4500 +15
- Partials 551 553 +2
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
4d1e93b to
b1cbe30
Compare
|
Right now the instruction files from all 24 forks import gas constants using Right now it works because PR #2396 has this fixed for the new I'm wondering if it's the right call to do this here in this PR, or in a separate PR. Mostly because it would bloat the PR another 96 files changed to 134 files which makes the other changes a pain to review. For now, I've made those changes in a separate branch as a PR to myself targeted at PR #2396 |
e758a16 to
2994e8f
Compare
This fixes a CI failure
2994e8f to
dad13e5
Compare
🗒️ Description
Implements gas repricing support for both the EEST test framework and the spec-side execution code, allowing users to override gas constants via a JSON config file without modifying source code. This enables fast iteration on alternative gas schedules, "what-if" analysis of proposed EIP gas changes, and comparative test runs under different cost models.
🔗 Related Issues or PRs
Core Repricing Mechanism
Shared config reader
ethereum.utils.gas_repricing: Loads a JSON config from the path specified by theEELS_GAS_REPRICING_CONFIGenvironment variable. The config maps fork names to field overrides (e.g.,{"Osaka": {"GAS_VERY_LOW": 4}}). Results are cached vialru_cache. Both spec-side and testing-side consumers import this shared reader.Testing-side repricing:
BaseFork.gas_costs()is now concrete — it calls the new abstract_base_gas_costs()to get the fork's default costs, then passes them throughapply_repricing(). Validation (field name + type checks againstGasCostsdataclass) happens at apply time in the testing module. All fork subclasses have been renamed fromgas_costs()to_base_gas_costs()accordingly.Spec-side repricing:
apply_spec_repricing()is called at the bottom of all 24src/ethereum/forks/*/vm/gas.pymodules. It mutates module globals in place, preservingUint/U64type wrappers viatype(original)(value). Validation against the module's actual globals ensures only real constants can be overridden. With no config set, this is a complete no-op..gitignore: Addedgas_repricing.jsonso local config files aren't accidentally committed.Gas Constant Name Unification
Important
Covered in PR #2383 which should be merged BEFORE this PR
Standardized 17 spec-side gas constant names to match the testing-side conventions (e.g.,
GAS_ECRECOVER→GAS_PRECOMPILE_ECRECOVER,GAS_WARM_ACCESS→GAS_WARM_ACCOUNT_ACCESS). This ensures users can use the same field names in their repricing config for both spec and test overrides. ~362 files affected, all withinsrc/ethereum/forks/.✨ CLI Tool
gas-mapInvoke with:
uv run gas-map # or uv run eest gas-mapThe mapping between opcodes (ADD, SLOAD, etc.) and
GasCostsfield names (GAS_LOW, GAS_WARM_SLOAD, etc.) is not obvious without reading source code. Thegas-mapCLI tool bridges this gap:eestsubcommand--fork/-foption (defaults to latest fork)--opcode/-ooption for single-opcode detail viewopcode_gas_map()inheritance chain and helper methods to accurately reverse-map opcodes to theirGasCostsfieldsGAS_MEMORYfor memory-expanding opcodes like REVERT), and shows constantsgas_repricing.jsonsnippet📝 Documentation
docs/gas_repricing/repricing_guide.md: What repricing is, JSON config format, activation via env var,gas-mapCLI usage, and an end-to-end example workflow.docs/gas_repricing/reference.md: Static convenience reference of all ~90GasCostsfields grouped by category, with affected opcodes and typical values.uv run gas-mapis the authoritative source of truth per fork.docs/navigation.md: New "Gas Repricing" nav section added after "Writing Tests".🔬 Tests
test_gas_repricing.py: Full test suite covering:load_repricing_config()(shared reader):apply_repricing()(testing-side):ValueErrorTypeErrorapply_spec_repricing()(spec-side):Uint/U64type wrappersValueErrorFileNotFoundErrorFORK.gas_costs()returns repriced valuesautousefixtureNote
ethereum-spec-lintwarnings: Theapply_spec_repricing()calls at the bottom of eachgas.pyproduce 8 "The expression <class 'ast.Expr'> has been ignored." print messages from theGlacierForksHygienelint. These are informational prints (not diagnostic errors) — the lint compares glacier forks against predecessors and doesn't have a visitor forast.Callexpressions. The warnings are harmless and do not cause lint failure. We could update the linter to ignore this, but I didn't want to go changing the linter in this PR.reference.mdmaintenance: The static tables inreference.mdare a convenience reference.uv run gas-mapis the authoritative per-fork source. A CI freshness check could be added in the future.✅ Checklist
toxchecks to avoid unnecessary CI fails, see also Code Standards and Enabling Pre-commit Checks:uvx tox -e statictype(scope):.mkdocs build --strictlocally and verified docs render correctly.Cute Animal Picture
Bobcat by Jean Beaufort
License: CC0 Public Domain