@@ -19,6 +19,7 @@ package eip4844
19
19
import (
20
20
"errors"
21
21
"fmt"
22
+ "math"
22
23
"math/big"
23
24
24
25
"github.com/ethereum/go-ethereum/core/types"
@@ -29,28 +30,94 @@ var (
29
30
minBlobGasPrice = big .NewInt (params .BlobTxMinBlobGasprice )
30
31
)
31
32
33
+ // BlobConfig contains the parameters for blob-related formulas.
34
+ // These can be adjusted in a fork.
35
+ type BlobConfig struct {
36
+ Target int
37
+ Max int
38
+ UpdateFraction uint64
39
+ }
40
+
41
+ func (bc * BlobConfig ) maxBlobGas () uint64 {
42
+ return uint64 (bc .Max ) * params .BlobTxBlobGasPerBlob
43
+ }
44
+
45
+ // blobBaseFee computes the blob fee.
46
+ func (bc * BlobConfig ) blobBaseFee (excessBlobGas uint64 ) * big.Int {
47
+ return fakeExponential (minBlobGasPrice , new (big.Int ).SetUint64 (excessBlobGas ), new (big.Int ).SetUint64 (bc .UpdateFraction ))
48
+ }
49
+
50
+ // blobPrice returns the price of one blob in Wei.
51
+ func (bc * BlobConfig ) blobPrice (excessBlobGas uint64 ) * big.Int {
52
+ f := bc .blobBaseFee (excessBlobGas )
53
+ return new (big.Int ).Mul (f , big .NewInt (params .BlobTxBlobGasPerBlob ))
54
+ }
55
+
56
+ func latestBlobConfig (cfg * params.ChainConfig , time uint64 ) * BlobConfig {
57
+ if cfg .BlobScheduleConfig == nil {
58
+ return nil
59
+ }
60
+ var (
61
+ london = cfg .LondonBlock
62
+ s = cfg .BlobScheduleConfig
63
+ bc * params.BlobConfig
64
+ )
65
+ switch {
66
+ case cfg .IsBPO5 (london , time ) && s .BPO5 != nil :
67
+ bc = s .BPO5
68
+ case cfg .IsBPO4 (london , time ) && s .BPO4 != nil :
69
+ bc = s .BPO4
70
+ case cfg .IsBPO3 (london , time ) && s .BPO3 != nil :
71
+ bc = s .BPO3
72
+ case cfg .IsBPO2 (london , time ) && s .BPO2 != nil :
73
+ bc = s .BPO2
74
+ case cfg .IsBPO1 (london , time ) && s .BPO1 != nil :
75
+ bc = s .BPO1
76
+ case cfg .IsOsaka (london , time ) && s .Osaka != nil :
77
+ bc = s .Osaka
78
+ case cfg .IsPrague (london , time ) && s .Prague != nil :
79
+ bc = s .Prague
80
+ case cfg .IsCancun (london , time ) && s .Cancun != nil :
81
+ bc = s .Cancun
82
+ default :
83
+ return nil
84
+ }
85
+
86
+ return & BlobConfig {
87
+ Target : bc .Target ,
88
+ Max : bc .Max ,
89
+ UpdateFraction : bc .UpdateFraction ,
90
+ }
91
+ }
92
+
32
93
// VerifyEIP4844Header verifies the presence of the excessBlobGas field and that
33
94
// if the current block contains no transactions, the excessBlobGas is updated
34
95
// accordingly.
35
96
func VerifyEIP4844Header (config * params.ChainConfig , parent , header * types.Header ) error {
36
97
if header .Number .Uint64 () != parent .Number .Uint64 ()+ 1 {
37
98
panic ("bad header pair" )
38
99
}
39
- // Verify the header is not malformed
100
+
101
+ bcfg := latestBlobConfig (config , header .Time )
102
+ if bcfg == nil {
103
+ panic ("called before EIP-4844 is active" )
104
+ }
105
+
40
106
if header .ExcessBlobGas == nil {
41
107
return errors .New ("header is missing excessBlobGas" )
42
108
}
43
109
if header .BlobGasUsed == nil {
44
110
return errors .New ("header is missing blobGasUsed" )
45
111
}
112
+
46
113
// Verify that the blob gas used remains within reasonable limits.
47
- maxBlobGas := MaxBlobGasPerBlock (config , header .Time )
48
- if * header .BlobGasUsed > maxBlobGas {
49
- return fmt .Errorf ("blob gas used %d exceeds maximum allowance %d" , * header .BlobGasUsed , maxBlobGas )
114
+ if * header .BlobGasUsed > bcfg .maxBlobGas () {
115
+ return fmt .Errorf ("blob gas used %d exceeds maximum allowance %d" , * header .BlobGasUsed , bcfg .maxBlobGas ())
50
116
}
51
117
if * header .BlobGasUsed % params .BlobTxBlobGasPerBlob != 0 {
52
118
return fmt .Errorf ("blob gas used %d not a multiple of blob gas per blob %d" , header .BlobGasUsed , params .BlobTxBlobGasPerBlob )
53
119
}
120
+
54
121
// Verify the excessBlobGas is correct based on the parent header
55
122
expectedExcessBlobGas := CalcExcessBlobGas (config , parent , header .Time )
56
123
if * header .ExcessBlobGas != expectedExcessBlobGas {
@@ -62,38 +129,41 @@ func VerifyEIP4844Header(config *params.ChainConfig, parent, header *types.Heade
62
129
// CalcExcessBlobGas calculates the excess blob gas after applying the set of
63
130
// blobs on top of the excess blob gas.
64
131
func CalcExcessBlobGas (config * params.ChainConfig , parent * types.Header , headTimestamp uint64 ) uint64 {
65
- var (
66
- parentExcessBlobGas uint64
67
- parentBlobGasUsed uint64
68
- )
132
+ isOsaka := config .IsOsaka (config .LondonBlock , headTimestamp )
133
+ bcfg := latestBlobConfig (config , headTimestamp )
134
+ return calcExcessBlobGas (isOsaka , bcfg , parent )
135
+ }
136
+
137
+ func calcExcessBlobGas (isOsaka bool , bcfg * BlobConfig , parent * types.Header ) uint64 {
138
+ var parentExcessBlobGas , parentBlobGasUsed uint64
69
139
if parent .ExcessBlobGas != nil {
70
140
parentExcessBlobGas = * parent .ExcessBlobGas
71
141
parentBlobGasUsed = * parent .BlobGasUsed
72
142
}
143
+
73
144
var (
74
145
excessBlobGas = parentExcessBlobGas + parentBlobGasUsed
75
- target = targetBlobsPerBlock (config , headTimestamp )
76
- targetGas = uint64 (target ) * params .BlobTxBlobGasPerBlob
146
+ targetGas = uint64 (bcfg .Target ) * params .BlobTxBlobGasPerBlob
77
147
)
78
148
if excessBlobGas < targetGas {
79
149
return 0
80
150
}
81
- if ! config .IsOsaka (config .LondonBlock , headTimestamp ) {
82
- // Pre-Osaka, we use the formula defined by EIP-4844.
83
- return excessBlobGas - targetGas
84
- }
85
151
86
- // EIP-7918 (post-Osaka) introduces a different formula for computing excess.
87
- var (
88
- baseCost = big .NewInt (params .BlobBaseCost )
89
- reservePrice = baseCost .Mul (baseCost , parent .BaseFee )
90
- blobPrice = calcBlobPrice (config , parent )
91
- )
92
- if reservePrice .Cmp (blobPrice ) > 0 {
93
- max := MaxBlobsPerBlock (config , headTimestamp )
94
- scaledExcess := parentBlobGasUsed * uint64 (max - target ) / uint64 (max )
95
- return parentExcessBlobGas + scaledExcess
152
+ // EIP-7918 (post-Osaka) introduces a different formula for computing excess,
153
+ // in cases where the price is lower than a 'reserve price'.
154
+ if isOsaka {
155
+ var (
156
+ baseCost = big .NewInt (params .BlobBaseCost )
157
+ reservePrice = baseCost .Mul (baseCost , parent .BaseFee )
158
+ blobPrice = bcfg .blobPrice (parentExcessBlobGas )
159
+ )
160
+ if reservePrice .Cmp (blobPrice ) > 0 {
161
+ scaledExcess := parentBlobGasUsed * uint64 (bcfg .Max - bcfg .Target ) / uint64 (bcfg .Max )
162
+ return parentExcessBlobGas + scaledExcess
163
+ }
96
164
}
165
+
166
+ // Original EIP-4844 formula.
97
167
return excessBlobGas - targetGas
98
168
}
99
169
@@ -103,7 +173,7 @@ func CalcBlobFee(config *params.ChainConfig, header *types.Header) *big.Int {
103
173
if blobConfig == nil {
104
174
panic ("calculating blob fee on unsupported fork" )
105
175
}
106
- return fakeExponential ( minBlobGasPrice , new (big. Int ). SetUint64 (* header .ExcessBlobGas ), new (big. Int ). SetUint64 ( blobConfig . UpdateFraction ) )
176
+ return blobConfig . blobBaseFee (* header .ExcessBlobGas )
107
177
}
108
178
109
179
// MaxBlobsPerBlock returns the max blobs per block for a block at the given timestamp.
@@ -115,36 +185,6 @@ func MaxBlobsPerBlock(cfg *params.ChainConfig, time uint64) int {
115
185
return blobConfig .Max
116
186
}
117
187
118
- func latestBlobConfig (cfg * params.ChainConfig , time uint64 ) * params.BlobConfig {
119
- if cfg .BlobScheduleConfig == nil {
120
- return nil
121
- }
122
- var (
123
- london = cfg .LondonBlock
124
- s = cfg .BlobScheduleConfig
125
- )
126
- switch {
127
- case cfg .IsBPO5 (london , time ) && s .BPO5 != nil :
128
- return s .BPO5
129
- case cfg .IsBPO4 (london , time ) && s .BPO4 != nil :
130
- return s .BPO4
131
- case cfg .IsBPO3 (london , time ) && s .BPO3 != nil :
132
- return s .BPO3
133
- case cfg .IsBPO2 (london , time ) && s .BPO2 != nil :
134
- return s .BPO2
135
- case cfg .IsBPO1 (london , time ) && s .BPO1 != nil :
136
- return s .BPO1
137
- case cfg .IsOsaka (london , time ) && s .Osaka != nil :
138
- return s .Osaka
139
- case cfg .IsPrague (london , time ) && s .Prague != nil :
140
- return s .Prague
141
- case cfg .IsCancun (london , time ) && s .Cancun != nil :
142
- return s .Cancun
143
- default :
144
- return nil
145
- }
146
- }
147
-
148
188
// MaxBlobGasPerBlock returns the maximum blob gas that can be spent in a block at the given timestamp.
149
189
func MaxBlobGasPerBlock (cfg * params.ChainConfig , time uint64 ) uint64 {
150
190
return uint64 (MaxBlobsPerBlock (cfg , time )) * params .BlobTxBlobGasPerBlob
@@ -153,39 +193,11 @@ func MaxBlobGasPerBlock(cfg *params.ChainConfig, time uint64) uint64 {
153
193
// LatestMaxBlobsPerBlock returns the latest max blobs per block defined by the
154
194
// configuration, regardless of the currently active fork.
155
195
func LatestMaxBlobsPerBlock (cfg * params.ChainConfig ) int {
156
- s := cfg .BlobScheduleConfig
157
- if s == nil {
158
- return 0
159
- }
160
- switch {
161
- case s .BPO5 != nil :
162
- return s .BPO5 .Max
163
- case s .BPO4 != nil :
164
- return s .BPO4 .Max
165
- case s .BPO3 != nil :
166
- return s .BPO3 .Max
167
- case s .BPO2 != nil :
168
- return s .BPO2 .Max
169
- case s .BPO1 != nil :
170
- return s .BPO1 .Max
171
- case s .Osaka != nil :
172
- return s .Osaka .Max
173
- case s .Prague != nil :
174
- return s .Prague .Max
175
- case s .Cancun != nil :
176
- return s .Cancun .Max
177
- default :
196
+ bcfg := latestBlobConfig (cfg , math .MaxUint64 )
197
+ if bcfg == nil {
178
198
return 0
179
199
}
180
- }
181
-
182
- // targetBlobsPerBlock returns the target number of blobs in a block at the given timestamp.
183
- func targetBlobsPerBlock (cfg * params.ChainConfig , time uint64 ) int {
184
- blobConfig := latestBlobConfig (cfg , time )
185
- if blobConfig == nil {
186
- return 0
187
- }
188
- return blobConfig .Target
200
+ return bcfg .Max
189
201
}
190
202
191
203
// fakeExponential approximates factor * e ** (numerator / denominator) using
@@ -204,9 +216,3 @@ func fakeExponential(factor, numerator, denominator *big.Int) *big.Int {
204
216
}
205
217
return output .Div (output , denominator )
206
218
}
207
-
208
- // calcBlobPrice calculates the blob price for a block.
209
- func calcBlobPrice (config * params.ChainConfig , header * types.Header ) * big.Int {
210
- blobBaseFee := CalcBlobFee (config , header )
211
- return new (big.Int ).Mul (blobBaseFee , big .NewInt (params .BlobTxBlobGasPerBlob ))
212
- }
0 commit comments