Skip to content

feat: Amsterdam hard fork — EIP-7825 tx gas cap and EIP-7702 authorization gas repricing#317

Open
SegueII wants to merge 8 commits into
mainfrom
eezo-shunt-sync-consensus
Open

feat: Amsterdam hard fork — EIP-7825 tx gas cap and EIP-7702 authorization gas repricing#317
SegueII wants to merge 8 commits into
mainfrom
eezo-shunt-sync-consensus

Conversation

@SegueII

@SegueII SegueII commented Apr 20, 2026

Copy link
Copy Markdown
Contributor

Summary by CodeRabbit

Summary by CodeRabbit

  • New Features

    • Added timestamp-activated Amsterdam fork support.
    • CLI transaction tooling now supports environment-file input via --input.env.
  • Behavior Changes

    • Enforced the post-Amsterdam per-transaction gas cap (MaxTxGas) across transaction validation/pooling and execution.
    • Updated EVM intrinsic/authorization gas rules for Amsterdam.
    • Gas estimation now uses the block header gas limit and applies the post-Amsterdam cap.
  • Bug Fixes

    • Light client now returns a live trie database instead of nil.
  • Tests

    • Expanded Amsterdam and env-input test coverage with updated fixtures/expectations.

Close: #341

SegueII added 2 commits April 17, 2026 13:14
Consensus change — off by default on all chain configs.

Motivation
----------
EIP-7702 per-auth intrinsic pricing in morph (and current upstream
go-ethereum) follows the official spec: charge `CallNewAccountGas`
(25000) per authorization up front, then refund
`CallNewAccountGas - TxAuthTupleGas` (12500) via `StateDB.refund` when
the authority account already exists in state. That refund shares the
single StateDB refund counter with SSTORE refunds and is capped at
`gasUsed/5` by `refundGas`. A transaction that declares many
authorizations all pointing at existing accounts can therefore have its
refund truncated, leading users to pay materially more gas than the EIP
intent. See .vscode/Eezo_Shunt_Final.md and .vscode/Eezo_Shunt_Spec.md
for the full write-up and worked example.

Design
------
The fix is a consensus-layer change and is strictly gated behind a new
time-based fork tentatively named Amsterdam. All existing chain configs
(Mainnet / Hoodi / Holesky / AllEthashProtocolChanges / TestChainConfig
/ …) leave `AmsterdamTime` nil, so this commit ships *without* altering
live behavior — the fork must be activated explicitly in a later chain
config update.

Pre-Amsterdam path (unchanged):
  - `IntrinsicGas` charges `CallNewAccountGas` per authorization.
  - `applyAuthorization` calls `AddRefund(12500)` when the authority
    already exists. Historical blocks remain reproducible.

Post-Amsterdam path:
  - `IntrinsicGas` charges only `TxAuthTupleGas` per authorization.
  - `applyAuthorization` debits `CallNewAccountGas - TxAuthTupleGas`
    directly from `st.gas` when the authority does not exist. This
    bypasses the StateDB refund counter entirely and is therefore
    immune to the `gasUsed/5` cap.
  - When remaining `st.gas` is below the delta, the authorization is
    skipped (no nonce bump, no delegation install) rather than
    triggering an OutOfGas; this mirrors the existing "validation
    errors silently skip the auth" contract in the TransitionDb loop
    ("errors are ignored, we simply skip invalid authorizations here")
    and prevents a partial debit from corrupting the subsequent EVM
    call's gas budget. A dedicated sentinel error
    `ErrInsufficientAuthorizationGas` makes the decision observable in
    tests.

Fork infrastructure
-------------------
  - `params/forks/forks.go`: add `JadeFork` and `Amsterdam` to the
    enum (JadeFork was previously missing — fill while at it).
  - `params/config.go`:
      * new `ChainConfig.AmsterdamTime` field, `IsAmsterdam(time)`
        predicate, and `Rules.IsAmsterdam`.
      * `CheckConfigForkOrder` / `CheckCompatible` entries.
      * `LatestFork` and `Timestamp` updated; JadeFork backfilled.
      * `String()` prints the new field.

Call-site propagation
---------------------
  - `IntrinsicGas` gains a trailing `isAmsterdam bool` argument. All
    six call sites updated:
      core/state_transition.go (TransitionDb),
      core/tx_pool.go (validateTx, new `amsterdam` fork indicator),
      light/txpool.go (new `amsterdam` fork indicator),
      tests/transaction_test_util.go,
      cmd/evm/internal/t8ntool/transaction.go (t8n has block-number
        context only and keeps the flag false, matching upstream t8n
        semantics),
      core/bench_test.go.
  - `applyAuthorization` gains `isAmsterdam bool`; the single caller
    inside `TransitionDb` passes `rules.IsAmsterdam`.

Tests
-----
`core/state_transition_test.go` (new):
  - `TestIntrinsicGas` — table-driven, covers zero/one/many auth
    scenarios both pre- and post-Amsterdam, plus AccessList interaction.
  - `TestIntrinsicGasAuthListScalingPreVsPost` — asserts the exact
    pre-vs-post-fork delta for N authorizations.
  - `TestApplyAuthorizationPreFork{Refund,NoRefund}` — refund-counter
    behavior for the legacy path.
  - `TestApplyAuthorizationPostFork{Charge,NoCharge,Skip,Boundary}` —
    st.gas debit behavior, including the exact-boundary and
    insufficient-gas edge cases.
  - `TestApplyAuthorizationInvalidSignatureSkipped` — verifies the
    "validation error → skip" contract still wins over the new gas
    accounting under both forks.

`params/config_test.go` (extended):
  - `TestIsAmsterdam` — nil / future / at-activation / past / genesis.
  - `TestLatestForkIncludesJadeForkAndAmsterdam` — asserts the
    correct ordering including the JadeFork backfill.
  - `TestTimestampForkLookup` — round-trips every time-based fork.
  - `TestCheckCompatibleAmsterdamTimestamp` — rejects an incompatible
    reschedule when the head is past the stored activation.
  - `TestAmsterdamForkOrdering` — enforces the Amsterdam-after-JadeFork
    ordering in `CheckConfigForkOrder`.

Made-with: Cursor
Consensus change — off by default on all chain configs.

Motivation
----------
EIP-7825 introduces a protocol-level cap of 2^24 (16_777_216) gas on
any single transaction, as an additional DoS mitigation that keeps
individual transactions well within the zkEVM circuit budget. morph
does not yet implement this limit; this commit adds the constant and
the preCheck enforcement, strictly gated on the Amsterdam fork added
in the preceding P1-3 commit.

Design
------
`params.MaxTxGas` is unconditionally defined so tooling (gas
estimators, RPC, block builders) can reference it. The enforcement
lives in `core/state_transition.go::preCheck` inside the existing
`!st.msg.IsFake()` block:

  - L1MessageTx transactions already take the early-return branch at
    the top of preCheck and are therefore naturally exempt (matches
    the spec's "L1 message transactions are excluded").
  - Simulation / eth_call transactions (`IsFake() == true`) skip the
    enforcement block entirely, matching upstream's
    `SkipTransactionChecks` semantics.
  - All other transactions, once Amsterdam is active, must have
    `msg.Gas() <= params.MaxTxGas`. The check precedes the nonce
    and EOA lookups and the balance check, so a malformed oversized
    transaction is rejected cheaply.

All existing chain configs leave `AmsterdamTime` nil, so this check
is a no-op on Holesky / Hoodi / Mainnet until the fork is activated
in chain configuration.

A new sentinel `core.ErrGasLimitTooHigh` makes the rejection
observable and matches the upstream go-ethereum error name.

Tests
-----
`core/state_transition_test.go` adds six direct preCheck tests,
covering every scenario called out in the Eezo Shunt spec
acceptance criteria:

  - `TestPreCheckMaxTxGasPreAmsterdamIgnoresCap` — confirms the
    check is fork-gated (pre-Amsterdam must not return
    ErrGasLimitTooHigh even for gas limits far above MaxTxGas).
  - `TestPreCheckMaxTxGasPostAmsterdamRejectsAboveCap` —
    `gas = MaxTxGas + 1` is rejected.
  - `TestPreCheckMaxTxGasPostAmsterdamAcceptsAtCap` —
    `gas = MaxTxGas` is accepted (predicate is strict `>`).
  - `TestPreCheckMaxTxGasPostAmsterdamAcceptsBelowCap` —
    `gas = MaxTxGas - 1` is accepted.
  - `TestPreCheckMaxTxGasFakeExempt` — `IsFake()` transactions
    bypass the cap.
  - `TestPreCheckMaxTxGasL1Exempt` — a real `L1MessageTx` built via
    `types.NewTx(&types.L1MessageTx{...}).AsMessage(...)` hits the
    early-return branch and is unaffected.

Made-with: Cursor
@SegueII SegueII requested a review from a team as a code owner April 20, 2026 07:27
@SegueII SegueII requested review from twcctop and removed request for a team April 20, 2026 07:27
@coderabbitai

coderabbitai Bot commented Apr 20, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Adds Amsterdam fork activation, a per-transaction gas cap, and fork-aware intrinsic-gas and authorization accounting across core execution, tx pools, RPC, CLI, and tests.

Changes

Amsterdam fork rollout

Layer / File(s) Summary
Fork config and compatibility
params/config.go, params/forks/forks.go, params/protocol_params.go, params/config_test.go, tests/init.go
Adds AmsterdamTime, IsAmsterdam, Rules.IsAmsterdam, Amsterdam fork ordering/compatibility handling, fork enum entries, and params.MaxTxGas, with tests and fork fixtures.
Core execution and enforcement
core/error.go, core/state_transition.go, core/state_transition_test.go, core/tx_pool.go, core/tx_pool_test.go, light/txpool.go, light/txpool_test.go, core/bench_test.go
Updates intrinsic gas and authorization gas handling for Amsterdam, adds ErrGasLimitTooHigh and ErrInsufficientAuthorizationGas, enforces the gas cap in state transition and tx pools, and covers the new behavior with tests.
RPC, CLI, and test wiring
internal/ethapi/api.go, internal/ethapi/api_morph_test.go, cmd/evm/main.go, cmd/evm/internal/t8ntool/transaction.go, cmd/evm/testdata/24/*, cmd/evm/t8n_test.go, tests/state_test_util.go, tests/transaction_test_util.go
Makes gas estimation and access-list pricing Amsterdam-aware, adds --input.env handling to t8n/t9n, and updates supporting fixtures and test utilities.
Light trie database
light/trie.go
Returns a live trie database from TrieDB() instead of nil.

Estimated code review effort: 4 (Complex) | ~70 minutes

Possibly related PRs

Suggested reviewers: panos-xyz, tomatoishealthy, curryxbo

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning The diff includes an unrelated light/trie.go behavior change that makes TrieDB return a live database, outside the Amsterdam gas/fork scope. Move the TrieDB change to a separate PR or explain why it is required for the Amsterdam work.
Docstring Coverage ⚠️ Warning Docstring coverage is 37.50% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Linked Issues check ✅ Passed The PR covers the Amsterdam fork gate, EIP-7702 pricing changes, EIP-7825 cap enforcement, RPC/CLI support, and the requested compatibility tests.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: Amsterdam fork work for EIP-7825 gas caps and EIP-7702 gas repricing.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch eezo-shunt-sync-consensus

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

…tion validation

- Introduced `--input.env` flag in the transaction command to allow specifying an environment file.
- Updated the transaction processing logic to read and validate the environment data, particularly for Amsterdam fork scenarios.
- Enhanced test cases to cover new input environment scenarios, ensuring proper handling of oversized gas transactions pre- and post-Amsterdam activation.
- Added new test data files for environment configurations and expected outputs for various transaction scenarios.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
cmd/evm/internal/t8ntool/transaction.go (2)

163-180: ⚠️ Potential issue | 🟡 Minor

Apply the Amsterdam gas-cap check before intrinsic-gas validation.

Production txpool validation rejects gas > params.MaxTxGas before calling IntrinsicGas. Here, an oversized Amsterdam transaction can instead report ErrIntrinsicGas when its intrinsic requirement is also above the supplied gas limit, producing inconsistent t9n results.

🐛 Proposed fix
+		if isAmsterdam && !tx.IsL1MessageTx() && tx.Gas() > params.MaxTxGas {
+			r.Error = fmt.Errorf("%w (cap: %d, tx: %d)", core.ErrGasLimitTooHigh, params.MaxTxGas, tx.Gas())
+			results = append(results, r)
+			continue
+		}
 		if gas, err := core.IntrinsicGas(tx.Data(), tx.AccessList(), tx.SetCodeAuthorizations(), tx.To() == nil,
 			chainConfig.IsHomestead(new(big.Int)), chainConfig.IsIstanbul(new(big.Int)), chainConfig.IsShanghai(new(big.Int)), isAmsterdam); err != nil {
 			r.Error = err
@@
-		if isAmsterdam && !tx.IsL1MessageTx() && tx.Gas() > params.MaxTxGas {
-			r.Error = fmt.Errorf("%w (cap: %d, tx: %d)", core.ErrGasLimitTooHigh, params.MaxTxGas, tx.Gas())
-			results = append(results, r)
-			continue
-		}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@cmd/evm/internal/t8ntool/transaction.go` around lines 163 - 180, Move the
Amsterdam gas-cap check so it runs before calling core.IntrinsicGas: before
invoking core.IntrinsicGas(...) in the transaction loop, check if isAmsterdam &&
!tx.IsL1MessageTx() && tx.Gas() > params.MaxTxGas and, if true, set r.Error to
fmt.Errorf("%w (cap: %d, tx: %d)", core.ErrGasLimitTooHigh, params.MaxTxGas,
tx.Gas()), append r to results and continue; this ensures the params.MaxTxGas
cap is enforced consistently (matching txpool) and prevents oversized txs from
incorrectly surfacing core.ErrIntrinsicGas.

97-120: ⚠️ Potential issue | 🟠 Major

Still load tx RLP when only --input.env is stdin.

With envStr == stdinSelector and txStr pointing to a file, this branch decodes stdin but never opens the tx file, so body stays empty and the command validates no transactions.

🐛 Proposed fix
-	if txStr == stdinSelector || envStr == stdinSelector {
+	if txStr == stdinSelector || envStr == stdinSelector {
 		decoder := json.NewDecoder(os.Stdin)
 		if err := decoder.Decode(inputData); err != nil {
 			return NewError(ErrorJson, fmt.Errorf("failed unmarshaling stdin: %v", err))
 		}
-		if txStr == stdinSelector {
-			// Decode the body of already signed transactions
-			body = common.FromHex(inputData.TxRlp)
-		}
-	} else {
+	}
+	if txStr == stdinSelector {
+		// Decode the body of already signed transactions
+		body = common.FromHex(inputData.TxRlp)
+	} else {
 		// Read input from file
 		inFile, err := os.Open(txStr)
 		if err != nil {
 			return NewError(ErrorIO, fmt.Errorf("failed reading txs file: %v", err))
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@cmd/evm/internal/t8ntool/transaction.go` around lines 97 - 120, When envStr
== stdinSelector the code decodes inputData from stdin but currently omits
opening/decoding txStr when txStr points to a file, leaving body empty; update
the branch that handles stdin (where decoder.Decode(inputData) occurs) so that
after decoding inputData you check if txStr != stdinSelector and then open txStr
(os.Open), create a json.Decoder for that file and decode the RLP body into the
variable body (or return a NewError/ErrorIO on failure), and still keep the
existing handling of txStr == stdinSelector where body =
common.FromHex(inputData.TxRlp); ensure you reference txStr, envStr,
stdinSelector, inputData, body and use os.Open/json.NewDecoder as in the
file-reading branch.
core/tx_pool.go (1)

1497-1587: ⚠️ Potential issue | 🟠 Major

Refresh fork indicators before reinjecting reorged transactions.

pool.addTxsLocked(reinject, false) still validates with the previous pool.amsterdam value. On a reorg from an Amsterdam head back to a pre-Amsterdam head, transactions with gas > params.MaxTxGas are valid again for the new pending context but will be rejected during reinjection.

🐛 Proposed fix
 	// Initialize the internal state to the current head
 	if newHead == nil {
 		newHead = pool.chain.CurrentBlock().Header() // Special case during testing
 	}
@@
 	pool.currentState = statedb
 	pool.pendingNonces = newTxNoncer(statedb)
 	pool.currentMaxGas = newHead.GasLimit
 
+	// Update all fork indicators by next pending block number before
+	// validating reinjected transactions against the new head context.
+	next := new(big.Int).Add(newHead.Number, big.NewInt(1))
+	pool.istanbul = pool.chainconfig.IsIstanbul(next)
+	pool.eip2718 = pool.chainconfig.IsCurie(next)
+	pool.eip1559 = pool.chainconfig.IsCurie(next)
+	pool.shanghai = pool.chainconfig.IsShanghai(next)
+	pool.eip7702 = pool.chainconfig.IsViridian(next, newHead.Time)
+	pool.jade = pool.chainconfig.IsJadeFork(newHead.Time)
+	pool.amsterdam = pool.chainconfig.IsAmsterdam(newHead.Time)
+	pool.currentHead = next
+
 	// Inject any transactions discarded due to reorgs
 	log.Debug("Reinjecting stale transactions", "count", len(reinject))
 	senderCacher.recover(pool.signer, reinject)
 	pool.addTxsLocked(reinject, false)
 
-	// Update all fork indicator by next pending block number.
-	next := new(big.Int).Add(newHead.Number, big.NewInt(1))
-	pool.istanbul = pool.chainconfig.IsIstanbul(next)
-
-	pool.eip2718 = pool.chainconfig.IsCurie(next)
-	pool.eip1559 = pool.chainconfig.IsCurie(next)
-	pool.shanghai = pool.chainconfig.IsShanghai(next)
-	pool.eip7702 = pool.chainconfig.IsViridian(next, newHead.Time)
-	pool.jade = pool.chainconfig.IsJadeFork(newHead.Time)
-	pool.amsterdam = pool.chainconfig.IsAmsterdam(newHead.Time)
-
 	// Remove MorphTx V1 transactions if jade fork is not active (e.g. after reorg)
 	if !pool.jade {
 		pool.removeMorphTxV1()
 	}
@@
-
-	// Update current head
-	pool.currentHead = next
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@core/tx_pool.go` around lines 1497 - 1587, Reinjecting stale transactions
uses the old fork flags (pool.amsterdam, pool.eip1559, eip2718, shanghai,
eip7702, jade) so addTxsLocked(reinject, false) may reject txs that are valid
under the new head; move the block that updates fork indicators (the
pool.istanbul / pool.eip2718 / pool.eip1559 / pool.shanghai / pool.eip7702 /
pool.jade / pool.amsterdam assignments that call pool.chainconfig.Is* with
next/newHead.Time) to occur before calling senderCacher.recover(...) and
pool.addTxsLocked(reinject, false) so reinjection validates against the correct
fork rules for newHead while keeping pool.currentState and pendingNonces
initialization as-is.
🧹 Nitpick comments (1)
params/config_test.go (1)

262-266: Consider asserting the Amsterdam rewind target too.

This compatibility error drives rollback behavior, so checking RewindToTime would make the Amsterdam-specific test match the existing timestamp compatibility coverage.

🧪 Proposed test assertion
 	require.Equal(t, "AmsterdamTime fork timestamp", err.What)
 	require.Equal(t, NewUint64(100), err.StoredTime)
 	require.Equal(t, NewUint64(200), err.NewTime)
+	require.Equal(t, NewUint64(99), err.RewindToTime)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@params/config_test.go` around lines 262 - 266, The test currently asserts the
compatibility error's What, StoredTime and NewTime after calling
stored.CheckCompatible(newer, 0, 150) but does not assert the Amsterdam rewind
target; add an assertion that err.RewindToTime equals NewUint64(150) so the
Amsterdam-specific behavior is covered (referencing the CheckCompatible call and
the err.RewindToTime field).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@core/tx_pool_test.go`:
- Around line 247-258: The helper txPoolNextHead can panic because it
dereferences parent.Hash() and parent.GasLimit even when parent is nil; update
txPoolNextHead to first handle a nil parent by providing safe defaults (e.g.,
nil ParentHash, zero GasLimit and a Number of 1) and only call parent.Hash(),
parent.GasLimit and parent.Number when parent != nil; ensure the returned Header
uses these safe defaults and preserves the existing increment logic for
parent.Number when parent is non-nil.

In `@light/trie.go`:
- Around line 92-94: odrDatabase.TrieDB() was changed to always return a fresh
*trie.Database (via trie.NewDatabase(db.backend.Database())) instead of nil, so
callers that rely on a nil sentinel (e.g., the nil check around the trie
returned in the tracer/state access paths) must be updated: remove or adapt the
nil-checks and use the returned trie.Database directly (or, if you prefer
preserving old semantics, change odrDatabase.TrieDB to return nil when
db.backend.Database() is nil). Locate odrDatabase.TrieDB and the callers that
check for nil (e.g., tracer/state accessor code that checks the trie result) and
either delete the dead nil-branch and proceed with the returned trie.Database,
or implement the conditional nil-return in odrDatabase.TrieDB to restore
previous behavior.

In `@light/txpool.go`:
- Around line 515-530: The dropOversizedAmsterdamTxs function currently deletes
entries from pool.pending and the DB but leaves per-sender nonce state stale in
pool.nonce/nonce-tracking, causing GetNonce to return removedNonce+1; update
dropOversizedAmsterdamTxs to collect the senders (tx.From or tx.Sender) of all
removed txs, then for each affected sender recompute their pending nonce by
scanning remaining pool.pending for the highest nonce (or clear the sender entry
if none remain), and if you detect remaining pending txs with nonces higher than
the recomputed lowest missing nonce, also remove those higher nonces to preserve
the “no queued transactions” invariant; finally still call batch.Write() and
pool.relay.Discard(hashes) as before. Ensure you reference
dropOversizedAmsterdamTxs, pool.pending, pool.nonce (or the nonce map used), and
pool.relay.Discard when making changes.

In `@tests/init.go`:
- Around line 235-254: The Amsterdam test config (map key "Amsterdam") sets
AmsterdamTime but omits predecessor timestamp forks, causing inconsistent fork
activation; update the Amsterdam entry to populate the missing timestamp fields
(Morph203Time, ViridianTime, EmeraldTime, JadeForkTime) using the same pattern
as other test configs (e.g., params.NewUint64(<value>)) so all predecessor
timestamp forks are activated before AmsterdamTime; edit the struct where
AmsterdamTime is set to add these fields with appropriate NewUint64 values
consistent with other test definitions.

---

Outside diff comments:
In `@cmd/evm/internal/t8ntool/transaction.go`:
- Around line 163-180: Move the Amsterdam gas-cap check so it runs before
calling core.IntrinsicGas: before invoking core.IntrinsicGas(...) in the
transaction loop, check if isAmsterdam && !tx.IsL1MessageTx() && tx.Gas() >
params.MaxTxGas and, if true, set r.Error to fmt.Errorf("%w (cap: %d, tx: %d)",
core.ErrGasLimitTooHigh, params.MaxTxGas, tx.Gas()), append r to results and
continue; this ensures the params.MaxTxGas cap is enforced consistently
(matching txpool) and prevents oversized txs from incorrectly surfacing
core.ErrIntrinsicGas.
- Around line 97-120: When envStr == stdinSelector the code decodes inputData
from stdin but currently omits opening/decoding txStr when txStr points to a
file, leaving body empty; update the branch that handles stdin (where
decoder.Decode(inputData) occurs) so that after decoding inputData you check if
txStr != stdinSelector and then open txStr (os.Open), create a json.Decoder for
that file and decode the RLP body into the variable body (or return a
NewError/ErrorIO on failure), and still keep the existing handling of txStr ==
stdinSelector where body = common.FromHex(inputData.TxRlp); ensure you reference
txStr, envStr, stdinSelector, inputData, body and use os.Open/json.NewDecoder as
in the file-reading branch.

In `@core/tx_pool.go`:
- Around line 1497-1587: Reinjecting stale transactions uses the old fork flags
(pool.amsterdam, pool.eip1559, eip2718, shanghai, eip7702, jade) so
addTxsLocked(reinject, false) may reject txs that are valid under the new head;
move the block that updates fork indicators (the pool.istanbul / pool.eip2718 /
pool.eip1559 / pool.shanghai / pool.eip7702 / pool.jade / pool.amsterdam
assignments that call pool.chainconfig.Is* with next/newHead.Time) to occur
before calling senderCacher.recover(...) and pool.addTxsLocked(reinject, false)
so reinjection validates against the correct fork rules for newHead while
keeping pool.currentState and pendingNonces initialization as-is.

---

Nitpick comments:
In `@params/config_test.go`:
- Around line 262-266: The test currently asserts the compatibility error's
What, StoredTime and NewTime after calling stored.CheckCompatible(newer, 0, 150)
but does not assert the Amsterdam rewind target; add an assertion that
err.RewindToTime equals NewUint64(150) so the Amsterdam-specific behavior is
covered (referencing the CheckCompatible call and the err.RewindToTime field).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 0a08e4f3-bc32-4fd6-ab78-c739331aaf58

📥 Commits

Reviewing files that changed from the base of the PR and between 87ecf43 and d1a6b11.

📒 Files selected for processing (26)
  • cmd/evm/internal/t8ntool/transaction.go
  • cmd/evm/main.go
  • cmd/evm/t8n_test.go
  • cmd/evm/testdata/15/exp3.json
  • cmd/evm/testdata/24/env.post.json
  • cmd/evm/testdata/24/env.pre.json
  • cmd/evm/testdata/24/exp.post.json
  • cmd/evm/testdata/24/exp.pre.json
  • cmd/evm/testdata/24/signed_txs.rlp
  • core/bench_test.go
  • core/error.go
  • core/state_transition.go
  • core/state_transition_test.go
  • core/tx_pool.go
  • core/tx_pool_test.go
  • internal/ethapi/api.go
  • internal/ethapi/api_morph_test.go
  • light/trie.go
  • light/txpool.go
  • light/txpool_test.go
  • params/config.go
  • params/config_test.go
  • params/forks/forks.go
  • params/protocol_params.go
  • tests/init.go
  • tests/transaction_test_util.go

Comment thread core/tx_pool_test.go
Comment thread light/trie.go
Comment thread light/txpool.go
Comment thread tests/init.go
- Introduced a new test, `TestAccessListAuthorizationLimitUsesAmsterdamPricing`, to validate the behavior of access list authorization limits under pre- and post-Amsterdam conditions.
- Updated the `mockEstimateGasBackend` to include an `RPCGasCap` method for better gas estimation handling.
- Adjusted the `AccessList` function to align with Amsterdam pricing semantics, ensuring correct gas calculations based on the active fork.
- Enhanced error handling for insufficient gas scenarios in access list creation, providing clearer feedback during testing.
@SegueII SegueII force-pushed the eezo-shunt-sync-consensus branch from 9694d76 to 85478c3 Compare April 22, 2026 07:28
SegueII and others added 4 commits June 2, 2026 18:23
Co-authored-by: Cursor <cursoragent@cursor.com>
…nsus

Co-authored-by: Cursor <cursoragent@cursor.com>

# Conflicts:
#	internal/ethapi/api_morph_test.go
#	params/config.go
- core/tx_pool.go: refresh fork indicators before reinjecting reorged
  transactions so they are validated against the new head's fork rules
- light/txpool.go: reset affected sender nonces and drop now-gapped
  transactions when purging oversized txs on Amsterdam activation
- cmd/evm/t8ntool: enforce Amsterdam gas cap before intrinsic gas check
  (matching txpool ordering) and load tx RLP file when only --input.env
  comes from stdin
- tests/init.go: activate predecessor timestamp forks in Amsterdam config
- core/tx_pool_test.go: handle nil parent in txPoolNextHead helper
- params/config_test.go: assert Amsterdam rewind target timestamp

Co-authored-by: Cursor <cursoragent@cursor.com>
@SegueII

SegueII commented Jul 8, 2026

Copy link
Copy Markdown
Contributor Author

Addressed all CodeRabbit review findings in e023b95, and merged the latest main into this branch in 0d61c47.

Outside-diff comments:

  • cmd/evm/internal/t8ntool/transaction.go (gas-cap ordering): the Amsterdam MaxTxGas check now runs before IntrinsicGas validation, matching the txpool's validateTx ordering. testdata/24/exp.post.json updated accordingly (the capped tx no longer reports intrinsicGas, since the cap rejection happens before intrinsic gas is computed).
  • cmd/evm/internal/t8ntool/transaction.go (stdin env + file txs): when only --input.env is stdin, the tx RLP file referenced by --input.txs is now still loaded — the stdin decode and the tx-body resolution are decoupled.
  • core/tx_pool.go (reset ordering): fork indicators (istanbul/eip2718/eip1559/shanghai/eip7702/jade/amsterdam) and currentHead are now refreshed before reinjecting reorged transactions, so reinjection validates against the new head's fork rules (e.g. a reorg from an Amsterdam head back to a pre-Amsterdam head no longer rejects gas > MaxTxGas txs that are valid again). The oldAmsterdam snapshot taken at the top of reset keeps the activation-eviction trigger intact.

Nitpick:

  • params/config_test.go: added the RewindToTime assertion (uint64(99), i.e. stored time 100 − 1) to TestCheckCompatibleAmsterdamTimestamp.

Merge notes (0d61c47):

  • params/config.go: kept main's updated JadeForkTime comment + this branch's AmsterdamTime field.
  • internal/ethapi/api_morph_test.go: adapted the new Amsterdam tests to main's updated DoEstimateGas / AccessList signatures (new *StateOverride parameter).

Verification: go build on all affected packages; go test green for params, internal/ethapi, light, tests, core -run TestTxPool, cmd/evm -run TestT9n. (cmd/evm TestT8n and core TestTransactionIndices fail identically on current main — pre-existing, unrelated to this PR.)

@SegueII SegueII changed the title Eezo shunt sync: improvement (Impact on consensus) feat: Amsterdam hard fork — EIP-7825 tx gas cap and EIP-7702 authorization gas repricing Jul 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[ Hard Fork ] EIP-7825 Gas limit && EIP-7702 IntrinsicGas refund model

1 participant