From 82061af43f385d2d05dee38f635ee1e5960d6f2f Mon Sep 17 00:00:00 2001 From: rjl493456442 Date: Mon, 10 Aug 2026 14:46:13 +0800 Subject: [PATCH] core/vm, params, tests: update gas price parameters (#35497) https://github.com/ethereum/EIPs/pull/12083 --- core/vm/eip8037_test.go | 25 +++++++++++-------------- core/vm/eip8038_test.go | 35 ++++++++++++++++++++++++++++------- params/protocol_params.go | 12 ++++++------ tests/block_test_util.go | 1 + 4 files changed, 46 insertions(+), 27 deletions(-) diff --git a/core/vm/eip8037_test.go b/core/vm/eip8037_test.go index 5bbf8e4c10..b8acb4c85c 100644 --- a/core/vm/eip8037_test.go +++ b/core/vm/eip8037_test.go @@ -190,24 +190,21 @@ func TestSStoreChargedAtOpcodeEnd(t *testing.T) { } // The SSTORE reentrancy sentry checks gas_left only; the reservoir is excluded. -// Uses a noop write (1->1->1): the two PUSH1s cost 6, leaving gas_left at the -// sentry (2300) for a 2306 budget. Under EIP-8038 the cold-slot access that -// follows a cleared sentry costs COLD_STORAGE_ACCESS (3000). +// Uses a noop write (1->1->1): the two PUSH1s cost 6, so a budget of +// 6 + SstoreSentryGasEIP2200 leaves gas_left exactly at the sentry. func TestSStoreStipendExcludesReservoir(t *testing.T) { - // execution at the sentry, huge reservoir: must still fail, proving the + const pushes = 6 + + // Execution gas at the sentry, huge reservoir: must still fail, proving the // reservoir does not count toward the sentry. - if _, _, err := run8037(t, sstore(0, 1), NewGasBudget(2306, math.MaxUint64/2), new(uint256.Int), setSlot(0, 1)); err == nil { + atSentry := pushes + params.SstoreSentryGasEIP2200 + if _, _, err := run8037(t, sstore(0, 1), NewGasBudget(atSentry, math.MaxUint64/2), new(uint256.Int), setSlot(0, 1)); err == nil { t.Fatal("expected sentry failure with execution gas at the limit") } - // Enough execution gas to clear the sentry and pay the cold-slot access - // (6 for the PUSH1s + COLD_STORAGE_ACCESS) succeeds with a huge reservoir. - execution := 6 + params.ColdStorageAccessAmsterdam - if _, _, err := run8037(t, sstore(0, 1), NewGasBudget(execution, math.MaxUint64/2), new(uint256.Int), setSlot(0, 1)); err != nil { - t.Fatalf("unexpected failure above sentry: %v", err) - } - // One gas short of the cold-slot access still fails (now on OOG, not sentry). - if _, _, err := run8037(t, sstore(0, 1), NewGasBudget(execution-1, math.MaxUint64/2), new(uint256.Int), setSlot(0, 1)); err == nil { - t.Fatal("expected OOG when execution gas cannot cover cold-slot access") + // One gas above the sentry succeeds: the cold-slot access is cheaper than the + // sentry, so clearing the sentry is sufficient. + if _, _, err := run8037(t, sstore(0, 1), NewGasBudget(atSentry+1, math.MaxUint64/2), new(uint256.Int), setSlot(0, 1)); err != nil { + t.Fatalf("unexpected failure one gas above the sentry: %v", err) } } diff --git a/core/vm/eip8038_test.go b/core/vm/eip8038_test.go index 52160bb4b6..675c44263e 100644 --- a/core/vm/eip8038_test.go +++ b/core/vm/eip8038_test.go @@ -378,16 +378,37 @@ func TestEIP8038SelfdestructAccountWrite(t *testing.T) { // TestEIP8038SStoreAccessGuard covers the affordability check that bails out // before the slot is read once the gas left cannot cover the slot's access cost. -// The two PUSH1s cost 6, so a 2506 budget leaves 2500 at the SSTORE: above the -// reentrancy sentry (2300) yet below COLD_STORAGE_ACCESS (3000). The guard must -// fire, distinguishable from the sentry/charge OOG by its "slot access" message. +// +// Under the current schedule that guard is a backstop rather than a reachable +// path: both access costs, COLD_STORAGE_ACCESS (2,100) and WARM_ACCESS (100), +// are below the reentrancy sentry (2,300), and the sentry is checked first, so +// any gas that reaches the guard already covers the access. The guard is kept +// as defensive code because the two are independent parameters. +// +// This test pins that relationship. If a repricing lifts either access cost +// above the sentry the guard becomes reachable again, and this test fails to +// say so rather than letting SSTORE's failure mode change unnoticed. func TestEIP8038SStoreAccessGuard(t *testing.T) { - budget := NewGasBudget(6+params.SstoreSentryGasEIP2200+200, 0) + for _, tc := range []struct { + name string + cost uint64 + }{ + {"cold", params.ColdStorageAccessAmsterdam}, + {"warm", params.WarmStorageAccessAmsterdam}, + } { + if tc.cost > params.SstoreSentryGasEIP2200 { + t.Fatalf("%s slot access (%d) exceeds the reentrancy sentry (%d): the guard "+ + "is reachable again and needs a test exercising it", tc.name, tc.cost, params.SstoreSentryGasEIP2200) + } + } + // Below the sentry the sentry itself must be what rejects the call, not the + // slot-access guard behind it. + budget := NewGasBudget(6+params.SstoreSentryGasEIP2200, 0) _, _, err := run8038(t, sstore(0, 1), budget, new(uint256.Int), nil) if err == nil { - t.Fatal("expected failure: gas left cannot cover cold-slot access") + t.Fatal("expected failure: gas left is at the reentrancy sentry") } - if !strings.Contains(err.Error(), "not enough gas for slot access") { - t.Fatalf("got %q, want the slot-access guard error", err) + if !strings.Contains(err.Error(), "not enough gas for reentrancy sentry") { + t.Fatalf("got %q, want the reentrancy sentry error", err) } } diff --git a/params/protocol_params.go b/params/protocol_params.go index 965a446c4c..3cc8e2320c 100644 --- a/params/protocol_params.go +++ b/params/protocol_params.go @@ -113,15 +113,15 @@ const ( // EIP-8038: state-access gas cost update (Amsterdam). ColdAccountAccessAmsterdam uint64 = 3000 // COLD_ACCOUNT_ACCESS: cold touch of an account WarmAccountAccessAmsterdam uint64 = 100 // WARM_ACCESS: warm touch of an account - AccountWriteAmsterdam uint64 = 8000 // ACCOUNT_WRITE: surcharge for first-time write to an account - CallValueTransferAmsterdam uint64 = 10300 // CALL_VALUE = ACCOUNT_WRITE + CallStipend (2300) - ColdStorageAccessAmsterdam uint64 = 3000 // COLD_STORAGE_ACCESS: cold touch of a storage slot + AccountWriteAmsterdam uint64 = 9000 // ACCOUNT_WRITE: surcharge for first-time write to an account + CallValueTransferAmsterdam uint64 = 11300 // CALL_VALUE = ACCOUNT_WRITE + CallStipend (2300) + ColdStorageAccessAmsterdam uint64 = 2100 // COLD_STORAGE_ACCESS: cold touch of a storage slot WarmStorageAccessAmsterdam uint64 = 100 // WARM_STORAGE_ACCESS: warm touch of a storage slot StorageWriteAmsterdam uint64 = 10000 // STORAGE_WRITE: surcharge for first-time write to a storage slot - StorageClearRefundAmsterdam uint64 = 12480 // STORAGE_CLEAR_REFUND: refund for clearing a storage slot - CreateAccessAmsterdam uint64 = 11000 // CREATE_ACCESS = ACCOUNT_WRITE + COLD_STORAGE_ACCESS + StorageClearRefundAmsterdam uint64 = 11616 // STORAGE_CLEAR_REFUND: refund for clearing a storage slot + CreateAccessAmsterdam uint64 = 12000 // CREATE_ACCESS = ACCOUNT_WRITE + COLD_ACCOUNT_ACCESS TxAccessListAddressGasAmsterdam uint64 = 2900 // ACCESS_LIST_ADDRESS_COST - TxAccessListStorageKeyGasAmsterdam uint64 = 2900 // ACCESS_LIST_STORAGE_KEY_COST + TxAccessListStorageKeyGasAmsterdam uint64 = 2000 // ACCESS_LIST_STORAGE_KEY_COST // These have been changed during the course of the chain CallGasFrontier uint64 = 40 // Once per CALL operation & message call transaction. diff --git a/tests/block_test_util.go b/tests/block_test_util.go index bece8ae610..62ee3b3b4b 100644 --- a/tests/block_test_util.go +++ b/tests/block_test_util.go @@ -227,6 +227,7 @@ func (t *BlockTest) genesis(config *params.ChainConfig) *core.Genesis { BaseFee: t.json.Genesis.BaseFeePerGas, BlobGasUsed: t.json.Genesis.BlobGasUsed, ExcessBlobGas: t.json.Genesis.ExcessBlobGas, + SlotNumber: t.json.Genesis.SlotNumber, } }