Skip to content

Conversation

@LouisTsai-Csie
Copy link
Collaborator

@LouisTsai-Csie LouisTsai-Csie commented Nov 11, 2025

🗒️ Description

Unify the gas cost variable name from Cancun to Osaka. Introduce a fork-dependent gas table.

The mapping for the EELS & EEST gas constant, I replace all the EEST variable name with the EELS naming, as this requires less effort. This documents the mapping: https://hackmd.io/@QmVpC8TxQ8a1nTCW46EsEQ/B1932RWy-x

Note: This PR is only a prototype and will be split into smaller PRs.

🔗 Related Issues or PRs

Issue #1599

✅ Checklist

  • All: Ran fast tox checks to avoid unnecessary CI fails, see also Code Standards and Enabling Pre-commit Checks:
    uvx tox -e static
  • All: PR title adheres to the repo standard - it will be used as the squash commit message and should start type(scope):.
  • All: Considered adding an entry to CHANGELOG.md.
  • All: Considered updating the online docs in the ./docs/ directory.
  • All: Set appropriate labels for the changes (only maintainers can apply labels).
  • Tests: Ran mkdocs serve locally and verified the auto-generated docs for new tests in the Test Case Reference are correctly formatted.
  • Tests: For PRs implementing a missed test case, update the post-mortem document to add an entry the list.
  • Ported Tests: All converted JSON/YML tests from ethereum/tests or tests/static have been assigned @ported_from marker.

Cute Animal Picture

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

Comment on lines +198 to +208
def test_fork_consistency() -> None:
"""Test that Prague and Osaka have same base costs for common opcodes."""
code = Op.PUSH1(0x01) + Op.PUSH1(0x02) + Op.ADD

prague_calc = OpcodeGasCalculator(Prague)
osaka_calc = OpcodeGasCalculator(Osaka)

prague_gas = prague_calc.calculate(code)
osaka_gas = osaka_calc.calculate(code)

assert prague_gas == osaka_gas == 9 # 3 + 3 + 3
Copy link
Collaborator Author

@LouisTsai-Csie LouisTsai-Csie Nov 11, 2025

Choose a reason for hiding this comment

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

This is the example usage:

code = Op.PUSH0 + Op.PUSH0 + Op.ADD
prague_calc = OpcodeGasCalculator(Prague)
prague_gas = prague_calc.calculate(code)
# the total gas cost for the code sequnece

This could be extended to:

code = Op.PUSH0 + Op.PUSH0 + Op.ADD
calc = OpcodeGasCalculator(fork)
gas =calc.calculate(code)

This version could help us avoid hardcoding the gas cost. As i believe in the near future there would be gas repricing for ZkVM, and we do not want to update all the gas cost again.

@spencer-tb spencer-tb self-requested a review November 11, 2025 14:59
@LouisTsai-Csie LouisTsai-Csie self-assigned this Nov 11, 2025
@LouisTsai-Csie LouisTsai-Csie added C-enhance Category: an improvement or new feature S-needs-discussion Status: needs discussion labels Nov 11, 2025
Comment on lines +2372 to +2375
@classmethod
def op_cost(
cls, opcode: Opcodes, *, block_number: int = 0, timestamp: int = 0
) -> int:
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

We need to define this op_cost function for every fork to enable fork-dependent gas table feature.

@codecov-commenter
Copy link

⚠️ Please install the 'codecov app svg image' to ensure uploads and comments are reliably processed by Codecov.

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 86.14%. Comparing base (9563a51) to head (0f2fdd7).
⚠️ Report is 21 commits behind head on forks/osaka.
❗ Your organization needs to install the Codecov GitHub app to enable full functionality.

Additional details and impacted files
@@               Coverage Diff               @@
##           forks/osaka    #1776      +/-   ##
===============================================
+ Coverage        86.07%   86.14%   +0.07%     
===============================================
  Files              743      743              
  Lines            44078    44261     +183     
  Branches          3894     3891       -3     
===============================================
+ Hits             37938    38127     +189     
+ Misses            5659     5656       -3     
+ Partials           481      478       -3     
Flag Coverage Δ
unittests 86.14% <100.00%> (+0.07%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@SamWilsn
Copy link
Contributor

🇺🇸

G_TX_DATA_ZERO = 4
G_TX_DATA_NON_ZERO = 16

# Transaction costs (from transactions.py)
Copy link
Contributor

Choose a reason for hiding this comment

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

Comments should describe the current state of the code. The git log gives us historical context.

Comment on lines +88 to +89
G_TX_DATA_ZERO = 4
G_TX_DATA_NON_ZERO = 16
Copy link
Contributor

Choose a reason for hiding this comment

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

Should these be typed?

Comment on lines +100 to +101
PER_EMPTY_ACCOUNT_COST = 25_000
PER_AUTH_BASE_COST = 12_500
Copy link
Contributor

Choose a reason for hiding this comment

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

Should these be typed?

PER_AUTH_BASE_COST = 12_500

# Opcode Costs
G_STOP = GAS_ZERO
Copy link
Contributor

Choose a reason for hiding this comment

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

We try to avoid abbreviations unless they are extremely common (eg. tx -> transaction). I'm not firmly opposed to g -> gas, but I did want to mention it.

Copy link
Contributor

Choose a reason for hiding this comment

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

I think at the very least we would want to document that so it's clear. I'm not sure that saving two characters is worth the loss in readability though.

G_SMOD = GAS_LOW
G_ADDMOD = GAS_MID
G_MULMOD = GAS_MID
G_EXP = GAS_EXPONENTIATION
Copy link
Contributor

Choose a reason for hiding this comment

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

Might be worth adding a docstring to each of these constants that explains the difference?

Copy link
Contributor

Choose a reason for hiding this comment

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

I count 7 of these, so it wouldn't be a huge addition to document each. If we do end up reorganizing this list into groups by gas cost, then these would all be in one block which would make for easy reading.

G_SHR = GAS_VERY_LOW
G_SAR = GAS_VERY_LOW
G_CLZ = GAS_LOW
G_KECCAK256 = GAS_KECCAK256
Copy link
Contributor

Choose a reason for hiding this comment

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

Same comment here about explaining the difference.

G_CLZ = GAS_LOW
G_KECCAK256 = GAS_KECCAK256
G_ADDRESS = GAS_BASE
G_BALANCE = GAS_WARM_ACCESS # or GAS_COLD_ACCOUNT_ACCESS if cold
Copy link
Contributor

Choose a reason for hiding this comment

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

Hm, I'm not sold on this. If the price of an opcode is dynamic, should the associated gas constant have a different naming scheme? Like G_BASE_BALANCE or G_MIN_BALANCE? I'm just musing here, a change is not necessarily required.

Comment on lines +175 to +178
G_PUSHx = GAS_VERY_LOW
G_DUPx = GAS_VERY_LOW
G_SWAPx = GAS_VERY_LOW
G_LOGx = GAS_LOG
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
G_PUSHx = GAS_VERY_LOW
G_DUPx = GAS_VERY_LOW
G_SWAPx = GAS_VERY_LOW
G_LOGx = GAS_LOG
G_PUSH = GAS_VERY_LOW
G_DUP = GAS_VERY_LOW
G_SWAP = GAS_VERY_LOW
G_LOG = GAS_LOG

The lowercase "x" is unusual in Python constants.

Comment on lines +92 to +97
TX_BASE_COST = Uint(21_000)
TX_CREATE_COST = Uint(32_000)
TX_ACCESS_LIST_ADDRESS_COST = Uint(2_400)
TX_ACCESS_LIST_STORAGE_KEY_COST = Uint(1_900)
STANDARD_CALLDATA_TOKEN_COST = Uint(4)
FLOOR_CALLDATA_COST = Uint(10)
Copy link
Contributor

Choose a reason for hiding this comment

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

IIUC, these constants are not used by anything under the ethereum.forks.osaka.vm package, right? It seems odd that they live in here if they aren't related to the virtual machine itself.

Copy link
Contributor

@Carsons-Eels Carsons-Eels left a comment

Choose a reason for hiding this comment

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

I'm not sure that I like mixing the use of the "G" and "GAS" prefixes (G_OPCODE vs GAS_OPCODE) in the codebase. If I understand correctly, the intent is to use "G" in the EELS part of the code and "GAS" in the EEST part of the code? In my mind that should be reversed, because a IMO higher priority should be placed on the how readable the spec is. Should we maybe consider simply aligning the naming of them all?

I'll keep looking this over in the morning, this is great stuff 🚀

STANDARD_CALLDATA_TOKEN_COST = Uint(4)
FLOOR_CALLDATA_COST = Uint(10)

# Authorization costs (from eoa_delegation.py)
Copy link
Contributor

Choose a reason for hiding this comment

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

Same as here, the "(from eoa_delegation.py)" is probably not required.

PER_EMPTY_ACCOUNT_COST = 25_000
PER_AUTH_BASE_COST = 12_500

# Opcode Costs
Copy link
Contributor

Choose a reason for hiding this comment

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

Right now these are in order of their opcode number, but the opcode numbers are not listed so it's not easy to reference them in that way. I'm wondering if there is a better way to organize this. Maybe by common cost?

PER_AUTH_BASE_COST = 12_500

# Opcode Costs
G_STOP = GAS_ZERO
Copy link
Contributor

Choose a reason for hiding this comment

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

I think at the very least we would want to document that so it's clear. I'm not sure that saving two characters is worth the loss in readability though.

G_SMOD = GAS_LOW
G_ADDMOD = GAS_MID
G_MULMOD = GAS_MID
G_EXP = GAS_EXPONENTIATION
Copy link
Contributor

Choose a reason for hiding this comment

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

I count 7 of these, so it wouldn't be a huge addition to document each. If we do end up reorganizing this list into groups by gas cost, then these would all be in one block which would make for easy reading.

Comment on lines +2365 to +2370
kwargs = {}
for field in fields(GasCosts):
if hasattr(g, field.name):
kwargs[field.name] = int(getattr(g, field.name))

return GasCosts(**kwargs)
Copy link
Contributor

Choose a reason for hiding this comment

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

Should we return an error here if the field is not found rather than skipping it silently? Not sure if this is intended.

G_SIGNEXTEND,
G_SMOD,
G_SUB,
GAS_EXPONENTIATION_PER_BYTE,
Copy link
Contributor

Choose a reason for hiding this comment

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

Why does this one keep it's GAS_ prefix rather than aligning with the others?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

C-enhance Category: an improvement or new feature S-needs-discussion Status: needs discussion

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants