@@ -72,6 +72,7 @@ type Oracle struct {
7272 lastPrice * big.Int
7373 lastBaseFee * big.Int // lastBaseFee contains next BaseFee value calculated based on the lastHead block.
7474 lastMinGasTipCap * big.Int // lastMinGasTipCap contains next MinGasTipCap value calculated based on the lastHead block.
75+ lastEnvelopeFee * big.Int // lastEnvelopeFee contains next EnvelopeFee value calculated based on the lastHead block.
7576 maxPrice * big.Int
7677 ignorePrice * big.Int
7778 cacheLock sync.RWMutex
@@ -161,6 +162,40 @@ func (oracle *Oracle) SuggestTipCap(ctx context.Context) (*big.Int, *big.Int, er
161162 return price , minGasTipCap , err
162163}
163164
165+ // EnvelopeFee returns an extra tip cap so that newly created envelope transactions
166+ // can have a very high chance to be included in the following blocks.
167+ func (oracle * Oracle ) EnvelopeFee (ctx context.Context ) (* big.Int , error ) {
168+ head , _ := oracle .backend .HeaderByNumber (ctx , rpc .LatestBlockNumber )
169+ headHash := head .Hash ()
170+
171+ // If the latest envelope fee is still available, return it.
172+ oracle .cacheLock .RLock ()
173+ lastHead , lastEnvelopeFee := oracle .lastHead , oracle .lastEnvelopeFee
174+ oracle .cacheLock .RUnlock ()
175+ if headHash == lastHead {
176+ return new (big.Int ).Set (lastEnvelopeFee ), nil
177+ }
178+ oracle .fetchLock .Lock ()
179+ defer oracle .fetchLock .Unlock ()
180+
181+ // Try checking the cache again, maybe the last fetch fetched what we need.
182+ oracle .cacheLock .RLock ()
183+ lastHead , lastPrice , lastEnvelopeFee := oracle .lastHead , oracle .lastPrice , oracle .lastEnvelopeFee
184+ oracle .cacheLock .RUnlock ()
185+ if headHash == lastHead {
186+ return new (big.Int ).Set (lastEnvelopeFee ), nil
187+ }
188+
189+ // It's a new head, then update.
190+ err := oracle .updateCache (ctx , head , lastPrice )
191+ if err != nil {
192+ return new (big.Int ).Set (lastEnvelopeFee ), err
193+ }
194+ oracle .cacheLock .RLock ()
195+ defer oracle .cacheLock .RUnlock ()
196+ return new (big.Int ).Set (oracle .lastEnvelopeFee ), nil
197+ }
198+
164199// suggestTipCapInternal return GAS price, BaseFee and minGasTipCap for the specified block.
165200// It updates the cache for the specified block height if needed. Zero BaseFee is returned if
166201// London is not active yet.
@@ -184,12 +219,35 @@ func (oracle *Oracle) suggestTipCapInternal(ctx context.Context, head *types.Hea
184219 if headHash == lastHead {
185220 return new (big.Int ).Set (lastPrice ), new (big.Int ).Set (lastBaseFee ), new (big.Int ).Set (lastMinGasTipCap ), nil
186221 }
222+
223+ // It's a new head, then update.
224+ err := oracle .updateCache (ctx , head , lastPrice )
225+ if err != nil {
226+ return new (big.Int ).Set (lastPrice ), new (big.Int ).Set (lastBaseFee ), new (big.Int ).Set (lastMinGasTipCap ), err
227+ }
228+ oracle .cacheLock .RLock ()
229+ defer oracle .cacheLock .RUnlock ()
230+ return new (big.Int ).Set (oracle .lastPrice ), new (big.Int ).Set (oracle .lastBaseFee ), new (big.Int ).Set (oracle .lastMinGasTipCap ), nil
231+ }
232+
233+ type results struct {
234+ values []* big.Int
235+ err error
236+ }
237+
238+ // updateCache updates the cache for the specified block height.
239+ func (oracle * Oracle ) updateCache (ctx context.Context , head * types.Header , lastPrice * big.Int ) error {
240+ headHash := head .Hash ()
187241 var (
188- sent , exp int
189- number = head .Number .Uint64 ()
190- result = make (chan results , oracle .checkBlocks )
191- quit = make (chan struct {})
192- results []* big.Int
242+ state * state.StateDB
243+ sent , exp int
244+ number = head .Number .Uint64 ()
245+ result = make (chan results , oracle .checkBlocks )
246+ quit = make (chan struct {})
247+ results []* big.Int
248+ lastBaseFee * big.Int
249+ lastMinGasTipCap * big.Int
250+ lastEnvelopeFee * big.Int
193251 )
194252 for sent < oracle .checkBlocks && number > 0 {
195253 go oracle .getBlockValues (ctx , number , sampleNumber , oracle .ignorePrice , result , quit )
@@ -201,7 +259,7 @@ func (oracle *Oracle) suggestTipCapInternal(ctx context.Context, head *types.Hea
201259 res := <- result
202260 if res .err != nil {
203261 close (quit )
204- return new (big. Int ). Set ( lastPrice ), new (big. Int ). Set ( lastBaseFee ), new (big. Int ). Set ( lastMinGasTipCap ), res .err
262+ return res .err
205263 }
206264 exp --
207265 // Nothing returned. There are two special cases here:
@@ -231,9 +289,10 @@ func (oracle *Oracle) suggestTipCapInternal(ctx context.Context, head *types.Hea
231289 price = new (big.Int ).Set (oracle .maxPrice )
232290 }
233291 if cfg := oracle .backend .ChainConfig (); cfg .IsLondon (head .Number ) {
234- state , _ , err := oracle .backend .StateAndHeaderByNumber (ctx , rpc .BlockNumber (head .Number .Uint64 ()))
292+ var err error
293+ state , _ , err = oracle .backend .StateAndHeaderByNumber (ctx , rpc .BlockNumber (head .Number .Uint64 ()))
235294 if err != nil {
236- return nil , nil , nil , fmt .Errorf ("failed to get state at %d to calculate base fee: %w" , head .Number .Uint64 (), err )
295+ return fmt .Errorf ("failed to get state at %d to calculate base fee: %w" , head .Number .Uint64 (), err )
237296 }
238297 lastBaseFee = eip1559 .CalcBaseFeeDBFT (cfg , head , state )
239298 if cfg .DBFT != nil {
@@ -245,19 +304,31 @@ func (oracle *Oracle) suggestTipCapInternal(ctx context.Context, head *types.Hea
245304 lastBaseFee = new (big.Int )
246305 lastMinGasTipCap = new (big.Int )
247306 }
307+ if cfg := oracle .backend .ChainConfig (); cfg .IsNeoXAMEV (head .Number ) {
308+ if cfg .DBFT != nil {
309+ if state == nil {
310+ var err error
311+ state , _ , err = oracle .backend .StateAndHeaderByNumber (ctx , rpc .BlockNumber (head .Number .Uint64 ()))
312+ if err != nil {
313+ return fmt .Errorf ("failed to get state at %d to get envelope fee: %w" , head .Number .Uint64 (), err )
314+ }
315+ }
316+ lastEnvelopeFee = state .GetState (systemcontracts .PolicyProxyHash , systemcontracts .GetEnvelopeFeeStateHash ()).Big ()
317+ } else {
318+ lastEnvelopeFee = new (big.Int )
319+ }
320+ } else {
321+ lastEnvelopeFee = new (big.Int )
322+ }
248323 oracle .cacheLock .Lock ()
249324 oracle .lastHead = headHash
250325 oracle .lastPrice = price
251326 oracle .lastBaseFee = lastBaseFee
252327 oracle .lastMinGasTipCap = lastMinGasTipCap
328+ oracle .lastEnvelopeFee = lastEnvelopeFee
253329 oracle .cacheLock .Unlock ()
254330
255- return new (big.Int ).Set (price ), new (big.Int ).Set (lastBaseFee ), new (big.Int ).Set (lastMinGasTipCap ), nil
256- }
257-
258- type results struct {
259- values []* big.Int
260- err error
331+ return nil
261332}
262333
263334// getBlockValues calculates the lowest transaction gas price in a given block
0 commit comments