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. // For Prague txs, validate the floor data gas.
if rules.IsPrague { if rules.IsPrague {
floorDataGas, err := core.FloorDataGas(tx.Data()) floorDataGas, err := core.FloorDataGas(rules, tx.Data())
if err != nil { if err != nil {
r.Error = err r.Error = err
results = append(results, r) 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). // 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 ( var (
z = uint64(bytes.Count(data, []byte{0})) tokens uint64
nz = uint64(len(data)) - z tokenCost uint64
tokens = nz*params.TxTokenPerNonZeroByte + z
) )
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 // Check for overflow
if (math.MaxUint64-params.TxGas)/params.TxCostFloorPerToken < tokens { if (math.MaxUint64-params.TxGas)/tokenCost < tokens {
return 0, ErrGasUintOverflow return 0, ErrGasUintOverflow
} }
// Minimum gas required for a transaction based on its data tokens (EIP-7623). // 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. // 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) // Gas limit suffices for the floor data cost (EIP-7623)
if rules.IsPrague { if rules.IsPrague {
floorDataGas, err = FloorDataGas(msg.Data) floorDataGas, err = FloorDataGas(rules, msg.Data)
if err != nil { if err != nil {
return nil, err 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. // Ensure the transaction can cover floor data gas.
if rules.IsPrague { if rules.IsPrague {
floorDataGas, err := core.FloorDataGas(tx.Data()) floorDataGas, err := core.FloorDataGas(rules, tx.Data())
if err != nil { if err != nil {
return err 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) 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. 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. 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 TxAccessListAddressGas uint64 = 2400 // Per address specified in EIP 2930 access list
TxAccessListStorageKeyGas uint64 = 1900 // Per storage key 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 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 { if err := tt.validate(); err != nil {
return err 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) tx := new(types.Transaction)
if err = tx.UnmarshalBinary(rlpData); err != nil { if err = tx.UnmarshalBinary(rlpData); err != nil {
return return
@ -91,7 +91,7 @@ func (tt *TransactionTest) Run() error {
if rules.IsPrague { if rules.IsPrague {
var floorDataGas uint64 var floorDataGas uint64
floorDataGas, err = core.FloorDataGas(tx.Data()) floorDataGas, err = core.FloorDataGas(rules, tx.Data())
if err != nil { if err != nil {
return return
} }
@ -132,7 +132,7 @@ func (tt *TransactionTest) Run() error {
rules = config.Rules(new(big.Int), testcase.isMerge, 0) rules = config.Rules(new(big.Int), testcase.isMerge, 0)
signer = types.MakeSigner(config, new(big.Int), 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 err != nil {
if expected.Hash != nil { if expected.Hash != nil {
return fmt.Errorf("unexpected error fork %s: %v", testcase.name, err) return fmt.Errorf("unexpected error fork %s: %v", testcase.name, err)