From bb987df015ca715ee0109ba7d4069403dbed0228 Mon Sep 17 00:00:00 2001 From: MariusVanDerWijden Date: Fri, 17 Apr 2026 14:41:14 +0200 Subject: [PATCH] core: implement eip-7976: Increase Calldata Floor Cost --- cmd/evm/internal/t8ntool/transaction.go | 2 +- core/state_transition.go | 28 ++++++++++++++++++------- core/txpool/validation.go | 2 +- params/protocol_params.go | 1 + tests/transaction_test_util.go | 6 +++--- 5 files changed, 27 insertions(+), 12 deletions(-) diff --git a/cmd/evm/internal/t8ntool/transaction.go b/cmd/evm/internal/t8ntool/transaction.go index 3a457eeaec..2e8bbb1260 100644 --- a/cmd/evm/internal/t8ntool/transaction.go +++ b/cmd/evm/internal/t8ntool/transaction.go @@ -147,7 +147,7 @@ func Transaction(ctx *cli.Context) error { } // For Prague txs, validate the floor data gas. if rules.IsPrague { - floorDataGas, err := core.FloorDataGas(tx.Data()) + floorDataGas, err := core.FloorDataGas(rules, tx.Data()) if err != nil { r.Error = err results = append(results, r) diff --git a/core/state_transition.go b/core/state_transition.go index bd7e5daeff..de8df47f84 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -117,18 +117,32 @@ func IntrinsicGas(data []byte, accessList types.AccessList, authList []types.Set } // FloorDataGas computes the minimum gas required for a transaction based on its data tokens (EIP-7623). -func FloorDataGas(data []byte) (uint64, error) { +func FloorDataGas(rules params.Rules, data []byte) (uint64, error) { var ( - z = uint64(bytes.Count(data, []byte{0})) - nz = uint64(len(data)) - z - tokens = nz*params.TxTokenPerNonZeroByte + z + tokens uint64 + tokenCost uint64 ) + if rules.IsAmsterdam { + // EIP-7976 changes both how calldata is priced. + // From 10/40 to 64/64 for zero/non-zero bytes. + tokens = uint64(len(data)) * params.TxTokenPerNonZeroByte + tokenCost = params.TxCostFloorPerToken7976 + } else { + var ( + z = uint64(bytes.Count(data, []byte{0})) + nz = uint64(len(data)) - z + ) + // Pre-Amsterdam + tokens = nz*params.TxTokenPerNonZeroByte + z + tokenCost = params.TxCostFloorPerToken + } + // Check for overflow - if (math.MaxUint64-params.TxGas)/params.TxCostFloorPerToken < tokens { + if (math.MaxUint64-params.TxGas)/tokenCost < tokens { return 0, ErrGasUintOverflow } // Minimum gas required for a transaction based on its data tokens (EIP-7623). - return params.TxGas + tokens*params.TxCostFloorPerToken, nil + return params.TxGas + tokens*tokenCost, nil } // toWordSize returns the ceiled word size required for init code payment calculation. @@ -457,7 +471,7 @@ func (st *stateTransition) execute() (*ExecutionResult, error) { } // Gas limit suffices for the floor data cost (EIP-7623) if rules.IsPrague { - floorDataGas, err = FloorDataGas(msg.Data) + floorDataGas, err = FloorDataGas(rules, msg.Data) if err != nil { return nil, err } diff --git a/core/txpool/validation.go b/core/txpool/validation.go index 13b1bfa312..30a8973e55 100644 --- a/core/txpool/validation.go +++ b/core/txpool/validation.go @@ -134,7 +134,7 @@ func ValidateTransaction(tx *types.Transaction, head *types.Header, signer types } // Ensure the transaction can cover floor data gas. if rules.IsPrague { - floorDataGas, err := core.FloorDataGas(tx.Data()) + floorDataGas, err := core.FloorDataGas(rules, tx.Data()) if err != nil { return err } diff --git a/params/protocol_params.go b/params/protocol_params.go index 652574287c..9da275c486 100644 --- a/params/protocol_params.go +++ b/params/protocol_params.go @@ -96,6 +96,7 @@ const ( TxDataNonZeroGasEIP2028 uint64 = 16 // Per byte of non zero data attached to a transaction after EIP 2028 (part in Istanbul) TxTokenPerNonZeroByte uint64 = 4 // Token cost per non-zero byte as specified by EIP-7623. TxCostFloorPerToken uint64 = 10 // Cost floor per byte of data as specified by EIP-7623. + TxCostFloorPerToken7976 uint64 = 16 // Cost floor per byte of data as specified by EIP-7976. TxAccessListAddressGas uint64 = 2400 // Per address specified in EIP 2930 access list TxAccessListStorageKeyGas uint64 = 1900 // Per storage key specified in EIP 2930 access list TxAuthTupleGas uint64 = 12500 // Per auth tuple code specified in EIP-7702 diff --git a/tests/transaction_test_util.go b/tests/transaction_test_util.go index a90c2d522f..9eafecfa63 100644 --- a/tests/transaction_test_util.go +++ b/tests/transaction_test_util.go @@ -71,7 +71,7 @@ func (tt *TransactionTest) Run() error { if err := tt.validate(); err != nil { return err } - validateTx := func(rlpData hexutil.Bytes, signer types.Signer, rules *params.Rules) (sender common.Address, hash common.Hash, requiredGas uint64, err error) { + validateTx := func(rlpData hexutil.Bytes, signer types.Signer, rules params.Rules) (sender common.Address, hash common.Hash, requiredGas uint64, err error) { tx := new(types.Transaction) if err = tx.UnmarshalBinary(rlpData); err != nil { return @@ -91,7 +91,7 @@ func (tt *TransactionTest) Run() error { if rules.IsPrague { var floorDataGas uint64 - floorDataGas, err = core.FloorDataGas(tx.Data()) + floorDataGas, err = core.FloorDataGas(rules, tx.Data()) if err != nil { return } @@ -132,7 +132,7 @@ func (tt *TransactionTest) Run() error { rules = config.Rules(new(big.Int), testcase.isMerge, 0) signer = types.MakeSigner(config, new(big.Int), 0) ) - sender, hash, gas, err := validateTx(tt.Txbytes, signer, &rules) + sender, hash, gas, err := validateTx(tt.Txbytes, signer, rules) if err != nil { if expected.Hash != nil { return fmt.Errorf("unexpected error fork %s: %v", testcase.name, err)