Skip to content

fix(l1): charge EIP-8141 intrinsic gas over payload bytes only - #7044

Closed
AnkushinDaniil wants to merge 1 commit into
lambdaclass:frames-devnet-0from
AnkushinDaniil:daniil/eip8141-intrinsic-payload-bytes
Closed

fix(l1): charge EIP-8141 intrinsic gas over payload bytes only#7044
AnkushinDaniil wants to merge 1 commit into
lambdaclass:frames-devnet-0from
AnkushinDaniil:daniil/eip8141-intrinsic-payload-bytes

Conversation

@AnkushinDaniil

@AnkushinDaniil AnkushinDaniil commented Jul 28, 2026

Copy link
Copy Markdown

Problem

EIP-8141 (Gas accounting) defines the calldata component of a frame transaction's intrinsic gas over the payload byte strings only:

frame_data_cost = sum(calldata_cost(frame.data) for frame in tx.frames)
signature_data_cost = sum(
    calldata_cost(sig.signer) + calldata_cost(sig.msg) + calldata_cost(sig.signature)
    for sig in tx.signatures)

with calldata_cost per standard EIP-7623 rules (4 per zero byte, 16 per nonzero byte).

FrameTransaction::total_gas_limit instead RLP-encoded the whole frames and signatures lists and charged calldata gas over every byte of the encoding, including RLP length prefixes and structural fields (gas_limit, value, to, mode, flags, scheme). That over-charges every frame transaction. In devnet interop replay against Nethermind, the 162-byte reference type-0x06 transaction came out at intrinsic 20662 in ethrex vs the spec value 19778 (delta 884), which makes ethrex reject exact-gas blocks other clients accept.

Change

Replace whole-RLP charging with per-field charging over the payload byte arrays (frame.data, and each signature's signer, msg, signature), keeping saturating arithmetic. Adds regression tests that pin the reference transaction's exact intrinsic gas and assert the intrinsic cost is insensitive to structural frame fields (gas_limit, value).

Evidence

Commands run on this branch:

cargo check -p ethrex-common                                # pass
cargo check -p ethrex-levm                                  # pass
cargo test -p ethrex-test --test ethrex_tests levm::eip8141_tests
# 77 passed; 0 failed; 0 ignored; 751 filtered out
cargo fmt --all -- --check                                  # pass
git diff --check                                            # pass

Stack

Targets frames-devnet-0. Part of a series of independent EIP-8141 fixes, one PR per logical change, each standing alone against the same base. Siblings: #7040 (canonical low-s), #7043 (recovery id at ecrecover boundary), #7045 (arbitrary-scheme verification gas), #7046 (frame gas refunds), #7047 (frame receipt storage encoding), #7048 (skipped-frame status 2), #7049 (EIP-7623 calldata floor).

Consensus risk / limits

Consensus-affecting: it lowers intrinsic gas for every frame transaction, changing gas accounting and block validity. Covered by unit tests pinning the reference vector; no cross-client conformance fixture yet.

FrameTransaction::total_gas_limit previously RLP-encoded the whole
frames and signatures lists and charged calldata gas over every byte,
including RLP length prefixes and structural fields (frame gas_limit,
value, to, etc.). EIP-8141 defines the intrinsic calldata cost over the
payload byte-set only: each frame's data plus each signature's signer,
msg, and signature bytes.

This over-charging surfaced in cross-client interop replay against
Nethermind: for the reference 162-byte low-s type-0x06 transaction ethrex
computed intrinsic 20662 vs the spec-correct 19778 (delta 884), causing
exact-gas block rejection.

Replace whole-RLP charging with per-field charging over the payload byte
arrays, preserving saturating arithmetic. Add regression tests pinning
the exact reference-tx intrinsic and asserting insensitivity to
structural frame fields (gas_limit, value).

Verified: 2/2 focused, 80/80 EIP-8141 regression, cargo fmt --check,
cargo clippy -D warnings, git diff --check.
@AnkushinDaniil
AnkushinDaniil force-pushed the daniil/eip8141-intrinsic-payload-bytes branch from 176d0a9 to e8b361c Compare July 29, 2026 06:12
@AnkushinDaniil AnkushinDaniil changed the title fix(common): charge EIP-8141 intrinsic gas over payload bytes only fix(l1): charge EIP-8141 intrinsic gas over payload bytes only Jul 29, 2026
@edg-l edg-l added the hegota label Jul 29, 2026
@edg-l

edg-l commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Superseded by #7004, which changed the calldata charge to data_fields() over frame.data plus each signature's signer/msg/signature, dropping the RLP framing. That is what this PR set out to do.

Worth salvaging though: main has no intrinsic-gas-accounting tests, so the intrinsic_gas_accounting_tests module here is still useful coverage over code main already has. A tests-only PR against current main would be welcome. Closing the implementation half.

@edg-l edg-l closed this Jul 29, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants