Skip to content

Commit

Permalink
FeeHistory estimator (#13833)
Browse files Browse the repository at this point in the history
* Introduce universal estimator

* Fixes

* Use WeiMin to cap bump price

* Update connectivity logic

* Fix error

* Fixes

* Cover an edge case when enforcing limits

* Add changeset

* Update mempool check logic

* Update config names

* Convert Universal Estimator to service

* Client changes to support UE

* Introduce configs

* Update mocks

* Fix lint

* Fix test cases

* Fix mockery

* Fix test cases

* Update comment

* Fix Start/Close sync issue

* Address feedback

* Fix lint

* Fix lint

* More changes

* Add more comments

* Fix merge conflicts

* Update CONFIG

* Rename to FeeHistory estimator

* Rename

* Exclude zero priced priority fees

* Remove HasMempool

* Remove testing commit

* Fixes

* Add DefaultJitter

* Add optimizations

* Fix testscripts

* Fix name

* Update error messages
  • Loading branch information
dimriou authored Sep 4, 2024
1 parent a234e14 commit 1ea9f79
Show file tree
Hide file tree
Showing 36 changed files with 1,778 additions and 2 deletions.
5 changes: 5 additions & 0 deletions .changeset/shiny-hornets-pretend.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"chainlink": minor
---

Introduce new gas estimator #internal
3 changes: 3 additions & 0 deletions .mockery.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,9 @@ packages:
feeEstimatorClient:
config:
mockname: FeeEstimatorClient
feeHistoryEstimatorClient:
config:
mockname: FeeHistoryEstimatorClient
EvmEstimator:
github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas/rollups:
interfaces:
Expand Down
2 changes: 1 addition & 1 deletion common/fee/models.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ func CalculateBumpedFee(
// Returns highest bumped fee price of originalFeePrice bumped by fixed units or percentage.
func MaxBumpedFee(originalFeePrice *big.Int, feeBumpPercent uint16, feeBumpUnits *big.Int) *big.Int {
return bigmath.Max(
addPercentage(originalFeePrice, feeBumpPercent),
AddPercentage(originalFeePrice, feeBumpPercent),
new(big.Int).Add(originalFeePrice, feeBumpUnits),
)
}
Expand Down
2 changes: 1 addition & 1 deletion common/fee/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ func ApplyMultiplier(feeLimit uint64, multiplier float32) (uint64, error) {
}

// Returns the input value increased by the given percentage.
func addPercentage(value *big.Int, percentage uint16) *big.Int {
func AddPercentage(value *big.Int, percentage uint16) *big.Int {
bumped := new(big.Int)
bumped.Mul(value, big.NewInt(int64(100+percentage)))
bumped.Div(bumped, big.NewInt(100))
Expand Down
8 changes: 8 additions & 0 deletions core/capabilities/ccip/ocrimpls/contract_transmitter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -591,6 +591,10 @@ func (g *TestGasEstimatorConfig) BlockHistory() evmconfig.BlockHistory {
return &TestBlockHistoryConfig{}
}

func (g *TestGasEstimatorConfig) FeeHistory() evmconfig.FeeHistory {
return &TestFeeHistoryConfig{}
}

func (g *TestGasEstimatorConfig) EIP1559DynamicFees() bool { return false }
func (g *TestGasEstimatorConfig) LimitDefault() uint64 { return 1e6 }
func (g *TestGasEstimatorConfig) BumpPercent() uint16 { return 2 }
Expand Down Expand Up @@ -639,6 +643,10 @@ func (b *TestBlockHistoryConfig) BlockHistorySize() uint16 { return 42
func (b *TestBlockHistoryConfig) EIP1559FeeCapBufferBlocks() uint16 { return 42 }
func (b *TestBlockHistoryConfig) TransactionPercentile() uint16 { return 42 }

type TestFeeHistoryConfig struct {
evmconfig.FeeHistory
}

type transactionsConfig struct {
evmconfig.Transactions
e *TestEvmConfig
Expand Down
9 changes: 9 additions & 0 deletions core/chains/evm/client/chain_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ type Client interface {
SuggestGasPrice(ctx context.Context) (*big.Int, error)
SuggestGasTipCap(ctx context.Context) (*big.Int, error)
LatestBlockHeight(ctx context.Context) (*big.Int, error)
FeeHistory(ctx context.Context, blockCount uint64, rewardPercentiles []float64) (feeHistory *ethereum.FeeHistory, err error)

HeaderByNumber(ctx context.Context, n *big.Int) (*types.Header, error)
HeaderByHash(ctx context.Context, h common.Hash) (*types.Header, error)
Expand Down Expand Up @@ -353,6 +354,14 @@ func (c *chainClient) LatestFinalizedBlock(ctx context.Context) (*evmtypes.Head,
return c.multiNode.LatestFinalizedBlock(ctx)
}

func (c *chainClient) FeeHistory(ctx context.Context, blockCount uint64, rewardPercentiles []float64) (feeHistory *ethereum.FeeHistory, err error) {
rpc, err := c.multiNode.SelectNodeRPC()
if err != nil {
return feeHistory, err
}
return rpc.FeeHistory(ctx, blockCount, rewardPercentiles)
}

func (c *chainClient) CheckTxValidity(ctx context.Context, from common.Address, to common.Address, data []byte) *SendError {
msg := ethereum.CallMsg{
From: from,
Expand Down
60 changes: 60 additions & 0 deletions core/chains/evm/client/mocks/client.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

60 changes: 60 additions & 0 deletions core/chains/evm/client/mocks/rpc_client.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions core/chains/evm/client/null_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -235,3 +235,7 @@ func (nc *NullClient) LatestFinalizedBlock(_ context.Context) (*evmtypes.Head, e
func (nc *NullClient) CheckTxValidity(_ context.Context, _ common.Address, _ common.Address, _ []byte) *SendError {
return nil
}

func (nc *NullClient) FeeHistory(ctx context.Context, blockCount uint64, rewardPercentiles []float64) (feeHistory *ethereum.FeeHistory, err error) {
return nil, nil
}
25 changes: 25 additions & 0 deletions core/chains/evm/client/rpc_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ type RPCClient interface {
SuggestGasTipCap(ctx context.Context) (t *big.Int, err error)
TransactionReceiptGeth(ctx context.Context, txHash common.Hash) (r *types.Receipt, err error)
GetInterceptedChainInfo() (latest, highestUserObservations commonclient.ChainInfo)
FeeHistory(ctx context.Context, blockCount uint64, rewardPercentiles []float64) (feeHistory *ethereum.FeeHistory, err error)
}

const rpcSubscriptionMethodNewHeads = "newHeads"
Expand Down Expand Up @@ -599,6 +600,7 @@ func (r *rpcClient) TransactionReceiptGeth(ctx context.Context, txHash common.Ha

return
}

func (r *rpcClient) TransactionByHash(ctx context.Context, txHash common.Hash) (tx *types.Transaction, err error) {
ctx, cancel, ws, http := r.makeLiveQueryCtxAndSafeGetClients(ctx, r.rpcTimeout)
defer cancel()
Expand Down Expand Up @@ -1119,6 +1121,29 @@ func (r *rpcClient) BalanceAt(ctx context.Context, account common.Address, block
return
}

func (r *rpcClient) FeeHistory(ctx context.Context, blockCount uint64, rewardPercentiles []float64) (feeHistory *ethereum.FeeHistory, err error) {
ctx, cancel, ws, http := r.makeLiveQueryCtxAndSafeGetClients(ctx, r.rpcTimeout)
defer cancel()
lggr := r.newRqLggr().With("blockCount", blockCount, "rewardPercentiles", rewardPercentiles)

lggr.Debug("RPC call: evmclient.Client#FeeHistory")
start := time.Now()
if http != nil {
feeHistory, err = http.geth.FeeHistory(ctx, blockCount, nil, rewardPercentiles)
err = r.wrapHTTP(err)
} else {
feeHistory, err = ws.geth.FeeHistory(ctx, blockCount, nil, rewardPercentiles)
err = r.wrapWS(err)
}
duration := time.Since(start)

r.logResult(lggr, err, duration, r.getRPCDomain(), "FeeHistory",
"feeHistory", feeHistory,
)

return
}

// CallArgs represents the data used to call the balance method of a contract.
// "To" is the address of the ERC contract. "Data" is the message sent
// to the contract. "From" is the sender address.
Expand Down
4 changes: 4 additions & 0 deletions core/chains/evm/client/simulated_backend_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,10 @@ func (c *SimulatedBackendClient) LINKBalance(ctx context.Context, address common
panic("not implemented")
}

func (c *SimulatedBackendClient) FeeHistory(ctx context.Context, blockCount uint64, rewardPercentiles []float64) (feeHistory *ethereum.FeeHistory, err error) {
panic("not implemented")
}

// TransactionReceipt returns the transaction receipt for the given transaction hash.
func (c *SimulatedBackendClient) TransactionReceipt(ctx context.Context, receipt common.Hash) (*types.Receipt, error) {
return c.b.TransactionReceipt(ctx, receipt)
Expand Down
14 changes: 14 additions & 0 deletions core/chains/evm/config/chain_scoped_gas_estimator.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package config

import (
"time"

gethcommon "github.com/ethereum/go-ethereum/common"

"github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets"
Expand Down Expand Up @@ -36,6 +38,10 @@ func (g *gasEstimatorConfig) BlockHistory() BlockHistory {
return &blockHistoryConfig{c: g.c.BlockHistory, blockDelay: g.blockDelay, bumpThreshold: g.c.BumpThreshold}
}

func (g *gasEstimatorConfig) FeeHistory() FeeHistory {
return &feeHistoryConfig{c: g.c.FeeHistory}
}

func (g *gasEstimatorConfig) EIP1559DynamicFees() bool {
return *g.c.EIP1559DynamicFees
}
Expand Down Expand Up @@ -176,3 +182,11 @@ func (b *blockHistoryConfig) TransactionPercentile() uint16 {
func (b *blockHistoryConfig) BlockDelay() uint16 {
return *b.blockDelay
}

type feeHistoryConfig struct {
c toml.FeeHistoryEstimator
}

func (u *feeHistoryConfig) CacheTimeout() time.Duration {
return u.c.CacheTimeout.Duration()
}
5 changes: 5 additions & 0 deletions core/chains/evm/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ type AutoPurgeConfig interface {

type GasEstimator interface {
BlockHistory() BlockHistory
FeeHistory() FeeHistory
LimitJobType() LimitJobType

EIP1559DynamicFees() bool
Expand Down Expand Up @@ -159,6 +160,10 @@ type BlockHistory interface {
TransactionPercentile() uint16
}

type FeeHistory interface {
CacheTimeout() time.Duration
}

type Workflow interface {
FromAddress() *types.EIP55Address
ForwarderAddress() *types.EIP55Address
Expand Down
7 changes: 7 additions & 0 deletions core/chains/evm/config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,13 @@ func TestChainScopedConfig_BlockHistory(t *testing.T) {
assert.Equal(t, uint16(1), bh.BlockDelay())
assert.Equal(t, uint16(4), bh.EIP1559FeeCapBufferBlocks())
}
func TestChainScopedConfig_FeeHistory(t *testing.T) {
t.Parallel()
cfg := testutils.NewTestChainScopedConfig(t, nil)

u := cfg.EVM().GasEstimator().FeeHistory()
assert.Equal(t, 10*time.Second, u.CacheTimeout())
}

func TestChainScopedConfig_GasEstimator(t *testing.T) {
t.Parallel()
Expand Down
47 changes: 47 additions & 0 deletions core/chains/evm/config/mocks/gas_estimator.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 1ea9f79

Please sign in to comment.