Skip to content

Commit 3a2f7f5

Browse files
committed
eth: internal: add eth_envelopeFee API
1 parent 480763d commit 3a2f7f5

File tree

7 files changed

+115
-14
lines changed

7 files changed

+115
-14
lines changed

eth/api_backend.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -377,6 +377,10 @@ func (b *EthAPIBackend) SuggestGasTipCap(ctx context.Context) (*big.Int, error)
377377
return suggestTipCap, nil
378378
}
379379

380+
func (b *EthAPIBackend) EnvelopeFee(ctx context.Context) (*big.Int, error) {
381+
return b.gpo.EnvelopeFee(ctx)
382+
}
383+
380384
func (b *EthAPIBackend) FeeHistory(ctx context.Context, blockCount uint64, lastBlock rpc.BlockNumber, rewardPercentiles []float64) (firstBlock *big.Int, reward [][]*big.Int, baseFee []*big.Int, gasUsedRatio []float64, err error) {
381385
return b.gpo.FeeHistory(ctx, blockCount, lastBlock, rewardPercentiles)
382386
}

eth/gasprice/gasprice.go

Lines changed: 85 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -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

ethclient/ethclient.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -567,6 +567,16 @@ func (ec *Client) SuggestGasTipCap(ctx context.Context) (*big.Int, error) {
567567
return (*big.Int)(&hex), nil
568568
}
569569

570+
// EnvelopeFee retrieves the currently envelope fee after NeoXAMEV to allow a
571+
// timely execution of an antimev envelope.
572+
func (ec *Client) EnvelopeFee(ctx context.Context) (*big.Int, error) {
573+
var hex hexutil.Big
574+
if err := ec.c.CallContext(ctx, &hex, "eth_envelopeFee"); err != nil {
575+
return nil, err
576+
}
577+
return (*big.Int)(&hex), nil
578+
}
579+
570580
type feeHistoryResultMarshaling struct {
571581
OldestBlock *hexutil.Big `json:"oldestBlock"`
572582
Reward [][]*hexutil.Big `json:"reward,omitempty"`

internal/ethapi/api.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,15 @@ func (s *EthereumAPI) MaxPriorityFeePerGas(ctx context.Context) (*hexutil.Big, e
9595
return (*hexutil.Big)(tipcap), err
9696
}
9797

98+
// EnvelopeFee returns a suggestion for an extra gas tip cap for envelope transactions.
99+
func (s *EthereumAPI) EnvelopeFee(ctx context.Context) (*hexutil.Big, error) {
100+
fee, err := s.b.EnvelopeFee(ctx)
101+
if err != nil {
102+
return nil, err
103+
}
104+
return (*hexutil.Big)(fee), err
105+
}
106+
98107
type feeHistoryResult struct {
99108
OldestBlock *hexutil.Big `json:"oldestBlock"`
100109
Reward [][]*hexutil.Big `json:"reward,omitempty"`

internal/ethapi/api_test.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -468,6 +468,9 @@ func (b testBackend) SyncProgress() ethereum.SyncProgress { return ethereum.Sync
468468
func (b testBackend) SuggestGasTipCap(ctx context.Context) (*big.Int, error) {
469469
return big.NewInt(0), nil
470470
}
471+
func (b testBackend) EnvelopeFee(ctx context.Context) (*big.Int, error) {
472+
return big.NewInt(0), nil
473+
}
471474
func (b testBackend) FeeHistory(ctx context.Context, blockCount uint64, lastBlock rpc.BlockNumber, rewardPercentiles []float64) (*big.Int, [][]*big.Int, []*big.Int, []float64, error) {
472475
return nil, nil, nil, nil, nil
473476
}

internal/ethapi/backend.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ type Backend interface {
4444
SyncProgress() ethereum.SyncProgress
4545

4646
SuggestGasTipCap(ctx context.Context) (*big.Int, error)
47+
EnvelopeFee(ctx context.Context) (*big.Int, error)
4748
FeeHistory(ctx context.Context, blockCount uint64, lastBlock rpc.BlockNumber, rewardPercentiles []float64) (*big.Int, [][]*big.Int, []*big.Int, []float64, error)
4849
ChainDb() ethdb.Database
4950
AccountManager() *accounts.Manager

internal/ethapi/transaction_args_test.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,9 @@ func (b *backendMock) setFork(fork string) error {
314314
func (b *backendMock) SuggestGasTipCap(ctx context.Context) (*big.Int, error) {
315315
return big.NewInt(42), nil
316316
}
317+
func (b *backendMock) EnvelopeFee(ctx context.Context) (*big.Int, error) {
318+
return big.NewInt(42), nil
319+
}
317320
func (b *backendMock) CurrentHeader() *types.Header { return b.current }
318321
func (b *backendMock) ChainConfig() *params.ChainConfig { return b.config }
319322

0 commit comments

Comments
 (0)