@@ -66,10 +66,14 @@ func (result *ExecutionResult) Revert() []byte {
66
66
return common .CopyBytes (result .ReturnData )
67
67
}
68
68
69
- // IntrinsicGas computes the 'intrinsic gas' for a message with the given data.
70
- func IntrinsicGas (data []byte , accessList types.AccessList , authList []types.SetCodeAuthorization , isContractCreation , isHomestead , isEIP2028 , isEIP3860 bool ) (uint64 , error ) {
69
+ // IntrinsicGas computes the 'intrinsic gas' and the number of tokens for EIP-7623
70
+ // for a message with the given data.
71
+ func IntrinsicGas (data []byte , accessList types.AccessList , authList []types.SetCodeAuthorization , isContractCreation , isHomestead , isEIP2028 , isEIP3860 bool ) (uint64 , uint64 , error ) {
71
72
// Set the starting gas for the raw transaction
72
- var gas uint64
73
+ var (
74
+ gas uint64
75
+ tokens uint64
76
+ )
73
77
if isContractCreation && isHomestead {
74
78
gas = params .TxGasContractCreation
75
79
} else {
@@ -85,26 +89,28 @@ func IntrinsicGas(data []byte, accessList types.AccessList, authList []types.Set
85
89
nz ++
86
90
}
87
91
}
92
+ z := dataLen - nz
93
+ tokens = nz * params .TokenPerNonZeroByte7623 + z
94
+
88
95
// Make sure we don't exceed uint64 for all data combinations
89
96
nonZeroGas := params .TxDataNonZeroGasFrontier
90
97
if isEIP2028 {
91
98
nonZeroGas = params .TxDataNonZeroGasEIP2028
92
99
}
93
100
if (math .MaxUint64 - gas )/ nonZeroGas < nz {
94
- return 0 , ErrGasUintOverflow
101
+ return 0 , tokens , ErrGasUintOverflow
95
102
}
96
103
gas += nz * nonZeroGas
97
104
98
- z := dataLen - nz
99
105
if (math .MaxUint64 - gas )/ params .TxDataZeroGas < z {
100
- return 0 , ErrGasUintOverflow
106
+ return 0 , tokens , ErrGasUintOverflow
101
107
}
102
108
gas += z * params .TxDataZeroGas
103
109
104
110
if isContractCreation && isEIP3860 {
105
111
lenWords := toWordSize (dataLen )
106
112
if (math .MaxUint64 - gas )/ params .InitCodeWordGas < lenWords {
107
- return 0 , ErrGasUintOverflow
113
+ return 0 , tokens , ErrGasUintOverflow
108
114
}
109
115
gas += lenWords * params .InitCodeWordGas
110
116
}
@@ -116,7 +122,7 @@ func IntrinsicGas(data []byte, accessList types.AccessList, authList []types.Set
116
122
if authList != nil {
117
123
gas += uint64 (len (authList )) * params .CallNewAccountGas
118
124
}
119
- return gas , nil
125
+ return gas , tokens , nil
120
126
}
121
127
122
128
// toWordSize returns the ceiled word size required for init code payment calculation.
@@ -417,13 +423,23 @@ func (st *stateTransition) execute() (*ExecutionResult, error) {
417
423
)
418
424
419
425
// Check clauses 4-5, subtract intrinsic gas if everything is correct
420
- gas , err := IntrinsicGas (msg .Data , msg .AccessList , msg .SetCodeAuthorizations , contractCreation , rules .IsHomestead , rules .IsIstanbul , rules .IsShanghai )
426
+ gas , dataTokens , err := IntrinsicGas (msg .Data , msg .AccessList , msg .SetCodeAuthorizations , contractCreation , rules .IsHomestead , rules .IsIstanbul , rules .IsShanghai )
421
427
if err != nil {
422
428
return nil , err
423
429
}
424
430
if st .gasRemaining < gas {
425
431
return nil , fmt .Errorf ("%w: have %d, want %d" , ErrIntrinsicGas , st .gasRemaining , gas )
426
432
}
433
+ // Gas limit suffices for the floor data cost (EIP-7623)
434
+ if rules .IsPrague {
435
+ floorGas , err := FloorDataGas (dataTokens )
436
+ if err != nil {
437
+ return nil , err
438
+ }
439
+ if st .gasRemaining < floorGas {
440
+ return nil , fmt .Errorf ("%w: have %d, want %d" , ErrDataFloorGas , st .gasRemaining , floorGas )
441
+ }
442
+ }
427
443
if t := st .evm .Config .Tracer ; t != nil && t .OnGasChange != nil {
428
444
t .OnGasChange (st .gasRemaining , st .gasRemaining - gas , tracing .GasChangeTxIntrinsicGas )
429
445
}
@@ -486,6 +502,14 @@ func (st *stateTransition) execute() (*ExecutionResult, error) {
486
502
// Execute the transaction's call.
487
503
ret , st .gasRemaining , vmerr = st .evm .Call (sender , st .to (), msg .Data , st .gasRemaining , value )
488
504
}
505
+ if rules .IsPrague {
506
+ // After EIP-7623: Data-heavy transactions pay the floor gas.
507
+ // Overflow error has already been checked and can be ignored here.
508
+ floorGas , _ := FloorDataGas (dataTokens )
509
+ if st .gasUsed () < floorGas {
510
+ st .gasRemaining = st .initialGas - floorGas
511
+ }
512
+ }
489
513
490
514
var gasRefund uint64
491
515
if ! rules .IsLondon {
@@ -623,3 +647,13 @@ func (st *stateTransition) gasUsed() uint64 {
623
647
func (st * stateTransition ) blobGasUsed () uint64 {
624
648
return uint64 (len (st .msg .BlobHashes ) * params .BlobTxBlobGasPerBlob )
625
649
}
650
+
651
+ // FloorDataGas calculates the minimum gas required for a transaction
652
+ // based on its data tokens (EIP-7623).
653
+ func FloorDataGas (tokens uint64 ) (uint64 , error ) {
654
+ // Check for overflow
655
+ if (math .MaxUint64 - params .TxGas )/ params .CostFloorPerToken7623 < tokens {
656
+ return 0 , ErrGasUintOverflow
657
+ }
658
+ return params .TxGas + tokens * params .CostFloorPerToken7623 , nil
659
+ }
0 commit comments