core: implement eip-7976: Increase Calldata Floor Cost

This commit is contained in:
MariusVanDerWijden 2026-04-17 14:41:14 +02:00
parent 573d94013c
commit bb987df015
5 changed files with 27 additions and 12 deletions

View file

@ -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)

View file

@ -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
}

View file

@ -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
}

View file

@ -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

View file

@ -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)