@@ -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
+ floorDataGas uint64
76
+ )
73
77
if isContractCreation && isHomestead {
74
78
gas = params .TxGasContractCreation
75
79
} else {
@@ -85,26 +89,36 @@ func IntrinsicGas(data []byte, accessList types.AccessList, authList []types.Set
85
89
nz ++
86
90
}
87
91
}
92
+ var (
93
+ z = dataLen - nz
94
+ tokens = nz * params .TokenPerNonZeroByte7623 + z
95
+ )
96
+ // Check for overflow
97
+ if (math .MaxUint64 - params .TxGas )/ params .CostFloorPerToken7623 < tokens {
98
+ return 0 , 0 , ErrGasUintOverflow
99
+ }
100
+ // Minimum gas required for a transaction based on its data tokens (EIP-7623).
101
+ floorDataGas = params .TxGas + tokens * params .CostFloorPerToken7623
102
+
88
103
// Make sure we don't exceed uint64 for all data combinations
89
104
nonZeroGas := params .TxDataNonZeroGasFrontier
90
105
if isEIP2028 {
91
106
nonZeroGas = params .TxDataNonZeroGasEIP2028
92
107
}
93
108
if (math .MaxUint64 - gas )/ nonZeroGas < nz {
94
- return 0 , ErrGasUintOverflow
109
+ return 0 , 0 , ErrGasUintOverflow
95
110
}
96
111
gas += nz * nonZeroGas
97
112
98
- z := dataLen - nz
99
113
if (math .MaxUint64 - gas )/ params .TxDataZeroGas < z {
100
- return 0 , ErrGasUintOverflow
114
+ return 0 , 0 , ErrGasUintOverflow
101
115
}
102
116
gas += z * params .TxDataZeroGas
103
117
104
118
if isContractCreation && isEIP3860 {
105
119
lenWords := toWordSize (dataLen )
106
120
if (math .MaxUint64 - gas )/ params .InitCodeWordGas < lenWords {
107
- return 0 , ErrGasUintOverflow
121
+ return 0 , 0 , ErrGasUintOverflow
108
122
}
109
123
gas += lenWords * params .InitCodeWordGas
110
124
}
@@ -116,7 +130,7 @@ func IntrinsicGas(data []byte, accessList types.AccessList, authList []types.Set
116
130
if authList != nil {
117
131
gas += uint64 (len (authList )) * params .CallNewAccountGas
118
132
}
119
- return gas , nil
133
+ return gas , floorDataGas , nil
120
134
}
121
135
122
136
// toWordSize returns the ceiled word size required for init code payment calculation.
@@ -417,13 +431,19 @@ func (st *stateTransition) execute() (*ExecutionResult, error) {
417
431
)
418
432
419
433
// 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 )
434
+ gas , floorDataGas , err := IntrinsicGas (msg .Data , msg .AccessList , msg .SetCodeAuthorizations , contractCreation , rules .IsHomestead , rules .IsIstanbul , rules .IsShanghai )
421
435
if err != nil {
422
436
return nil , err
423
437
}
424
438
if st .gasRemaining < gas {
425
439
return nil , fmt .Errorf ("%w: have %d, want %d" , ErrIntrinsicGas , st .gasRemaining , gas )
426
440
}
441
+ // Gas limit suffices for the floor data cost (EIP-7623)
442
+ if rules .IsPrague {
443
+ if st .gasRemaining < floorDataGas {
444
+ return nil , fmt .Errorf ("%w: have %d, want %d" , ErrDataFloorGas , st .gasRemaining , floorDataGas )
445
+ }
446
+ }
427
447
if t := st .evm .Config .Tracer ; t != nil && t .OnGasChange != nil {
428
448
t .OnGasChange (st .gasRemaining , st .gasRemaining - gas , tracing .GasChangeTxIntrinsicGas )
429
449
}
@@ -490,11 +510,28 @@ func (st *stateTransition) execute() (*ExecutionResult, error) {
490
510
var gasRefund uint64
491
511
if ! rules .IsLondon {
492
512
// Before EIP-3529: refunds were capped to gasUsed / 2
493
- gasRefund = st .refundGas (params .RefundQuotient )
513
+ gasRefund = st .refundAmount (params .RefundQuotient )
494
514
} else {
495
515
// After EIP-3529: refunds are capped to gasUsed / 5
496
- gasRefund = st .refundGas (params .RefundQuotientEIP3529 )
516
+ gasRefund = st .refundAmount (params .RefundQuotientEIP3529 )
517
+ }
518
+
519
+ if st .evm .Config .Tracer != nil && st .evm .Config .Tracer .OnGasChange != nil && gasRefund > 0 {
520
+ st .evm .Config .Tracer .OnGasChange (st .gasRemaining , st .gasRemaining + gasRefund , tracing .GasChangeTxRefunds )
497
521
}
522
+ st .gasRemaining += gasRefund
523
+ if rules .IsPrague {
524
+ // After EIP-7623: Data-heavy transactions pay the floor gas.
525
+ if st .gasUsed () < floorDataGas {
526
+ prev := st .gasRemaining
527
+ st .gasRemaining = st .initialGas - floorDataGas
528
+ if t := st .evm .Config .Tracer ; t != nil && t .OnGasChange != nil {
529
+ t .OnGasChange (prev , st .gasRemaining , tracing .GasChangeTxDataFloor )
530
+ }
531
+ }
532
+ }
533
+ st .returnGas ()
534
+
498
535
effectiveTip := msg .GasPrice
499
536
if rules .IsLondon {
500
537
effectiveTip = new (big.Int ).Sub (msg .GasFeeCap , st .evm .Context .BaseFee )
@@ -585,19 +622,16 @@ func (st *stateTransition) applyAuthorization(msg *Message, auth *types.SetCodeA
585
622
return nil
586
623
}
587
624
588
- func (st * stateTransition ) refundGas (refundQuotient uint64 ) uint64 {
625
+ func (st * stateTransition ) refundAmount (refundQuotient uint64 ) uint64 {
589
626
// Apply refund counter, capped to a refund quotient
590
627
refund := st .gasUsed () / refundQuotient
591
628
if refund > st .state .GetRefund () {
592
629
refund = st .state .GetRefund ()
593
630
}
631
+ return refund
632
+ }
594
633
595
- if st .evm .Config .Tracer != nil && st .evm .Config .Tracer .OnGasChange != nil && refund > 0 {
596
- st .evm .Config .Tracer .OnGasChange (st .gasRemaining , st .gasRemaining + refund , tracing .GasChangeTxRefunds )
597
- }
598
-
599
- st .gasRemaining += refund
600
-
634
+ func (st * stateTransition ) returnGas () {
601
635
// Return ETH for remaining gas, exchanged at the original rate.
602
636
remaining := uint256 .NewInt (st .gasRemaining )
603
637
remaining .Mul (remaining , uint256 .MustFromBig (st .msg .GasPrice ))
@@ -610,8 +644,6 @@ func (st *stateTransition) refundGas(refundQuotient uint64) uint64 {
610
644
// Also return remaining gas to the block gas counter so it is
611
645
// available for the next transaction.
612
646
st .gp .AddGas (st .gasRemaining )
613
-
614
- return refund
615
647
}
616
648
617
649
// gasUsed returns the amount of gas used up by the state transition.
0 commit comments