@@ -19,17 +19,17 @@ package gasprice
19
19
import (
20
20
"context"
21
21
"math/big"
22
- "sort "
22
+ "slices "
23
23
"sync"
24
24
25
25
"github.com/XinFinOrg/XDPoSChain/common"
26
+ "github.com/XinFinOrg/XDPoSChain/common/lru"
26
27
"github.com/XinFinOrg/XDPoSChain/core"
27
28
"github.com/XinFinOrg/XDPoSChain/core/types"
28
29
"github.com/XinFinOrg/XDPoSChain/event"
29
30
"github.com/XinFinOrg/XDPoSChain/log"
30
31
"github.com/XinFinOrg/XDPoSChain/params"
31
32
"github.com/XinFinOrg/XDPoSChain/rpc"
32
- lru "github.com/hashicorp/golang-lru"
33
33
)
34
34
35
35
const sampleNumber = 3 // Number of transactions sampled in a block
@@ -44,7 +44,6 @@ type Config struct {
44
44
Percentile int
45
45
MaxHeaderHistory uint64
46
46
MaxBlockHistory uint64
47
- Default * big.Int `toml:",omitempty"`
48
47
MaxPrice * big.Int `toml:",omitempty"`
49
48
IgnorePrice * big.Int `toml:",omitempty"`
50
49
}
@@ -72,12 +71,13 @@ type Oracle struct {
72
71
73
72
checkBlocks , percentile int
74
73
maxHeaderHistory , maxBlockHistory uint64
75
- historyCache * lru.Cache
74
+
75
+ historyCache * lru.Cache [cacheKey , processedFees ]
76
76
}
77
77
78
78
// NewOracle returns a new gasprice oracle which can recommend suitable
79
79
// gasprice for newly created transaction.
80
- func NewOracle (backend OracleBackend , params Config ) * Oracle {
80
+ func NewOracle (backend OracleBackend , params Config , startPrice * big. Int ) * Oracle {
81
81
blocks := params .Blocks
82
82
if blocks < 1 {
83
83
blocks = 1
@@ -87,8 +87,7 @@ func NewOracle(backend OracleBackend, params Config) *Oracle {
87
87
if percent < 0 {
88
88
percent = 0
89
89
log .Warn ("Sanitizing invalid gasprice oracle sample percentile" , "provided" , params .Percentile , "updated" , percent )
90
- }
91
- if percent > 100 {
90
+ } else if percent > 100 {
92
91
percent = 100
93
92
log .Warn ("Sanitizing invalid gasprice oracle sample percentile" , "provided" , params .Percentile , "updated" , percent )
94
93
}
@@ -104,8 +103,21 @@ func NewOracle(backend OracleBackend, params Config) *Oracle {
104
103
} else if ignorePrice .Int64 () > 0 {
105
104
log .Info ("Gasprice oracle is ignoring threshold set" , "threshold" , ignorePrice )
106
105
}
106
+ maxHeaderHistory := params .MaxHeaderHistory
107
+ if maxHeaderHistory < 1 {
108
+ maxHeaderHistory = 1
109
+ log .Warn ("Sanitizing invalid gasprice oracle max header history" , "provided" , params .MaxHeaderHistory , "updated" , maxHeaderHistory )
110
+ }
111
+ maxBlockHistory := params .MaxBlockHistory
112
+ if maxBlockHistory < 1 {
113
+ maxBlockHistory = 1
114
+ log .Warn ("Sanitizing invalid gasprice oracle max block history" , "provided" , params .MaxBlockHistory , "updated" , maxBlockHistory )
115
+ }
116
+ if startPrice == nil {
117
+ startPrice = new (big.Int )
118
+ }
107
119
108
- cache , _ := lru .New (2048 )
120
+ cache := lru.NewCache [ cacheKey , processedFees ] (2048 )
109
121
headEvent := make (chan core.ChainHeadEvent , 1 )
110
122
backend .SubscribeChainHeadEvent (headEvent )
111
123
go func () {
@@ -120,13 +132,13 @@ func NewOracle(backend OracleBackend, params Config) *Oracle {
120
132
121
133
return & Oracle {
122
134
backend : backend ,
123
- lastPrice : params . Default ,
135
+ lastPrice : startPrice ,
124
136
maxPrice : maxPrice ,
125
137
ignorePrice : ignorePrice ,
126
138
checkBlocks : blocks ,
127
139
percentile : percent ,
128
- maxHeaderHistory : params . MaxHeaderHistory ,
129
- maxBlockHistory : params . MaxBlockHistory ,
140
+ maxHeaderHistory : maxHeaderHistory ,
141
+ maxBlockHistory : maxBlockHistory ,
130
142
historyCache : cache ,
131
143
}
132
144
}
@@ -166,7 +178,7 @@ func (oracle *Oracle) SuggestTipCap(ctx context.Context) (*big.Int, error) {
166
178
results []* big.Int
167
179
)
168
180
for sent < oracle .checkBlocks && number > 0 {
169
- go oracle .getBlockValues (ctx , types . MakeSigner ( oracle . backend . ChainConfig (), big . NewInt ( int64 ( number ))), number , sampleNumber , oracle .ignorePrice , result , quit )
181
+ go oracle .getBlockValues (ctx , number , sampleNumber , oracle .ignorePrice , result , quit )
170
182
sent ++
171
183
exp ++
172
184
number --
@@ -181,15 +193,15 @@ func (oracle *Oracle) SuggestTipCap(ctx context.Context) (*big.Int, error) {
181
193
// Nothing returned. There are two special cases here:
182
194
// - The block is empty
183
195
// - All the transactions included are sent by the miner itself.
184
- // In these cases, use the latest calculated price for samping.
196
+ // In these cases, use half of the latest calculated price for samping.
185
197
if len (res .values ) == 0 {
186
- res .values = []* big.Int {lastPrice }
198
+ res .values = []* big.Int {new (big. Int ). Div ( lastPrice , common . Big2 ) }
187
199
}
188
200
// Besides, in order to collect enough data for sampling, if nothing
189
201
// meaningful returned, try to query more blocks. But the maximum
190
202
// is 2*checkBlocks.
191
203
if len (res .values ) == 1 && len (results )+ 1 + exp < oracle .checkBlocks * 2 && number > 0 {
192
- go oracle .getBlockValues (ctx , types . MakeSigner ( oracle . backend . ChainConfig (), big . NewInt ( int64 ( number ))), number , sampleNumber , oracle .ignorePrice , result , quit )
204
+ go oracle .getBlockValues (ctx , number , sampleNumber , oracle .ignorePrice , result , quit )
193
205
sent ++
194
206
exp ++
195
207
number --
@@ -198,7 +210,7 @@ func (oracle *Oracle) SuggestTipCap(ctx context.Context) (*big.Int, error) {
198
210
}
199
211
price := lastPrice
200
212
if len (results ) > 0 {
201
- sort . Sort ( bigIntArray ( results ) )
213
+ slices . SortFunc ( results , func ( a , b * big. Int ) int { return a . Cmp ( b ) } )
202
214
price = results [(len (results )- 1 )* oracle .percentile / 100 ]
203
215
}
204
216
if price .Cmp (oracle .maxPrice ) > 0 {
@@ -226,35 +238,11 @@ type results struct {
226
238
err error
227
239
}
228
240
229
- type txSorter struct {
230
- txs []* types.Transaction
231
- baseFee * big.Int
232
- }
233
-
234
- func newSorter (txs []* types.Transaction , baseFee * big.Int ) * txSorter {
235
- return & txSorter {
236
- txs : txs ,
237
- baseFee : baseFee ,
238
- }
239
- }
240
-
241
- func (s * txSorter ) Len () int { return len (s .txs ) }
242
- func (s * txSorter ) Swap (i , j int ) {
243
- s .txs [i ], s .txs [j ] = s .txs [j ], s .txs [i ]
244
- }
245
- func (s * txSorter ) Less (i , j int ) bool {
246
- // It's okay to discard the error because a tx would never be
247
- // accepted into a block with an invalid effective tip.
248
- tip1 , _ := s .txs [i ].EffectiveGasTip (s .baseFee )
249
- tip2 , _ := s .txs [j ].EffectiveGasTip (s .baseFee )
250
- return tip1 .Cmp (tip2 ) < 0
251
- }
252
-
253
- // getBlockPrices calculates the lowest transaction gas price in a given block
241
+ // getBlockValues calculates the lowest transaction gas price in a given block
254
242
// and sends it to the result channel. If the block is empty or all transactions
255
243
// are sent by the miner itself(it doesn't make any sense to include this kind of
256
244
// transaction prices for sampling), nil gasprice is returned.
257
- func (oracle * Oracle ) getBlockValues (ctx context.Context , signer types. Signer , blockNum uint64 , limit int , ignoreUnder * big.Int , result chan results , quit chan struct {}) {
245
+ func (oracle * Oracle ) getBlockValues (ctx context.Context , blockNum uint64 , limit int , ignoreUnder * big.Int , result chan results , quit chan struct {}) {
258
246
block , err := oracle .backend .BlockByNumber (ctx , rpc .BlockNumber (blockNum ))
259
247
if block == nil {
260
248
select {
@@ -263,15 +251,24 @@ func (oracle *Oracle) getBlockValues(ctx context.Context, signer types.Signer, b
263
251
}
264
252
return
265
253
}
254
+ signer := types .MakeSigner (oracle .backend .ChainConfig (), block .Number ())
255
+
266
256
// Sort the transaction by effective tip in ascending sort.
267
- txs := make ([]* types.Transaction , len (block .Transactions ()))
268
- copy (txs , block .Transactions ())
269
- sorter := newSorter (txs , block .BaseFee ())
270
- sort .Sort (sorter )
257
+ txs := block .Transactions ()
258
+ sortedTxs := make ([]* types.Transaction , len (txs ))
259
+ copy (sortedTxs , txs )
260
+ baseFee := block .BaseFee ()
261
+ slices .SortFunc (sortedTxs , func (a , b * types.Transaction ) int {
262
+ // It's okay to discard the error because a tx would never be
263
+ // accepted into a block with an invalid effective tip.
264
+ tip1 , _ := a .EffectiveGasTip (baseFee )
265
+ tip2 , _ := b .EffectiveGasTip (baseFee )
266
+ return tip1 .Cmp (tip2 )
267
+ })
271
268
272
269
var prices []* big.Int
273
- for _ , tx := range sorter . txs {
274
- tip , _ := tx .EffectiveGasTip (block . BaseFee () )
270
+ for _ , tx := range sortedTxs {
271
+ tip , _ := tx .EffectiveGasTip (baseFee )
275
272
if ignoreUnder != nil && tip .Cmp (ignoreUnder ) == - 1 {
276
273
continue
277
274
}
@@ -288,9 +285,3 @@ func (oracle *Oracle) getBlockValues(ctx context.Context, signer types.Signer, b
288
285
case <- quit :
289
286
}
290
287
}
291
-
292
- type bigIntArray []* big.Int
293
-
294
- func (s bigIntArray ) Len () int { return len (s ) }
295
- func (s bigIntArray ) Less (i , j int ) bool { return s [i ].Cmp (s [j ]) < 0 }
296
- func (s bigIntArray ) Swap (i , j int ) { s [i ], s [j ] = s [j ], s [i ] }
0 commit comments