@@ -19,17 +19,17 @@ package gasprice
1919import (
2020 "context"
2121 "math/big"
22- "sort "
22+ "slices "
2323 "sync"
2424
2525 "github.com/XinFinOrg/XDPoSChain/common"
26+ "github.com/XinFinOrg/XDPoSChain/common/lru"
2627 "github.com/XinFinOrg/XDPoSChain/core"
2728 "github.com/XinFinOrg/XDPoSChain/core/types"
2829 "github.com/XinFinOrg/XDPoSChain/event"
2930 "github.com/XinFinOrg/XDPoSChain/log"
3031 "github.com/XinFinOrg/XDPoSChain/params"
3132 "github.com/XinFinOrg/XDPoSChain/rpc"
32- lru "github.com/hashicorp/golang-lru"
3333)
3434
3535const sampleNumber = 3 // Number of transactions sampled in a block
@@ -44,7 +44,6 @@ type Config struct {
4444 Percentile int
4545 MaxHeaderHistory uint64
4646 MaxBlockHistory uint64
47- Default * big.Int `toml:",omitempty"`
4847 MaxPrice * big.Int `toml:",omitempty"`
4948 IgnorePrice * big.Int `toml:",omitempty"`
5049}
@@ -72,12 +71,13 @@ type Oracle struct {
7271
7372 checkBlocks , percentile int
7473 maxHeaderHistory , maxBlockHistory uint64
75- historyCache * lru.Cache
74+
75+ historyCache * lru.Cache [cacheKey , processedFees ]
7676}
7777
7878// NewOracle returns a new gasprice oracle which can recommend suitable
7979// gasprice for newly created transaction.
80- func NewOracle (backend OracleBackend , params Config ) * Oracle {
80+ func NewOracle (backend OracleBackend , params Config , startPrice * big. Int ) * Oracle {
8181 blocks := params .Blocks
8282 if blocks < 1 {
8383 blocks = 1
@@ -87,8 +87,7 @@ func NewOracle(backend OracleBackend, params Config) *Oracle {
8787 if percent < 0 {
8888 percent = 0
8989 log .Warn ("Sanitizing invalid gasprice oracle sample percentile" , "provided" , params .Percentile , "updated" , percent )
90- }
91- if percent > 100 {
90+ } else if percent > 100 {
9291 percent = 100
9392 log .Warn ("Sanitizing invalid gasprice oracle sample percentile" , "provided" , params .Percentile , "updated" , percent )
9493 }
@@ -104,8 +103,21 @@ func NewOracle(backend OracleBackend, params Config) *Oracle {
104103 } else if ignorePrice .Int64 () > 0 {
105104 log .Info ("Gasprice oracle is ignoring threshold set" , "threshold" , ignorePrice )
106105 }
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+ }
107119
108- cache , _ := lru .New (2048 )
120+ cache := lru.NewCache [ cacheKey , processedFees ] (2048 )
109121 headEvent := make (chan core.ChainHeadEvent , 1 )
110122 backend .SubscribeChainHeadEvent (headEvent )
111123 go func () {
@@ -120,13 +132,13 @@ func NewOracle(backend OracleBackend, params Config) *Oracle {
120132
121133 return & Oracle {
122134 backend : backend ,
123- lastPrice : params . Default ,
135+ lastPrice : startPrice ,
124136 maxPrice : maxPrice ,
125137 ignorePrice : ignorePrice ,
126138 checkBlocks : blocks ,
127139 percentile : percent ,
128- maxHeaderHistory : params . MaxHeaderHistory ,
129- maxBlockHistory : params . MaxBlockHistory ,
140+ maxHeaderHistory : maxHeaderHistory ,
141+ maxBlockHistory : maxBlockHistory ,
130142 historyCache : cache ,
131143 }
132144}
@@ -166,7 +178,7 @@ func (oracle *Oracle) SuggestTipCap(ctx context.Context) (*big.Int, error) {
166178 results []* big.Int
167179 )
168180 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 )
170182 sent ++
171183 exp ++
172184 number --
@@ -181,15 +193,15 @@ func (oracle *Oracle) SuggestTipCap(ctx context.Context) (*big.Int, error) {
181193 // Nothing returned. There are two special cases here:
182194 // - The block is empty
183195 // - 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.
185197 if len (res .values ) == 0 {
186- res .values = []* big.Int {lastPrice }
198+ res .values = []* big.Int {new (big. Int ). Div ( lastPrice , common . Big2 ) }
187199 }
188200 // Besides, in order to collect enough data for sampling, if nothing
189201 // meaningful returned, try to query more blocks. But the maximum
190202 // is 2*checkBlocks.
191203 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 )
193205 sent ++
194206 exp ++
195207 number --
@@ -198,7 +210,7 @@ func (oracle *Oracle) SuggestTipCap(ctx context.Context) (*big.Int, error) {
198210 }
199211 price := lastPrice
200212 if len (results ) > 0 {
201- sort . Sort ( bigIntArray ( results ) )
213+ slices . SortFunc ( results , func ( a , b * big. Int ) int { return a . Cmp ( b ) } )
202214 price = results [(len (results )- 1 )* oracle .percentile / 100 ]
203215 }
204216 if price .Cmp (oracle .maxPrice ) > 0 {
@@ -226,35 +238,11 @@ type results struct {
226238 err error
227239}
228240
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
254242// and sends it to the result channel. If the block is empty or all transactions
255243// are sent by the miner itself(it doesn't make any sense to include this kind of
256244// 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 {}) {
258246 block , err := oracle .backend .BlockByNumber (ctx , rpc .BlockNumber (blockNum ))
259247 if block == nil {
260248 select {
@@ -263,15 +251,24 @@ func (oracle *Oracle) getBlockValues(ctx context.Context, signer types.Signer, b
263251 }
264252 return
265253 }
254+ signer := types .MakeSigner (oracle .backend .ChainConfig (), block .Number ())
255+
266256 // 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+ })
271268
272269 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 )
275272 if ignoreUnder != nil && tip .Cmp (ignoreUnder ) == - 1 {
276273 continue
277274 }
@@ -288,9 +285,3 @@ func (oracle *Oracle) getBlockValues(ctx context.Context, signer types.Signer, b
288285 case <- quit :
289286 }
290287}
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