@@ -84,7 +84,7 @@ func (s sortGasAndReward) Less(i, j int) bool {
84
84
// processBlock takes a blockFees structure with the blockNumber, the header and optionally
85
85
// the block field filled in, retrieves the block from the backend if not present yet and
86
86
// fills in the rest of the fields.
87
- func (oracle * Oracle ) processBlock (bf * blockFees , percentiles []float64 ) {
87
+ func (oracle * Oracle ) processBlock (bf * blockFees , percentiles []float64 , nonCongestedPrice * big. Int ) {
88
88
chainconfig := oracle .backend .ChainConfig ()
89
89
if bf .results .baseFee = bf .header .BaseFee ; bf .results .baseFee == nil {
90
90
bf .results .baseFee = new (big.Int )
@@ -121,7 +121,12 @@ func (oracle *Oracle) processBlock(bf *blockFees, percentiles []float64) {
121
121
122
122
sorter := make (sortGasAndReward , len (bf .block .Transactions ()))
123
123
for i , tx := range bf .block .Transactions () {
124
- reward , _ := tx .EffectiveGasTip (bf .block .BaseFee ())
124
+ var reward * big.Int
125
+ if nonCongestedPrice != nil {
126
+ reward = nonCongestedPrice
127
+ } else {
128
+ reward , _ = tx .EffectiveGasTip (bf .block .BaseFee ())
129
+ }
125
130
sorter [i ] = txGasAndReward {gasUsed : bf .receipts [i ].GasUsed , reward : reward }
126
131
}
127
132
sort .Sort (sorter )
@@ -144,51 +149,54 @@ func (oracle *Oracle) processBlock(bf *blockFees, percentiles []float64) {
144
149
// also returned if requested and available.
145
150
// Note: an error is only returned if retrieving the head header has failed. If there are no
146
151
// retrievable blocks in the specified range then zero block count is returned with no error.
147
- func (oracle * Oracle ) resolveBlockRange (ctx context.Context , lastBlock rpc.BlockNumber , blocks int ) (* types.Block , []* types.Receipt , uint64 , int , error ) {
152
+ func (oracle * Oracle ) resolveBlockRange (ctx context.Context , lastBlock rpc.BlockNumber , blocks int ) (* types.Block , []* types.Receipt , uint64 , int , * types. Header , error ) {
148
153
var (
149
154
headBlock rpc.BlockNumber
150
155
pendingBlock * types.Block
151
156
pendingReceipts types.Receipts
157
+ headHeader * types.Header
152
158
)
153
159
// query either pending block or head header and set headBlock
154
160
if lastBlock == rpc .PendingBlockNumber {
155
161
if pendingBlock , pendingReceipts = oracle .backend .PendingBlockAndReceipts (); pendingBlock != nil {
156
162
lastBlock = rpc .BlockNumber (pendingBlock .NumberU64 ())
157
163
headBlock = lastBlock - 1
164
+ headHeader = pendingBlock .Header ()
158
165
} else {
159
166
// pending block not supported by backend, process until latest block
160
167
lastBlock = rpc .LatestBlockNumber
161
168
blocks --
162
169
if blocks == 0 {
163
- return nil , nil , 0 , 0 , nil
170
+ return nil , nil , 0 , 0 , nil , nil
164
171
}
165
172
}
166
173
}
167
174
if pendingBlock == nil {
168
175
// if pending block is not fetched then we retrieve the head header to get the head block number
169
176
if latestHeader , err := oracle .backend .HeaderByNumber (ctx , rpc .LatestBlockNumber ); err == nil {
170
177
headBlock = rpc .BlockNumber (latestHeader .Number .Uint64 ())
178
+ headHeader = latestHeader
171
179
} else {
172
- return nil , nil , 0 , 0 , err
180
+ return nil , nil , 0 , 0 , nil , err
173
181
}
174
182
}
175
183
if lastBlock == rpc .LatestBlockNumber {
176
184
lastBlock = headBlock
177
185
} else if pendingBlock == nil && lastBlock > headBlock {
178
- return nil , nil , 0 , 0 , fmt .Errorf ("%w: requested %d, head %d" , errRequestBeyondHead , lastBlock , headBlock )
186
+ return nil , nil , 0 , 0 , nil , fmt .Errorf ("%w: requested %d, head %d" , errRequestBeyondHead , lastBlock , headBlock )
179
187
}
180
188
if lastBlock == rpc .FinalizedBlockNumber {
181
189
if latestFinalizedHeader , err := oracle .backend .HeaderByNumber (ctx , rpc .FinalizedBlockNumber ); err == nil {
182
190
lastBlock = rpc .BlockNumber (latestFinalizedHeader .Number .Uint64 ())
183
191
} else {
184
- return nil , nil , 0 , 0 , err
192
+ return nil , nil , 0 , 0 , nil , err
185
193
}
186
194
}
187
195
// ensure not trying to retrieve before genesis
188
196
if rpc .BlockNumber (blocks ) > lastBlock + 1 {
189
197
blocks = int (lastBlock + 1 )
190
198
}
191
- return pendingBlock , pendingReceipts , uint64 (lastBlock ), blocks , nil
199
+ return pendingBlock , pendingReceipts , uint64 (lastBlock ), blocks , headHeader , nil
192
200
}
193
201
194
202
// FeeHistory returns data relevant for fee estimation based on the specified range of blocks.
@@ -230,12 +238,26 @@ func (oracle *Oracle) FeeHistory(ctx context.Context, blocks int, unresolvedLast
230
238
pendingReceipts []* types.Receipt
231
239
err error
232
240
)
233
- pendingBlock , pendingReceipts , lastBlock , blocks , err := oracle .resolveBlockRange (ctx , unresolvedLastBlock , blocks )
241
+ pendingBlock , pendingReceipts , lastBlock , blocks , headHeader , err := oracle .resolveBlockRange (ctx , unresolvedLastBlock , blocks )
234
242
if err != nil || blocks == 0 {
235
243
return common .Big0 , nil , nil , nil , err
236
244
}
237
245
oldestBlock := lastBlock + 1 - uint64 (blocks )
238
246
247
+ // If pending txs are less than oracle.congestedThreshold, we consider the network to be non-congested and suggest
248
+ // a minimal tip cap. This is to prevent users from overpaying for gas when the network is not congested and a few
249
+ // high-priced txs are causing the suggested tip cap to be high.
250
+ var nonCongestedPrice * big.Int
251
+ pendingTxCount , _ := oracle .backend .StatsWithMinBaseFee (headHeader .BaseFee )
252
+ if pendingTxCount < oracle .congestedThreshold {
253
+ // Before Curie (EIP-1559), we need to return the total suggested gas price. After Curie we return defaultGasTipCap wei as the tip cap,
254
+ // as the base fee is set separately or added manually for legacy transactions.
255
+ nonCongestedPrice = oracle .defaultGasTipCap
256
+ if ! oracle .backend .ChainConfig ().IsCurie (headHeader .Number ) {
257
+ nonCongestedPrice = oracle .defaultBasePrice
258
+ }
259
+ }
260
+
239
261
var (
240
262
next = oldestBlock
241
263
results = make (chan * blockFees , blocks )
@@ -244,6 +266,7 @@ func (oracle *Oracle) FeeHistory(ctx context.Context, blocks int, unresolvedLast
244
266
for i , p := range rewardPercentiles {
245
267
binary .LittleEndian .PutUint64 (percentileKey [i * 8 :(i + 1 )* 8 ], math .Float64bits (p ))
246
268
}
269
+
247
270
for i := 0 ; i < maxBlockFetchers && i < blocks ; i ++ {
248
271
go func () {
249
272
for {
@@ -257,7 +280,7 @@ func (oracle *Oracle) FeeHistory(ctx context.Context, blocks int, unresolvedLast
257
280
if pendingBlock != nil && blockNumber >= pendingBlock .NumberU64 () {
258
281
fees .block , fees .receipts = pendingBlock , pendingReceipts
259
282
fees .header = fees .block .Header ()
260
- oracle .processBlock (fees , rewardPercentiles )
283
+ oracle .processBlock (fees , rewardPercentiles , nonCongestedPrice )
261
284
results <- fees
262
285
} else {
263
286
cacheKey := struct {
@@ -279,7 +302,7 @@ func (oracle *Oracle) FeeHistory(ctx context.Context, blocks int, unresolvedLast
279
302
fees .header , fees .err = oracle .backend .HeaderByNumber (ctx , rpc .BlockNumber (blockNumber ))
280
303
}
281
304
if fees .header != nil && fees .err == nil {
282
- oracle .processBlock (fees , rewardPercentiles )
305
+ oracle .processBlock (fees , rewardPercentiles , nonCongestedPrice )
283
306
if fees .err == nil {
284
307
oracle .historyCache .Add (cacheKey , fees .results )
285
308
}
0 commit comments