From ea29e8f8c9428fa67cbd3d92ea0bf491cbf514c5 Mon Sep 17 00:00:00 2001 From: george-dorin <120329946+george-dorin@users.noreply.github.com> Date: Mon, 10 Jul 2023 17:24:53 +0300 Subject: [PATCH] Move KeySpecific field (#9694) * Move KeySpecific field * Fix test * Fix test * Change KeySpecificMaxPrice to MaxPriceKey * Change MaxPriceKey to PriceMaxKey --- core/chains/evm/config/config.go | 3 +- core/chains/evm/config/config_test.go | 18 +- core/chains/evm/config/mocks/gas_estimator.go | 318 ++++++++++++++++++ core/chains/evm/config/v2/chain_scoped.go | 21 +- .../config/v2/chain_scoped_gas_estimator.go | 21 ++ core/chains/evm/txmgr/attempts.go | 30 +- core/chains/evm/txmgr/attempts_test.go | 39 +-- core/chains/evm/txmgr/broadcaster_test.go | 16 +- core/chains/evm/txmgr/builder.go | 2 +- core/chains/evm/txmgr/config.go | 4 +- core/chains/evm/txmgr/confirmer_test.go | 37 +- core/chains/evm/txmgr/mocks/config.go | 20 -- core/chains/evm/txmgr/txmgr_test.go | 12 +- core/cmd/shell_local.go | 2 +- core/internal/cltest/cltest.go | 2 +- core/services/vrf/delegate.go | 6 +- core/services/vrf/delegate_test.go | 44 +-- core/services/vrf/listener_v2.go | 8 +- core/services/vrf/mocks/config.go | 23 +- core/web/eth_keys_controller.go | 2 +- core/web/evm_transfer_controller.go | 2 +- core/web/resolver/eth_key.go | 2 +- core/web/resolver/eth_key_test.go | 20 +- 23 files changed, 470 insertions(+), 182 deletions(-) create mode 100644 core/chains/evm/config/mocks/gas_estimator.go diff --git a/core/chains/evm/config/config.go b/core/chains/evm/config/config.go index 398bc1cc394..4c04d992f99 100644 --- a/core/chains/evm/config/config.go +++ b/core/chains/evm/config/config.go @@ -27,7 +27,6 @@ type EVM interface { ChainType() config.ChainType FinalityDepth() uint32 FlagsContractAddress() string - KeySpecificMaxGasPriceWei(addr gethcommon.Address) *assets.Wei LinkContractAddress() string LogBackfillBatchSize() uint32 LogKeepBlocksDepth() uint32 @@ -74,6 +73,7 @@ type Transactions interface { MaxQueued() uint64 } +//go:generate mockery --quiet --name GasEstimator --output ./mocks/ --case=underscore type GasEstimator interface { BlockHistory() BlockHistory LimitJobType() LimitJobType @@ -94,6 +94,7 @@ type GasEstimator interface { PriceMax() *assets.Wei PriceMin() *assets.Wei Mode() string + PriceMaxKey(gethcommon.Address) *assets.Wei } type LimitJobType interface { diff --git a/core/chains/evm/config/config_test.go b/core/chains/evm/config/config_test.go index 4f2bd5fa529..9483897b952 100644 --- a/core/chains/evm/config/config_test.go +++ b/core/chains/evm/config/config_test.go @@ -81,7 +81,7 @@ func TestChainScopedConfig(t *testing.T) { }) }) - t.Run("KeySpecificMaxGasPriceWei", func(t *testing.T) { + t.Run("PriceMaxKey", func(t *testing.T) { addr := testutils.NewAddress() randomOtherAddr := testutils.NewAddress() gcfg2 := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { @@ -97,7 +97,7 @@ func TestChainScopedConfig(t *testing.T) { cfg2 := evmtest.NewChainScopedConfig(t, gcfg2) t.Run("uses chain-specific default value when nothing is set", func(t *testing.T) { - assert.Equal(t, assets.NewWeiI(100000000000000), cfg2.EVM().KeySpecificMaxGasPriceWei(addr)) + assert.Equal(t, assets.NewWeiI(100000000000000), cfg2.EVM().GasEstimator().PriceMaxKey(addr)) }) t.Run("uses chain-specific override value when that is set", func(t *testing.T) { @@ -107,7 +107,7 @@ func TestChainScopedConfig(t *testing.T) { }) cfg3 := evmtest.NewChainScopedConfig(t, gcfg3) - assert.Equal(t, val.String(), cfg3.EVM().KeySpecificMaxGasPriceWei(addr).String()) + assert.Equal(t, val.String(), cfg3.EVM().GasEstimator().PriceMaxKey(addr).String()) }) t.Run("uses key-specific override value when set", func(t *testing.T) { val := assets.GWei(250) @@ -122,7 +122,7 @@ func TestChainScopedConfig(t *testing.T) { }) cfg3 := evmtest.NewChainScopedConfig(t, gcfg3) - assert.Equal(t, val.String(), cfg3.EVM().KeySpecificMaxGasPriceWei(addr).String()) + assert.Equal(t, val.String(), cfg3.EVM().GasEstimator().PriceMaxKey(addr).String()) }) t.Run("uses key-specific override value when set and lower than chain specific config", func(t *testing.T) { keySpecificPrice := assets.GWei(900) @@ -139,7 +139,7 @@ func TestChainScopedConfig(t *testing.T) { }) cfg3 := evmtest.NewChainScopedConfig(t, gcfg3) - assert.Equal(t, keySpecificPrice.String(), cfg3.EVM().KeySpecificMaxGasPriceWei(addr).String()) + assert.Equal(t, keySpecificPrice.String(), cfg3.EVM().GasEstimator().PriceMaxKey(addr).String()) }) t.Run("uses chain-specific value when higher than key-specific value", func(t *testing.T) { keySpecificPrice := assets.GWei(1400) @@ -156,7 +156,7 @@ func TestChainScopedConfig(t *testing.T) { }) cfg3 := evmtest.NewChainScopedConfig(t, gcfg3) - assert.Equal(t, chainSpecificPrice.String(), cfg3.EVM().KeySpecificMaxGasPriceWei(addr).String()) + assert.Equal(t, chainSpecificPrice.String(), cfg3.EVM().GasEstimator().PriceMaxKey(addr).String()) }) t.Run("uses key-specific override value when set and lower than global config", func(t *testing.T) { keySpecificPrice := assets.GWei(900) @@ -171,7 +171,7 @@ func TestChainScopedConfig(t *testing.T) { }) cfg3 := evmtest.NewChainScopedConfig(t, gcfg3) - assert.Equal(t, keySpecificPrice.String(), cfg3.EVM().KeySpecificMaxGasPriceWei(addr).String()) + assert.Equal(t, keySpecificPrice.String(), cfg3.EVM().GasEstimator().PriceMaxKey(addr).String()) }) t.Run("uses global value when higher than key-specific value", func(t *testing.T) { keySpecificPrice := assets.GWei(1400) @@ -188,7 +188,7 @@ func TestChainScopedConfig(t *testing.T) { }) cfg3 := evmtest.NewChainScopedConfig(t, gcfg3) - assert.Equal(t, chainSpecificPrice.String(), cfg3.EVM().KeySpecificMaxGasPriceWei(addr).String()) + assert.Equal(t, chainSpecificPrice.String(), cfg3.EVM().GasEstimator().PriceMaxKey(addr).String()) }) t.Run("uses global value when there is no key-specific price", func(t *testing.T) { val := assets.NewWeiI(rand.Int63()) @@ -198,7 +198,7 @@ func TestChainScopedConfig(t *testing.T) { }) cfg3 := evmtest.NewChainScopedConfig(t, gcfg3) - assert.Equal(t, val.String(), cfg3.EVM().KeySpecificMaxGasPriceWei(unsetAddr).String()) + assert.Equal(t, val.String(), cfg3.EVM().GasEstimator().PriceMaxKey(unsetAddr).String()) }) }) diff --git a/core/chains/evm/config/mocks/gas_estimator.go b/core/chains/evm/config/mocks/gas_estimator.go new file mode 100644 index 00000000000..0788370d3cc --- /dev/null +++ b/core/chains/evm/config/mocks/gas_estimator.go @@ -0,0 +1,318 @@ +// Code generated by mockery v2.28.1. DO NOT EDIT. + +package mocks + +import ( + common "github.com/ethereum/go-ethereum/common" + assets "github.com/smartcontractkit/chainlink/v2/core/assets" + + config "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config" + + mock "github.com/stretchr/testify/mock" +) + +// GasEstimator is an autogenerated mock type for the GasEstimator type +type GasEstimator struct { + mock.Mock +} + +// BlockHistory provides a mock function with given fields: +func (_m *GasEstimator) BlockHistory() config.BlockHistory { + ret := _m.Called() + + var r0 config.BlockHistory + if rf, ok := ret.Get(0).(func() config.BlockHistory); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(config.BlockHistory) + } + } + + return r0 +} + +// BumpMin provides a mock function with given fields: +func (_m *GasEstimator) BumpMin() *assets.Wei { + ret := _m.Called() + + var r0 *assets.Wei + if rf, ok := ret.Get(0).(func() *assets.Wei); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*assets.Wei) + } + } + + return r0 +} + +// BumpPercent provides a mock function with given fields: +func (_m *GasEstimator) BumpPercent() uint16 { + ret := _m.Called() + + var r0 uint16 + if rf, ok := ret.Get(0).(func() uint16); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(uint16) + } + + return r0 +} + +// BumpThreshold provides a mock function with given fields: +func (_m *GasEstimator) BumpThreshold() uint64 { + ret := _m.Called() + + var r0 uint64 + if rf, ok := ret.Get(0).(func() uint64); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(uint64) + } + + return r0 +} + +// BumpTxDepth provides a mock function with given fields: +func (_m *GasEstimator) BumpTxDepth() uint32 { + ret := _m.Called() + + var r0 uint32 + if rf, ok := ret.Get(0).(func() uint32); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(uint32) + } + + return r0 +} + +// EIP1559DynamicFees provides a mock function with given fields: +func (_m *GasEstimator) EIP1559DynamicFees() bool { + ret := _m.Called() + + var r0 bool + if rf, ok := ret.Get(0).(func() bool); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(bool) + } + + return r0 +} + +// FeeCapDefault provides a mock function with given fields: +func (_m *GasEstimator) FeeCapDefault() *assets.Wei { + ret := _m.Called() + + var r0 *assets.Wei + if rf, ok := ret.Get(0).(func() *assets.Wei); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*assets.Wei) + } + } + + return r0 +} + +// LimitDefault provides a mock function with given fields: +func (_m *GasEstimator) LimitDefault() uint32 { + ret := _m.Called() + + var r0 uint32 + if rf, ok := ret.Get(0).(func() uint32); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(uint32) + } + + return r0 +} + +// LimitJobType provides a mock function with given fields: +func (_m *GasEstimator) LimitJobType() config.LimitJobType { + ret := _m.Called() + + var r0 config.LimitJobType + if rf, ok := ret.Get(0).(func() config.LimitJobType); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(config.LimitJobType) + } + } + + return r0 +} + +// LimitMax provides a mock function with given fields: +func (_m *GasEstimator) LimitMax() uint32 { + ret := _m.Called() + + var r0 uint32 + if rf, ok := ret.Get(0).(func() uint32); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(uint32) + } + + return r0 +} + +// LimitMultiplier provides a mock function with given fields: +func (_m *GasEstimator) LimitMultiplier() float32 { + ret := _m.Called() + + var r0 float32 + if rf, ok := ret.Get(0).(func() float32); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(float32) + } + + return r0 +} + +// LimitTransfer provides a mock function with given fields: +func (_m *GasEstimator) LimitTransfer() uint32 { + ret := _m.Called() + + var r0 uint32 + if rf, ok := ret.Get(0).(func() uint32); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(uint32) + } + + return r0 +} + +// Mode provides a mock function with given fields: +func (_m *GasEstimator) Mode() string { + ret := _m.Called() + + var r0 string + if rf, ok := ret.Get(0).(func() string); ok { + r0 = rf() + } else { + r0 = ret.Get(0).(string) + } + + return r0 +} + +// PriceDefault provides a mock function with given fields: +func (_m *GasEstimator) PriceDefault() *assets.Wei { + ret := _m.Called() + + var r0 *assets.Wei + if rf, ok := ret.Get(0).(func() *assets.Wei); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*assets.Wei) + } + } + + return r0 +} + +// PriceMax provides a mock function with given fields: +func (_m *GasEstimator) PriceMax() *assets.Wei { + ret := _m.Called() + + var r0 *assets.Wei + if rf, ok := ret.Get(0).(func() *assets.Wei); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*assets.Wei) + } + } + + return r0 +} + +// PriceMaxKey provides a mock function with given fields: _a0 +func (_m *GasEstimator) PriceMaxKey(_a0 common.Address) *assets.Wei { + ret := _m.Called(_a0) + + var r0 *assets.Wei + if rf, ok := ret.Get(0).(func(common.Address) *assets.Wei); ok { + r0 = rf(_a0) + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*assets.Wei) + } + } + + return r0 +} + +// PriceMin provides a mock function with given fields: +func (_m *GasEstimator) PriceMin() *assets.Wei { + ret := _m.Called() + + var r0 *assets.Wei + if rf, ok := ret.Get(0).(func() *assets.Wei); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*assets.Wei) + } + } + + return r0 +} + +// TipCapDefault provides a mock function with given fields: +func (_m *GasEstimator) TipCapDefault() *assets.Wei { + ret := _m.Called() + + var r0 *assets.Wei + if rf, ok := ret.Get(0).(func() *assets.Wei); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*assets.Wei) + } + } + + return r0 +} + +// TipCapMin provides a mock function with given fields: +func (_m *GasEstimator) TipCapMin() *assets.Wei { + ret := _m.Called() + + var r0 *assets.Wei + if rf, ok := ret.Get(0).(func() *assets.Wei); ok { + r0 = rf() + } else { + if ret.Get(0) != nil { + r0 = ret.Get(0).(*assets.Wei) + } + } + + return r0 +} + +type mockConstructorTestingTNewGasEstimator interface { + mock.TestingT + Cleanup(func()) +} + +// NewGasEstimator creates a new instance of GasEstimator. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. +func NewGasEstimator(t mockConstructorTestingTNewGasEstimator) *GasEstimator { + mock := &GasEstimator{} + mock.Mock.Test(t) + + t.Cleanup(func() { mock.AssertExpectations(t) }) + + return mock +} diff --git a/core/chains/evm/config/v2/chain_scoped.go b/core/chains/evm/config/v2/chain_scoped.go index 690d0b24b67..db4b141c396 100644 --- a/core/chains/evm/config/v2/chain_scoped.go +++ b/core/chains/evm/config/v2/chain_scoped.go @@ -4,7 +4,6 @@ import ( "math/big" "time" - "github.com/ethereum/go-ethereum/common" "go.uber.org/multierr" ocr "github.com/smartcontractkit/libocr/offchainreporting" @@ -71,7 +70,7 @@ func (e *evmConfig) OCR2() config.OCR2 { } func (e *evmConfig) GasEstimator() config.GasEstimator { - return &gasEstimatorConfig{c: e.c.GasEstimator, blockDelay: e.c.RPCBlockQueryDelay, transactionsMaxInFlight: e.c.Transactions.MaxInFlight} + return &gasEstimatorConfig{c: e.c.GasEstimator, blockDelay: e.c.RPCBlockQueryDelay, transactionsMaxInFlight: e.c.Transactions.MaxInFlight, k: e.c.KeySpecific} } func (e *evmConfig) AutoCreateKey() bool { @@ -125,24 +124,6 @@ func (e *evmConfig) ChainID() *big.Int { return e.c.ChainID.ToInt() } -func (e *evmConfig) KeySpecificMaxGasPriceWei(addr common.Address) *assets.Wei { - var keySpecific *assets.Wei - for i := range e.c.KeySpecific { - ks := e.c.KeySpecific[i] - if ks.Key.Address() == addr { - keySpecific = ks.GasEstimator.PriceMax - break - } - } - - chainSpecific := e.GasEstimator().PriceMax() - if keySpecific != nil && !keySpecific.IsZero() && keySpecific.Cmp(chainSpecific) < 0 { - return keySpecific - } - - return e.GasEstimator().PriceMax() -} - func (e *evmConfig) MinIncomingConfirmations() uint32 { return *e.c.MinIncomingConfirmations } diff --git a/core/chains/evm/config/v2/chain_scoped_gas_estimator.go b/core/chains/evm/config/v2/chain_scoped_gas_estimator.go index 06cc6da674d..dde27c664c5 100644 --- a/core/chains/evm/config/v2/chain_scoped_gas_estimator.go +++ b/core/chains/evm/config/v2/chain_scoped_gas_estimator.go @@ -1,16 +1,37 @@ package v2 import ( + gethcommon "github.com/ethereum/go-ethereum/common" + "github.com/smartcontractkit/chainlink/v2/core/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config" ) type gasEstimatorConfig struct { c GasEstimator + k KeySpecificConfig blockDelay *uint16 transactionsMaxInFlight *uint32 } +func (g *gasEstimatorConfig) PriceMaxKey(addr gethcommon.Address) *assets.Wei { + var keySpecific *assets.Wei + for i := range g.k { + ks := g.k[i] + if ks.Key.Address() == addr { + keySpecific = ks.GasEstimator.PriceMax + break + } + } + + chainSpecific := g.c.PriceMax + if keySpecific != nil && !keySpecific.IsZero() && keySpecific.Cmp(chainSpecific) < 0 { + return keySpecific + } + + return g.c.PriceMax +} + func (g *gasEstimatorConfig) BlockHistory() config.BlockHistory { return &blockHistoryConfig{c: g.c.BlockHistory, blockDelay: g.blockDelay, bumpThreshold: g.c.BumpThreshold} } diff --git a/core/chains/evm/txmgr/attempts.go b/core/chains/evm/txmgr/attempts.go index f9bb4b09f8d..7b2a05a34c4 100644 --- a/core/chains/evm/txmgr/attempts.go +++ b/core/chains/evm/txmgr/attempts.go @@ -26,24 +26,20 @@ var _ TxAttemptBuilder = (*evmTxAttemptBuilder)(nil) type evmTxAttemptBuilder struct { chainID big.Int - config evmTxAttemptBuilderConfig feeConfig evmTxAttemptBuilderFeeConfig keystore TxAttemptSigner[common.Address] gas.EvmFeeEstimator } -type evmTxAttemptBuilderConfig interface { - KeySpecificMaxGasPriceWei(common.Address) *assets.Wei -} - type evmTxAttemptBuilderFeeConfig interface { EIP1559DynamicFees() bool TipCapMin() *assets.Wei PriceMin() *assets.Wei + PriceMaxKey(common.Address) *assets.Wei } -func NewEvmTxAttemptBuilder(chainID big.Int, config evmTxAttemptBuilderConfig, feeConfig evmTxAttemptBuilderFeeConfig, keystore TxAttemptSigner[common.Address], estimator gas.EvmFeeEstimator) *evmTxAttemptBuilder { - return &evmTxAttemptBuilder{chainID, config, feeConfig, keystore, estimator} +func NewEvmTxAttemptBuilder(chainID big.Int, feeConfig evmTxAttemptBuilderFeeConfig, keystore TxAttemptSigner[common.Address], estimator gas.EvmFeeEstimator) *evmTxAttemptBuilder { + return &evmTxAttemptBuilder{chainID, feeConfig, keystore, estimator} } // NewTxAttempt builds an new attempt using the configured fee estimator + using the EIP1559 config to determine tx type @@ -59,7 +55,7 @@ func (c *evmTxAttemptBuilder) NewTxAttempt(ctx context.Context, etx Tx, lggr log // NewTxAttemptWithType builds a new attempt with a new fee estimation where the txType can be specified by the caller // used for L2 re-estimation on broadcasting (note EIP1559 must be disabled otherwise this will fail with mismatched fees + tx type) func (c *evmTxAttemptBuilder) NewTxAttemptWithType(ctx context.Context, etx Tx, lggr logger.Logger, txType int, opts ...feetypes.Opt) (attempt TxAttempt, fee gas.EvmFee, feeLimit uint32, retryable bool, err error) { - keySpecificMaxGasPriceWei := c.config.KeySpecificMaxGasPriceWei(etx.FromAddress) + keySpecificMaxGasPriceWei := c.feeConfig.PriceMaxKey(etx.FromAddress) fee, feeLimit, err = c.EvmFeeEstimator.GetFee(ctx, etx.EncodedPayload, etx.FeeLimit, keySpecificMaxGasPriceWei, opts...) if err != nil { return attempt, fee, feeLimit, true, errors.Wrap(err, "failed to get fee") // estimator errors are retryable @@ -72,7 +68,7 @@ func (c *evmTxAttemptBuilder) NewTxAttemptWithType(ctx context.Context, etx Tx, // NewBumpTxAttempt builds a new attempt with a bumped fee - based on the previous attempt tx type // used in the txm broadcaster + confirmer when tx ix rejected for too low fee or is not included in a timely manner func (c *evmTxAttemptBuilder) NewBumpTxAttempt(ctx context.Context, etx Tx, previousAttempt TxAttempt, priorAttempts []TxAttempt, lggr logger.Logger) (attempt TxAttempt, bumpedFee gas.EvmFee, bumpedFeeLimit uint32, retryable bool, err error) { - keySpecificMaxGasPriceWei := c.config.KeySpecificMaxGasPriceWei(etx.FromAddress) + keySpecificMaxGasPriceWei := c.feeConfig.PriceMaxKey(etx.FromAddress) bumpedFee, bumpedFeeLimit, err = c.EvmFeeEstimator.BumpFee(ctx, previousAttempt.TxFee, etx.FeeLimit, keySpecificMaxGasPriceWei, newEvmPriorAttempts(priorAttempts)) if err != nil { @@ -137,7 +133,7 @@ func (c *evmTxAttemptBuilder) NewEmptyTxAttempt(nonce evmtypes.Nonce, feeLimit u } func (c *evmTxAttemptBuilder) newDynamicFeeAttempt(etx Tx, fee gas.DynamicFee, gasLimit uint32) (attempt TxAttempt, err error) { - if err = validateDynamicFeeGas(c.config, c.feeConfig.TipCapMin(), fee, gasLimit, etx); err != nil { + if err = validateDynamicFeeGas(c.feeConfig, c.feeConfig.TipCapMin(), fee, gasLimit, etx); err != nil { return attempt, errors.Wrap(err, "error validating gas") } @@ -167,9 +163,13 @@ func (c *evmTxAttemptBuilder) newDynamicFeeAttempt(etx Tx, fee gas.DynamicFee, g var Max256BitUInt = big.NewInt(0).Exp(big.NewInt(2), big.NewInt(256), nil) +type keySpecificEstimator interface { + PriceMaxKey(addr common.Address) *assets.Wei +} + // validateDynamicFeeGas is a sanity check - we have other checks elsewhere, but this // makes sure we _never_ create an invalid attempt -func validateDynamicFeeGas(cfg evmTxAttemptBuilderConfig, tipCapMinimum *assets.Wei, fee gas.DynamicFee, gasLimit uint32, etx Tx) error { +func validateDynamicFeeGas(kse keySpecificEstimator, tipCapMinimum *assets.Wei, fee gas.DynamicFee, gasLimit uint32, etx Tx) error { gasTipCap, gasFeeCap := fee.TipCap, fee.FeeCap if gasTipCap == nil { @@ -192,7 +192,7 @@ func validateDynamicFeeGas(cfg evmTxAttemptBuilderConfig, tipCapMinimum *assets. } // Configuration sanity-check - max := cfg.KeySpecificMaxGasPriceWei(etx.FromAddress) + max := kse.PriceMaxKey(etx.FromAddress) if gasFeeCap.Cmp(max) > 0 { return errors.Errorf("cannot create tx attempt: specified gas fee cap of %s would exceed max configured gas price of %s for key %s", gasFeeCap.String(), max.String(), etx.FromAddress.String()) } @@ -218,7 +218,7 @@ func newDynamicFeeTransaction(nonce uint64, to common.Address, value *big.Int, g } func (c *evmTxAttemptBuilder) newLegacyAttempt(etx Tx, gasPrice *assets.Wei, gasLimit uint32) (attempt TxAttempt, err error) { - if err = validateLegacyGas(c.config, c.feeConfig.PriceMin(), gasPrice, gasLimit, etx); err != nil { + if err = validateLegacyGas(c.feeConfig, c.feeConfig.PriceMin(), gasPrice, gasLimit, etx); err != nil { return attempt, errors.Wrap(err, "error validating gas") } @@ -251,11 +251,11 @@ func (c *evmTxAttemptBuilder) newLegacyAttempt(etx Tx, gasPrice *assets.Wei, gas // validateLegacyGas is a sanity check - we have other checks elsewhere, but this // makes sure we _never_ create an invalid attempt -func validateLegacyGas(cfg evmTxAttemptBuilderConfig, minGasPriceWei, gasPrice *assets.Wei, gasLimit uint32, etx Tx) error { +func validateLegacyGas(kse keySpecificEstimator, minGasPriceWei, gasPrice *assets.Wei, gasLimit uint32, etx Tx) error { if gasPrice == nil { panic("gas price missing") } - max := cfg.KeySpecificMaxGasPriceWei(etx.FromAddress) + max := kse.PriceMaxKey(etx.FromAddress) if gasPrice.Cmp(max) > 0 { return errors.Errorf("cannot create tx attempt: specified gas price of %s would exceed max configured gas price of %s for key %s", gasPrice.String(), max.String(), etx.FromAddress.String()) } diff --git a/core/chains/evm/txmgr/attempts_test.go b/core/chains/evm/txmgr/attempts_test.go index f2379daff6c..099143f0ce4 100644 --- a/core/chains/evm/txmgr/attempts_test.go +++ b/core/chains/evm/txmgr/attempts_test.go @@ -17,7 +17,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas" gasmocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/gas/mocks" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" - txmmocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr/mocks" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" configtest "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest/v2" @@ -35,18 +34,21 @@ type feeConfig struct { eip1559DynamicFees bool tipCapMin *assets.Wei priceMin *assets.Wei + priceMax *assets.Wei } func newFeeConfig() *feeConfig { return &feeConfig{ tipCapMin: assets.NewWeiI(0), priceMin: assets.NewWeiI(0), + priceMax: assets.NewWeiI(0), } } -func (g *feeConfig) EIP1559DynamicFees() bool { return g.eip1559DynamicFees } -func (g *feeConfig) TipCapMin() *assets.Wei { return g.tipCapMin } -func (g *feeConfig) PriceMin() *assets.Wei { return g.priceMin } +func (g *feeConfig) EIP1559DynamicFees() bool { return g.eip1559DynamicFees } +func (g *feeConfig) TipCapMin() *assets.Wei { return g.tipCapMin } +func (g *feeConfig) PriceMin() *assets.Wei { return g.priceMin } +func (g *feeConfig) PriceMaxKey(addr gethcommon.Address) *assets.Wei { return g.priceMax } func TestTxm_SignTx(t *testing.T) { t.Parallel() @@ -64,10 +66,9 @@ func TestTxm_SignTx(t *testing.T) { t.Run("returns correct hash for non-okex chains", func(t *testing.T) { chainID := big.NewInt(1) - cfg := txmmocks.NewConfig(t) kst := ksmocks.NewEth(t) kst.On("SignTx", to, tx, chainID).Return(tx, nil).Once() - cks := txmgr.NewEvmTxAttemptBuilder(*chainID, cfg, newFeeConfig(), kst, nil) + cks := txmgr.NewEvmTxAttemptBuilder(*chainID, newFeeConfig(), kst, nil) hash, rawBytes, err := cks.SignTx(addr, tx) require.NoError(t, err) require.NotNil(t, rawBytes) @@ -76,10 +77,9 @@ func TestTxm_SignTx(t *testing.T) { // okex used to have a custom hash but now this just verifies that is it the same t.Run("returns correct hash for okex chains", func(t *testing.T) { chainID := big.NewInt(1) - cfg := txmmocks.NewConfig(t) kst := ksmocks.NewEth(t) kst.On("SignTx", to, tx, chainID).Return(tx, nil).Once() - cks := txmgr.NewEvmTxAttemptBuilder(*chainID, cfg, newFeeConfig(), kst, nil) + cks := txmgr.NewEvmTxAttemptBuilder(*chainID, newFeeConfig(), kst, nil) hash, rawBytes, err := cks.SignTx(addr, tx) require.NoError(t, err) require.NotNil(t, rawBytes) @@ -96,9 +96,9 @@ func TestTxm_NewDynamicFeeTx(t *testing.T) { lggr := logger.TestLogger(t) t.Run("creates attempt with fields", func(t *testing.T) { - gcfg := configtest.NewGeneralConfig(t, nil) - cfg := evmtest.NewChainScopedConfig(t, gcfg) - cks := txmgr.NewEvmTxAttemptBuilder(*big.NewInt(1), cfg.EVM(), newFeeConfig(), kst, nil) + feeCfg := newFeeConfig() + feeCfg.priceMax = assets.GWei(200) + cks := txmgr.NewEvmTxAttemptBuilder(*big.NewInt(1), feeCfg, kst, nil) dynamicFee := gas.DynamicFee{TipCap: assets.GWei(100), FeeCap: assets.GWei(200)} a, _, err := cks.NewCustomTxAttempt(txmgr.Tx{Sequence: &n, FromAddress: addr}, gas.EvmFee{ DynamicTipCap: dynamicFee.TipCap, @@ -140,7 +140,7 @@ func TestTxm_NewDynamicFeeTx(t *testing.T) { t.Run(test.name, func(t *testing.T) { gcfg := configtest.NewGeneralConfig(t, test.setCfg) cfg := evmtest.NewChainScopedConfig(t, gcfg) - cks := txmgr.NewEvmTxAttemptBuilder(*big.NewInt(1), cfg.EVM(), cfg.EVM().GasEstimator(), kst, nil) + cks := txmgr.NewEvmTxAttemptBuilder(*big.NewInt(1), cfg.EVM().GasEstimator(), kst, nil) dynamicFee := gas.DynamicFee{TipCap: test.tipcap, FeeCap: test.feecap} _, _, err := cks.NewCustomTxAttempt(txmgr.Tx{Sequence: &n, FromAddress: addr}, gas.EvmFee{ DynamicTipCap: dynamicFee.TipCap, @@ -158,16 +158,13 @@ func TestTxm_NewDynamicFeeTx(t *testing.T) { func TestTxm_NewLegacyAttempt(t *testing.T) { addr := NewEvmAddress() - gcfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { - c.EVM[0].GasEstimator.PriceMax = assets.NewWeiI(50) - }) - cfg := evmtest.NewChainScopedConfig(t, gcfg) kst := ksmocks.NewEth(t) tx := types.NewTx(&types.LegacyTx{}) kst.On("SignTx", addr, mock.Anything, big.NewInt(1)).Return(tx, nil) gc := newFeeConfig() gc.priceMin = assets.NewWeiI(10) - cks := txmgr.NewEvmTxAttemptBuilder(*big.NewInt(1), cfg.EVM(), gc, kst, nil) + gc.priceMax = assets.NewWeiI(50) + cks := txmgr.NewEvmTxAttemptBuilder(*big.NewInt(1), gc, kst, nil) lggr := logger.TestLogger(t) t.Run("creates attempt with fields", func(t *testing.T) { @@ -191,10 +188,9 @@ func TestTxm_NewLegacyAttempt(t *testing.T) { func TestTxm_NewCustomTxAttempt_NonRetryableErrors(t *testing.T) { t.Parallel() - cfg := txmmocks.NewConfig(t) kst := ksmocks.NewEth(t) lggr := logger.TestLogger(t) - cks := txmgr.NewEvmTxAttemptBuilder(*big.NewInt(1), cfg, newFeeConfig(), kst, nil) + cks := txmgr.NewEvmTxAttemptBuilder(*big.NewInt(1), newFeeConfig(), kst, nil) dynamicFee := gas.DynamicFee{TipCap: assets.GWei(100), FeeCap: assets.GWei(200)} legacyFee := assets.NewWeiI(100) @@ -225,13 +221,10 @@ func TestTxm_EvmTxAttemptBuilder_RetryableEstimatorError(t *testing.T) { est.On("GetFee", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(gas.EvmFee{}, uint32(0), errors.New("fail")) est.On("BumpFee", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(gas.EvmFee{}, uint32(0), errors.New("fail")) - cfg := txmmocks.NewConfig(t) - cfg.On("KeySpecificMaxGasPriceWei", mock.Anything).Return(assets.NewWeiI(100)) - kst := ksmocks.NewEth(t) lggr := logger.TestLogger(t) ctx := testutils.Context(t) - cks := txmgr.NewEvmTxAttemptBuilder(*big.NewInt(1), cfg, &feeConfig{eip1559DynamicFees: true}, kst, est) + cks := txmgr.NewEvmTxAttemptBuilder(*big.NewInt(1), &feeConfig{eip1559DynamicFees: true}, kst, est) t.Run("NewAttempt", func(t *testing.T) { _, _, _, retryable, err := cks.NewTxAttempt(ctx, txmgr.Tx{}, lggr) diff --git a/core/chains/evm/txmgr/broadcaster_test.go b/core/chains/evm/txmgr/broadcaster_test.go index a262d91a3c6..9107311691b 100644 --- a/core/chains/evm/txmgr/broadcaster_test.go +++ b/core/chains/evm/txmgr/broadcaster_test.go @@ -67,7 +67,7 @@ func NewTestEthBroadcaster( lggr := logger.TestLogger(t) ge := config.EVM().GasEstimator() estimator := gas.NewWrappedEvmEstimator(gas.NewFixedPriceEstimator(config.EVM().GasEstimator(), ge.BlockHistory(), lggr), ge.EIP1559DynamicFees()) - txBuilder := txmgr.NewEvmTxAttemptBuilder(*ethClient.ConfiguredChainID(), config.EVM(), ge, keyStore, estimator) + txBuilder := txmgr.NewEvmTxAttemptBuilder(*ethClient.ConfiguredChainID(), ge, keyStore, estimator) txNonceSyncer := txmgr.NewNonceSyncer(txStore, lggr, ethClient, keyStore) ethBroadcaster := txmgr.NewEvmBroadcaster(txStore, txmgr.NewEvmTxmClient(ethClient), txmgr.NewEvmTxmConfig(config.EVM()), txmgr.NewEvmTxmFeeConfig(config.EVM().GasEstimator()), config.EVM().Transactions(), config.Database().Listener(), keyStore, eventBroadcaster, txBuilder, txNonceSyncer, lggr, checkerFactory, nonceAutoSync) @@ -90,7 +90,7 @@ func TestEthBroadcaster_Lifecycle(t *testing.T) { ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, 0) estimator := gasmocks.NewEvmFeeEstimator(t) - txBuilder := txmgr.NewEvmTxAttemptBuilder(*ethClient.ConfiguredChainID(), evmcfg.EVM(), evmcfg.EVM().GasEstimator(), ethKeyStore, estimator) + txBuilder := txmgr.NewEvmTxAttemptBuilder(*ethClient.ConfiguredChainID(), evmcfg.EVM().GasEstimator(), ethKeyStore, estimator) eb := txmgr.NewEvmBroadcaster( txStore, @@ -582,12 +582,12 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_OptimisticLockingOnEthTx(t *testi ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore, 0) estimator := gasmocks.NewEvmFeeEstimator(t) - txBuilder := txmgr.NewEvmTxAttemptBuilder(*ethClient.ConfiguredChainID(), evmcfg, ccfg.EVM().GasEstimator(), ethKeyStore, estimator) + txBuilder := txmgr.NewEvmTxAttemptBuilder(*ethClient.ConfiguredChainID(), ccfg.EVM().GasEstimator(), ethKeyStore, estimator) chStartEstimate := make(chan struct{}) chBlock := make(chan struct{}) - estimator.On("GetFee", mock.Anything, mock.Anything, mock.Anything, evmcfg.KeySpecificMaxGasPriceWei(fromAddress)).Return(gas.EvmFee{Legacy: assets.GWei(32)}, uint32(500), nil).Run(func(_ mock.Arguments) { + estimator.On("GetFee", mock.Anything, mock.Anything, mock.Anything, ccfg.EVM().GasEstimator().PriceMaxKey(fromAddress)).Return(gas.EvmFee{Legacy: assets.GWei(32)}, uint32(500), nil).Run(func(_ mock.Arguments) { close(chStartEstimate) <-chBlock }) @@ -1134,7 +1134,7 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { t.Cleanup(func() { assert.NoError(t, eventBroadcaster.Close()) }) lggr := logger.TestLogger(t) estimator := gas.NewWrappedEvmEstimator(gas.NewFixedPriceEstimator(evmcfg.EVM().GasEstimator(), evmcfg.EVM().GasEstimator().BlockHistory(), lggr), evmcfg.EVM().GasEstimator().EIP1559DynamicFees()) - txBuilder := txmgr.NewEvmTxAttemptBuilder(*ethClient.ConfiguredChainID(), evmcfg.EVM(), evmcfg.EVM().GasEstimator(), ethKeyStore, estimator) + txBuilder := txmgr.NewEvmTxAttemptBuilder(*ethClient.ConfiguredChainID(), evmcfg.EVM().GasEstimator(), ethKeyStore, estimator) eb = txmgr.NewEvmBroadcaster(txStore, txmgr.NewEvmTxmClient(ethClient), txmgr.NewEvmTxmConfig(evmcfg.EVM()), txmgr.NewEvmTxmFeeConfig(evmcfg.EVM().GasEstimator()), evmcfg.EVM().Transactions(), evmcfg.Database().Listener(), ethKeyStore, eventBroadcaster, txBuilder, nil, lggr, &testCheckerFactory{}, false) require.NoError(t, err) { @@ -1795,7 +1795,7 @@ func TestEthBroadcaster_SyncNonce(t *testing.T) { t.Run("does nothing if nonce sync is disabled", func(t *testing.T) { ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - txBuilder := txmgr.NewEvmTxAttemptBuilder(*ethClient.ConfiguredChainID(), evmcfg.EVM(), ge, kst, estimator) + txBuilder := txmgr.NewEvmTxAttemptBuilder(*ethClient.ConfiguredChainID(), ge, kst, estimator) eb := txmgr.NewEvmBroadcaster(txStore, txmgr.NewEvmTxmClient(ethClient), evmTxmCfg, txmgr.NewEvmTxmFeeConfig(ge), evmcfg.EVM().Transactions(), cfg.Database().Listener(), kst, eventBroadcaster, txBuilder, nil, lggr, checkerFactory, false) err := eb.Start(testutils.Context(t)) @@ -1808,7 +1808,7 @@ func TestEthBroadcaster_SyncNonce(t *testing.T) { t.Run("when eth node returns nonce, successfully sets nonce", func(t *testing.T) { ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - txBuilder := txmgr.NewEvmTxAttemptBuilder(*ethClient.ConfiguredChainID(), evmcfg.EVM(), ge, kst, estimator) + txBuilder := txmgr.NewEvmTxAttemptBuilder(*ethClient.ConfiguredChainID(), ge, kst, estimator) txNonceSyncer := txmgr.NewNonceSyncer(txStore, lggr, ethClient, kst) eb := txmgr.NewEvmBroadcaster(txStore, txmgr.NewEvmTxmClient(ethClient), evmTxmCfg, txmgr.NewEvmTxmFeeConfig(ge), evmcfg.EVM().Transactions(), cfg.Database().Listener(), kst, eventBroadcaster, txBuilder, txNonceSyncer, lggr, checkerFactory, true) @@ -1839,7 +1839,7 @@ func TestEthBroadcaster_SyncNonce(t *testing.T) { t.Run("when eth node returns error, retries and successfully sets nonce", func(t *testing.T) { ethClient := evmtest.NewEthClientMockWithDefaultChain(t) - txBuilder := txmgr.NewEvmTxAttemptBuilder(*ethClient.ConfiguredChainID(), evmcfg.EVM(), ge, kst, estimator) + txBuilder := txmgr.NewEvmTxAttemptBuilder(*ethClient.ConfiguredChainID(), ge, kst, estimator) txNonceSyncer := txmgr.NewNonceSyncer(txStore, lggr, ethClient, kst) eb := txmgr.NewEvmBroadcaster(txStore, txmgr.NewEvmTxmClient(ethClient), evmTxmCfg, txmgr.NewEvmTxmFeeConfig(evmcfg.EVM().GasEstimator()), evmcfg.EVM().Transactions(), cfg.Database().Listener(), kst, eventBroadcaster, txBuilder, txNonceSyncer, lggr, checkerFactory, true) eb.XXXTestDisableUnstartedTxAutoProcessing() diff --git a/core/chains/evm/txmgr/builder.go b/core/chains/evm/txmgr/builder.go index 6cd29f9f7a9..464cf6f9c59 100644 --- a/core/chains/evm/txmgr/builder.go +++ b/core/chains/evm/txmgr/builder.go @@ -45,7 +45,7 @@ func NewTxm( } checker := &CheckerFactory{Client: client} // create tx attempt builder - txAttemptBuilder := NewEvmTxAttemptBuilder(*client.ConfiguredChainID(), chainConfig, fCfg, keyStore, estimator) + txAttemptBuilder := NewEvmTxAttemptBuilder(*client.ConfiguredChainID(), fCfg, keyStore, estimator) txStore := NewTxStore(db, lggr, dbConfig) txNonceSyncer := NewNonceSyncer(txStore, lggr, client, keyStore) diff --git a/core/chains/evm/txmgr/config.go b/core/chains/evm/txmgr/config.go index 5c912a77b94..acc50ae65b8 100644 --- a/core/chains/evm/txmgr/config.go +++ b/core/chains/evm/txmgr/config.go @@ -3,7 +3,7 @@ package txmgr import ( "time" - "github.com/ethereum/go-ethereum/common" + gethcommon "github.com/ethereum/go-ethereum/common" txmgrtypes "github.com/smartcontractkit/chainlink/v2/common/txmgr/types" "github.com/smartcontractkit/chainlink/v2/core/assets" @@ -19,7 +19,6 @@ type ChainConfig interface { FinalityDepth() uint32 NonceAutoSync() bool RPCDefaultBatchSize() uint32 - KeySpecificMaxGasPriceWei(addr common.Address) *assets.Wei } type FeeConfig interface { @@ -32,6 +31,7 @@ type FeeConfig interface { TipCapMin() *assets.Wei PriceMax() *assets.Wei PriceMin() *assets.Wei + PriceMaxKey(gethcommon.Address) *assets.Wei } type DatabaseConfig interface { diff --git a/core/chains/evm/txmgr/confirmer_test.go b/core/chains/evm/txmgr/confirmer_test.go index b324da83387..63f9a945809 100644 --- a/core/chains/evm/txmgr/confirmer_test.go +++ b/core/chains/evm/txmgr/confirmer_test.go @@ -122,7 +122,7 @@ func TestEthConfirmer_Lifecycle(t *testing.T) { lggr := logger.TestLogger(t) ge := config.EVM().GasEstimator() feeEstimator := gas.NewWrappedEvmEstimator(estimator, ge.EIP1559DynamicFees()) - txBuilder := txmgr.NewEvmTxAttemptBuilder(*ethClient.ConfiguredChainID(), config.EVM(), ge, ethKeyStore, feeEstimator) + txBuilder := txmgr.NewEvmTxAttemptBuilder(*ethClient.ConfiguredChainID(), ge, ethKeyStore, feeEstimator) ec := txmgr.NewEvmConfirmer(txStore, txmgr.NewEvmTxmClient(ethClient), txmgr.NewEvmTxmConfig(config.EVM()), txmgr.NewEvmTxmFeeConfig(ge), config.EVM().Transactions(), config.Database(), ethKeyStore, txBuilder, lggr) ctx := testutils.Context(t) @@ -1635,7 +1635,6 @@ func TestEthConfirmer_RebroadcastWhereNecessary_WithConnectivityCheck(t *testing c.EVM[0].GasEstimator.BlockHistory.CheckInclusionBlocks = ptr[uint16](4) }) ccfg := evmtest.NewChainScopedConfig(t, cfg) - evmcfg := txmgr.NewEvmTxmConfig(ccfg.EVM()) txStore := cltest.NewTestTxStore(t, db, cfg.Database()) ethKeyStore := cltest.NewKeyStore(t, db, cfg.Database()).Eth() @@ -1646,7 +1645,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary_WithConnectivityCheck(t *testing estimator.On("BumpLegacyGas", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil, uint32(0), pkgerrors.Wrapf(gas.ErrConnectivity, "transaction...")) ge := ccfg.EVM().GasEstimator() feeEstimator := gas.NewWrappedEvmEstimator(estimator, ge.EIP1559DynamicFees()) - txBuilder := txmgr.NewEvmTxAttemptBuilder(*ethClient.ConfiguredChainID(), evmcfg, ge, kst, feeEstimator) + txBuilder := txmgr.NewEvmTxAttemptBuilder(*ethClient.ConfiguredChainID(), ge, kst, feeEstimator) addresses := []gethCommon.Address{fromAddress} kst.On("EnabledAddressesForChain", &cltest.FixtureChainID).Return(addresses, nil).Maybe() // Create confirmer with necessary state @@ -1691,7 +1690,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary_WithConnectivityCheck(t *testing // Create confirmer with necessary state ge := ccfg.EVM().GasEstimator() feeEstimator := gas.NewWrappedEvmEstimator(estimator, ge.EIP1559DynamicFees()) - txBuilder := txmgr.NewEvmTxAttemptBuilder(*ethClient.ConfiguredChainID(), ccfg.EVM(), ge, kst, feeEstimator) + txBuilder := txmgr.NewEvmTxAttemptBuilder(*ethClient.ConfiguredChainID(), ge, kst, feeEstimator) addresses := []gethCommon.Address{fromAddress} kst.On("EnabledAddressesForChain", &cltest.FixtureChainID).Return(addresses, nil).Maybe() ec := txmgr.NewEvmConfirmer(txStore, txmgr.NewEvmTxmClient(ethClient), ccfg.EVM(), txmgr.NewEvmTxmFeeConfig(ccfg.EVM().GasEstimator()), ccfg.EVM().Transactions(), cfg.Database(), kst, txBuilder, lggr) @@ -1722,9 +1721,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { t.Parallel() db := pgtest.NewSqlxDB(t) - var config *chainlink.Config cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { - config = c // DO NOT COPY - major hack c.EVM[0].GasEstimator.PriceMax = (*assets.Wei)(assets.GWei(500)) }) txStore := cltest.NewTestTxStore(t, db, cfg.Database()) @@ -2207,14 +2204,19 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { // Set price such that the next bump will exceed EVM.GasEstimator.PriceMax // Existing gas price is: 60480000000 gasPrice := attempt3_4.TxFee.Legacy.ToInt() - config.EVM[0].GasEstimator.PriceMax = (*assets.Wei)(assets.NewWeiI(60500000000)) + gcfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { + c.EVM[0].GasEstimator.PriceMax = assets.NewWeiI(60500000000) + }) + newCfg := evmtest.NewChainScopedConfig(t, gcfg) + ec2, err := cltest.NewEthConfirmer(t, txStore, ethClient, newCfg, ethKeyStore, nil) + require.NoError(t, err) ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *types.Transaction) bool { return evmtypes.Nonce(tx.Nonce()) == *etx3.Sequence && gasPrice.Cmp(tx.GasPrice()) == 0 }), fromAddress).Return(clienttypes.Successful, errors.New("already known")).Once() // we already submitted at this price, now its time to bump and submit again but since we simply resubmitted rather than increasing gas price, geth already knows about this tx // Do the thing - require.NoError(t, ec.RebroadcastWhereNecessary(testutils.Context(t), currentHead)) + require.NoError(t, ec2.RebroadcastWhereNecessary(testutils.Context(t), currentHead)) etx3, err = txStore.FindTxWithAttempts(etx3.ID) require.NoError(t, err) @@ -2233,14 +2235,19 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { // Set price such that the current price is already at EVM.GasEstimator.PriceMax // Existing gas price is: 60480000000 gasPrice := attempt3_4.TxFee.Legacy.ToInt() - config.EVM[0].GasEstimator.PriceMax = (*assets.Wei)(assets.NewWeiI(60480000000)) + gcfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { + c.EVM[0].GasEstimator.PriceMax = assets.NewWeiI(60480000000) + }) + newCfg := evmtest.NewChainScopedConfig(t, gcfg) + ec2, err := cltest.NewEthConfirmer(t, txStore, ethClient, newCfg, ethKeyStore, nil) + require.NoError(t, err) ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *types.Transaction) bool { return evmtypes.Nonce(tx.Nonce()) == *etx3.Sequence && gasPrice.Cmp(tx.GasPrice()) == 0 }), fromAddress).Return(clienttypes.Successful, errors.New("already known")).Once() // we already submitted at this price, now its time to bump and submit again but since we simply resubmitted rather than increasing gas price, geth already knows about this tx // Do the thing - require.NoError(t, ec.RebroadcastWhereNecessary(testutils.Context(t), currentHead)) + require.NoError(t, ec2.RebroadcastWhereNecessary(testutils.Context(t), currentHead)) etx3, err = txStore.FindTxWithAttempts(etx3.ID) require.NoError(t, err) @@ -2261,7 +2268,6 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { var attempt4_2 txmgr.TxAttempt t.Run("EIP-1559: bumps using EIP-1559 rules when existing attempts are of type 0x2", func(t *testing.T) { - config.EVM[0].GasEstimator.PriceMax = (*assets.Wei)(assets.GWei(1000)) ethTx := *types.NewTx(&types.DynamicFeeTx{}) kst.On("SignTx", fromAddress, @@ -2298,14 +2304,19 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { oldEnough, assets.GWei(999), assets.GWei(1000), attempt4_2.ID)) t.Run("EIP-1559: resubmits at the old price and does not create a new attempt if one of the bumped EIP-1559 transactions would have its tip cap exceed EVM.GasEstimator.PriceMax", func(t *testing.T) { - config.EVM[0].GasEstimator.PriceMax = (*assets.Wei)(assets.GWei(1000)) + gcfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { + c.EVM[0].GasEstimator.PriceMax = assets.GWei(1000) + }) + newCfg := evmtest.NewChainScopedConfig(t, gcfg) + ec2, err := cltest.NewEthConfirmer(t, txStore, ethClient, newCfg, ethKeyStore, nil) + require.NoError(t, err) // Third attempt failed to bump, resubmits old one instead ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *types.Transaction) bool { return evmtypes.Nonce(tx.Nonce()) == *etx4.Sequence && attempt4_2.Hash.String() == tx.Hash().String() }), fromAddress).Return(clienttypes.Successful, nil).Once() - require.NoError(t, ec.RebroadcastWhereNecessary(testutils.Context(t), currentHead)) + require.NoError(t, ec2.RebroadcastWhereNecessary(testutils.Context(t), currentHead)) etx4, err = txStore.FindTxWithAttempts(etx4.ID) require.NoError(t, err) diff --git a/core/chains/evm/txmgr/mocks/config.go b/core/chains/evm/txmgr/mocks/config.go index c7bd0454ea9..dc54f7850c2 100644 --- a/core/chains/evm/txmgr/mocks/config.go +++ b/core/chains/evm/txmgr/mocks/config.go @@ -3,11 +3,7 @@ package mocks import ( - common "github.com/ethereum/go-ethereum/common" - assets "github.com/smartcontractkit/chainlink/v2/core/assets" - config "github.com/smartcontractkit/chainlink/v2/core/config" - mock "github.com/stretchr/testify/mock" ) @@ -44,22 +40,6 @@ func (_m *Config) FinalityDepth() uint32 { return r0 } -// KeySpecificMaxGasPriceWei provides a mock function with given fields: addr -func (_m *Config) KeySpecificMaxGasPriceWei(addr common.Address) *assets.Wei { - ret := _m.Called(addr) - - var r0 *assets.Wei - if rf, ok := ret.Get(0).(func(common.Address) *assets.Wei); ok { - r0 = rf(addr) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*assets.Wei) - } - } - - return r0 -} - // NonceAutoSync provides a mock function with given fields: func (_m *Config) NonceAutoSync() bool { ret := _m.Called() diff --git a/core/chains/evm/txmgr/txmgr_test.go b/core/chains/evm/txmgr/txmgr_test.go index a15ebbc0342..1541713db75 100644 --- a/core/chains/evm/txmgr/txmgr_test.go +++ b/core/chains/evm/txmgr/txmgr_test.go @@ -395,6 +395,9 @@ func (g *gasEstimatorConfig) PriceMax() *assets.Wei { return asse func (g *gasEstimatorConfig) PriceMin() *assets.Wei { return assets.NewWeiI(42) } func (g *gasEstimatorConfig) Mode() string { return "FixedPrice" } func (g *gasEstimatorConfig) LimitJobType() evmconfig.LimitJobType { return &limitJobTypeConfig{} } +func (e *gasEstimatorConfig) PriceMaxKey(addr common.Address) *assets.Wei { + return assets.NewWeiI(42) +} type limitJobTypeConfig struct { } @@ -438,11 +441,10 @@ func (c *mockConfig) EVM() evmconfig.EVM { return c.evmConfig } -func (c *mockConfig) NonceAutoSync() bool { return true } -func (c *mockConfig) ChainType() config.ChainType { return "" } -func (c *mockConfig) FinalityDepth() uint32 { return c.finalityDepth } -func (c *mockConfig) KeySpecificMaxGasPriceWei(common.Address) *assets.Wei { return assets.NewWeiI(0) } -func (c *mockConfig) RPCDefaultBatchSize() uint32 { return c.rpcDefaultBatchSize } +func (c *mockConfig) NonceAutoSync() bool { return true } +func (c *mockConfig) ChainType() config.ChainType { return "" } +func (c *mockConfig) FinalityDepth() uint32 { return c.finalityDepth } +func (c *mockConfig) RPCDefaultBatchSize() uint32 { return c.rpcDefaultBatchSize } func makeConfigs(t *testing.T) (*mockConfig, *databaseConfig, *evmConfig) { db := &databaseConfig{defaultQueryTimeout: pg.DefaultQueryTimeout} diff --git a/core/cmd/shell_local.go b/core/cmd/shell_local.go index 1b266f85731..926727944bf 100644 --- a/core/cmd/shell_local.go +++ b/core/cmd/shell_local.go @@ -619,7 +619,7 @@ func (s *Shell) RebroadcastTransactions(c *cli.Context) (err error) { s.Logger.Infof("Rebroadcasting transactions from %v to %v", beginningNonce, endingNonce) orm := txmgr.NewTxStore(app.GetSqlxDB(), lggr, s.Config.Database()) - txBuilder := txmgr.NewEvmTxAttemptBuilder(*ethClient.ConfiguredChainID(), chain.Config().EVM(), chain.Config().EVM().GasEstimator(), keyStore.Eth(), nil) + txBuilder := txmgr.NewEvmTxAttemptBuilder(*ethClient.ConfiguredChainID(), chain.Config().EVM().GasEstimator(), keyStore.Eth(), nil) cfg := txmgr.NewEvmTxmConfig(chain.Config().EVM()) feeCfg := txmgr.NewEvmTxmFeeConfig(chain.Config().EVM().GasEstimator()) ec := txmgr.NewEvmConfirmer(orm, txmgr.NewEvmTxmClient(ethClient), cfg, feeCfg, chain.Config().EVM().Transactions(), chain.Config().Database(), keyStore.Eth(), txBuilder, chain.Logger()) diff --git a/core/internal/cltest/cltest.go b/core/internal/cltest/cltest.go index 4a1cfc238ee..0c45887902e 100644 --- a/core/internal/cltest/cltest.go +++ b/core/internal/cltest/cltest.go @@ -219,7 +219,7 @@ func NewEthConfirmer(t testing.TB, txStore txmgr.EvmTxStore, ethClient evmclient lggr := logger.TestLogger(t) ge := config.EVM().GasEstimator() estimator := gas.NewWrappedEvmEstimator(gas.NewFixedPriceEstimator(ge, ge.BlockHistory(), lggr), ge.EIP1559DynamicFees()) - txBuilder := txmgr.NewEvmTxAttemptBuilder(*ethClient.ConfiguredChainID(), config.EVM(), ge, ks, estimator) + txBuilder := txmgr.NewEvmTxAttemptBuilder(*ethClient.ConfiguredChainID(), ge, ks, estimator) ec := txmgr.NewEvmConfirmer(txStore, txmgr.NewEvmTxmClient(ethClient), txmgr.NewEvmTxmConfig(config.EVM()), txmgr.NewEvmTxmFeeConfig(ge), config.EVM().Transactions(), config.Database(), ks, txBuilder, lggr) ec.SetResumeCallback(fn) require.NoError(t, ec.Start(testutils.Context(t))) diff --git a/core/services/vrf/delegate.go b/core/services/vrf/delegate.go index 5b036db5e14..a8d4878bbff 100644 --- a/core/services/vrf/delegate.go +++ b/core/services/vrf/delegate.go @@ -47,13 +47,13 @@ type GethKeyStore interface { //go:generate mockery --quiet --name Config --output ./mocks/ --case=underscore type Config interface { FinalityDepth() uint32 - KeySpecificMaxGasPriceWei(addr common.Address) *assets.Wei MinIncomingConfirmations() uint32 } type FeeConfig interface { LimitDefault() uint32 LimitJobType() config.LimitJobType + PriceMaxKey(common.Address) *assets.Wei } func NewDelegate( @@ -146,11 +146,11 @@ func (d *Delegate) ServicesForSpec(jb job.Job) ([]job.ServiceCtx, error) { return nil, err } - if !FromAddressMaxGasPricesAllEqual(jb, chain.Config().EVM().KeySpecificMaxGasPriceWei) { + if !FromAddressMaxGasPricesAllEqual(jb, chain.Config().EVM().GasEstimator().PriceMaxKey) { return nil, errors.New("key-specific max gas prices of all fromAddresses are not equal, please set them to equal values") } - if err := CheckFromAddressMaxGasPrices(jb, chain.Config().EVM().KeySpecificMaxGasPriceWei); err != nil { + if err := CheckFromAddressMaxGasPrices(jb, chain.Config().EVM().GasEstimator().PriceMaxKey); err != nil { return nil, err } diff --git a/core/services/vrf/delegate_test.go b/core/services/vrf/delegate_test.go index efeedb865f8..63ef08be6ae 100644 --- a/core/services/vrf/delegate_test.go +++ b/core/services/vrf/delegate_test.go @@ -12,6 +12,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/chains/evm" evmclimocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client/mocks" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/mocks" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker" httypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/headtracker/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log" @@ -33,7 +34,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/signatures/secp256k1" "github.com/smartcontractkit/chainlink/v2/core/services/srvctest" "github.com/smartcontractkit/chainlink/v2/core/services/vrf" - vrf_mocks "github.com/smartcontractkit/chainlink/v2/core/services/vrf/mocks" "github.com/smartcontractkit/chainlink/v2/core/testdata/testspecs" "github.com/smartcontractkit/chainlink/v2/core/utils" @@ -494,8 +494,8 @@ decode_log->vrf->encode_tx->submit_tx jb, err := vrf.ValidatedVRFSpec(spec) require.NoError(tt, err) - cfg := vrf_mocks.NewConfig(t) - require.NoError(tt, vrf.CheckFromAddressMaxGasPrices(jb, cfg.KeySpecificMaxGasPriceWei)) + gasEstimator := mocks.NewGasEstimator(t) + require.NoError(tt, vrf.CheckFromAddressMaxGasPrices(jb, gasEstimator.PriceMaxKey)) }) t.Run("returns nil error on valid gas lane <=> key specific gas price setting", func(tt *testing.T) { @@ -504,11 +504,11 @@ decode_log->vrf->encode_tx->submit_tx fromAddresses = append(fromAddresses, testutils.NewAddress().Hex()) } - cfg := vrf_mocks.NewConfig(t) + gasEstimator := mocks.NewGasEstimator(t) for _, a := range fromAddresses { - cfg.On("KeySpecificMaxGasPriceWei", common.HexToAddress(a)).Return(assets.GWei(100)).Once() + gasEstimator.On("PriceMaxKey", common.HexToAddress(a)).Return(assets.GWei(100)).Once() } - defer cfg.AssertExpectations(tt) + defer gasEstimator.AssertExpectations(tt) jb, err := vrf.ValidatedVRFSpec(testspecs.GenerateVRFSpec( testspecs.VRFSpecParams{ @@ -522,7 +522,7 @@ decode_log->vrf->encode_tx->submit_tx Toml()) require.NoError(t, err) - require.NoError(tt, vrf.CheckFromAddressMaxGasPrices(jb, cfg.KeySpecificMaxGasPriceWei)) + require.NoError(tt, vrf.CheckFromAddressMaxGasPrices(jb, gasEstimator.PriceMaxKey)) }) t.Run("returns error on invalid setting", func(tt *testing.T) { @@ -531,12 +531,12 @@ decode_log->vrf->encode_tx->submit_tx fromAddresses = append(fromAddresses, testutils.NewAddress().Hex()) } - cfg := vrf_mocks.NewConfig(t) - cfg.On("KeySpecificMaxGasPriceWei", common.HexToAddress(fromAddresses[0])).Return(assets.GWei(100)).Once() - cfg.On("KeySpecificMaxGasPriceWei", common.HexToAddress(fromAddresses[1])).Return(assets.GWei(100)).Once() + gasEstimator := mocks.NewGasEstimator(t) + gasEstimator.On("PriceMaxKey", common.HexToAddress(fromAddresses[0])).Return(assets.GWei(100)).Once() + gasEstimator.On("PriceMaxKey", common.HexToAddress(fromAddresses[1])).Return(assets.GWei(100)).Once() // last from address has wrong key-specific max gas price - cfg.On("KeySpecificMaxGasPriceWei", common.HexToAddress(fromAddresses[2])).Return(assets.GWei(50)).Once() - defer cfg.AssertExpectations(tt) + gasEstimator.On("PriceMaxKey", common.HexToAddress(fromAddresses[2])).Return(assets.GWei(50)).Once() + defer gasEstimator.AssertExpectations(tt) jb, err := vrf.ValidatedVRFSpec(testspecs.GenerateVRFSpec( testspecs.VRFSpecParams{ @@ -550,7 +550,7 @@ decode_log->vrf->encode_tx->submit_tx Toml()) require.NoError(t, err) - require.Error(tt, vrf.CheckFromAddressMaxGasPrices(jb, cfg.KeySpecificMaxGasPriceWei)) + require.Error(tt, vrf.CheckFromAddressMaxGasPrices(jb, gasEstimator.PriceMaxKey)) }) } @@ -632,13 +632,13 @@ func Test_FromAddressMaxGasPricesAllEqual(t *testing.T) { }).Toml()) require.NoError(tt, err) - cfg := vrf_mocks.NewConfig(t) + gasEstimator := mocks.NewGasEstimator(t) for _, a := range fromAddresses { - cfg.On("KeySpecificMaxGasPriceWei", common.HexToAddress(a)).Return(assets.GWei(100)) + gasEstimator.On("PriceMaxKey", common.HexToAddress(a)).Return(assets.GWei(100)) } - defer cfg.AssertExpectations(tt) + defer gasEstimator.AssertExpectations(tt) - assert.True(tt, vrf.FromAddressMaxGasPricesAllEqual(jb, cfg.KeySpecificMaxGasPriceWei)) + assert.True(tt, vrf.FromAddressMaxGasPricesAllEqual(jb, gasEstimator.PriceMaxKey)) }) t.Run("one max gas price not equal to others", func(tt *testing.T) { @@ -659,14 +659,14 @@ func Test_FromAddressMaxGasPricesAllEqual(t *testing.T) { }).Toml()) require.NoError(tt, err) - cfg := vrf_mocks.NewConfig(t) + gasEstimator := mocks.NewGasEstimator(t) for _, a := range fromAddresses[:3] { - cfg.On("KeySpecificMaxGasPriceWei", common.HexToAddress(a)).Return(assets.GWei(100)) + gasEstimator.On("PriceMaxKey", common.HexToAddress(a)).Return(assets.GWei(100)) } - cfg.On("KeySpecificMaxGasPriceWei", common.HexToAddress(fromAddresses[len(fromAddresses)-1])). + gasEstimator.On("PriceMaxKey", common.HexToAddress(fromAddresses[len(fromAddresses)-1])). Return(assets.GWei(200)) // doesn't match the rest - defer cfg.AssertExpectations(tt) + defer gasEstimator.AssertExpectations(tt) - assert.False(tt, vrf.FromAddressMaxGasPricesAllEqual(jb, cfg.KeySpecificMaxGasPriceWei)) + assert.False(tt, vrf.FromAddressMaxGasPricesAllEqual(jb, gasEstimator.PriceMaxKey)) }) } diff --git a/core/services/vrf/listener_v2.go b/core/services/vrf/listener_v2.go index b367d8410ba..edd53e5b96a 100644 --- a/core/services/vrf/listener_v2.go +++ b/core/services/vrf/listener_v2.go @@ -599,9 +599,9 @@ func (lsn *listenerV2) processRequestsPerSubBatch( } } - // All fromAddresses passed to the VRFv2 job have the same KeySpecificMaxGasPriceWei value. + // All fromAddresses passed to the VRFv2 job have the same KeySpecific-MaxPrice value. fromAddresses := lsn.fromAddresses() - maxGasPriceWei := lsn.cfg.KeySpecificMaxGasPriceWei(fromAddresses[0]) + maxGasPriceWei := lsn.feeCfg.PriceMaxKey(fromAddresses[0]) // Cases: // 1. Never simulated: in this case, we want to observe the time until simulated @@ -879,9 +879,9 @@ func (lsn *listenerV2) processRequestsPerSub( } } - // All fromAddresses passed to the VRFv2 job have the same KeySpecificMaxGasPriceWei value. + // All fromAddresses passed to the VRFv2 job have the same KeySpecific-MaxPrice value. fromAddresses := lsn.fromAddresses() - maxGasPriceWei := lsn.cfg.KeySpecificMaxGasPriceWei(fromAddresses[0]) + maxGasPriceWei := lsn.feeCfg.PriceMaxKey(fromAddresses[0]) observeRequestSimDuration(lsn.job.Name.ValueOrZero(), lsn.job.ExternalJobID, v2, unfulfilled) pipelines := lsn.runPipelines(ctx, l, maxGasPriceWei, unfulfilled) for _, p := range pipelines { diff --git a/core/services/vrf/mocks/config.go b/core/services/vrf/mocks/config.go index ab0b4d5290b..574d448b94e 100644 --- a/core/services/vrf/mocks/config.go +++ b/core/services/vrf/mocks/config.go @@ -2,12 +2,7 @@ package mocks -import ( - common "github.com/ethereum/go-ethereum/common" - assets "github.com/smartcontractkit/chainlink/v2/core/assets" - - mock "github.com/stretchr/testify/mock" -) +import mock "github.com/stretchr/testify/mock" // Config is an autogenerated mock type for the Config type type Config struct { @@ -28,22 +23,6 @@ func (_m *Config) FinalityDepth() uint32 { return r0 } -// KeySpecificMaxGasPriceWei provides a mock function with given fields: addr -func (_m *Config) KeySpecificMaxGasPriceWei(addr common.Address) *assets.Wei { - ret := _m.Called(addr) - - var r0 *assets.Wei - if rf, ok := ret.Get(0).(func(common.Address) *assets.Wei); ok { - r0 = rf(addr) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).(*assets.Wei) - } - } - - return r0 -} - // MinIncomingConfirmations provides a mock function with given fields: func (_m *Config) MinIncomingConfirmations() uint32 { ret := _m.Called() diff --git a/core/web/eth_keys_controller.go b/core/web/eth_keys_controller.go index 9f82527e692..f796aefbe87 100644 --- a/core/web/eth_keys_controller.go +++ b/core/web/eth_keys_controller.go @@ -406,7 +406,7 @@ func (ekc *ETHKeysController) setKeyMaxGasPriceWei(state ethkey.State, keyAddres ekc.lggr.Errorw("Failed to get EVM Chain", "chainID", chainID, "err", err) } } else { - price = chain.Config().EVM().KeySpecificMaxGasPriceWei(keyAddress) + price = chain.Config().EVM().GasEstimator().PriceMaxKey(keyAddress) } return presenters.SetETHKeyMaxGasPriceWei(utils.NewBig(price.ToInt())) } diff --git a/core/web/evm_transfer_controller.go b/core/web/evm_transfer_controller.go index e373fbac1d0..7e7df04160c 100644 --- a/core/web/evm_transfer_controller.go +++ b/core/web/evm_transfer_controller.go @@ -99,7 +99,7 @@ func ValidateEthBalanceForTransfer(c *gin.Context, chain evm.Chain, fromAddr com gasLimit := chain.Config().EVM().GasEstimator().LimitTransfer() estimator := chain.GasEstimator() - fees, gasLimit, err = estimator.GetFee(c, nil, gasLimit, chain.Config().EVM().KeySpecificMaxGasPriceWei(fromAddr)) + fees, gasLimit, err = estimator.GetFee(c, nil, gasLimit, chain.Config().EVM().GasEstimator().PriceMaxKey(fromAddr)) if err != nil { return errors.Wrap(err, "failed to estimate gas") } diff --git a/core/web/resolver/eth_key.go b/core/web/resolver/eth_key.go index 9a5271c532f..868d53565dd 100644 --- a/core/web/resolver/eth_key.go +++ b/core/web/resolver/eth_key.go @@ -99,7 +99,7 @@ func (r *ETHKeyResolver) MaxGasPriceWei() *string { return nil } - gasPrice := r.key.chain.Config().EVM().KeySpecificMaxGasPriceWei(r.key.addr.Address()) + gasPrice := r.key.chain.Config().EVM().GasEstimator().PriceMaxKey(r.key.addr.Address()) if gasPrice != nil { val := gasPrice.ToInt().String() diff --git a/core/web/resolver/eth_key_test.go b/core/web/resolver/eth_key_test.go index 954cfbaa336..d437fac0958 100644 --- a/core/web/resolver/eth_key_test.go +++ b/core/web/resolver/eth_key_test.go @@ -12,6 +12,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/assets" "github.com/smartcontractkit/chainlink/v2/core/chains/evm" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config" + mocks2 "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/mocks" v2 "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/v2" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" @@ -20,14 +21,12 @@ import ( type mockEvmConfig struct { config.EVM - linkAddr string - maxGasPrice *assets.Wei + linkAddr string + gasEstimatorMock *mocks2.GasEstimator } -func (m *mockEvmConfig) LinkContractAddress() string { return m.linkAddr } -func (m *mockEvmConfig) KeySpecificMaxGasPriceWei(addr common.Address) *assets.Wei { - return m.maxGasPrice -} +func (m *mockEvmConfig) LinkContractAddress() string { return m.linkAddr } +func (m *mockEvmConfig) GasEstimator() config.GasEstimator { return m.gasEstimatorMock } func TestResolver_ETHKeys(t *testing.T) { t.Parallel() @@ -66,6 +65,9 @@ func TestResolver_ETHKeys(t *testing.T) { keysError := fmt.Errorf("error getting unlocked keys: %v", gError) statesError := fmt.Errorf("error getting key states: %v", gError) + evmMockConfig := mockEvmConfig{linkAddr: "0x5431F5F973781809D18643b87B44921b11355d81", gasEstimatorMock: mocks2.NewGasEstimator(t)} + evmMockConfig.gasEstimatorMock.On("PriceMaxKey", mock.Anything).Return(assets.NewWeiI(1)) + testCases := []GQLTestCase{ unauthorizedTestCase(GQLTestCase{query: query}, "ethKeys"), { @@ -98,7 +100,7 @@ func TestResolver_ETHKeys(t *testing.T) { f.App.On("GetKeyStore").Return(f.Mocks.keystore) f.App.On("EVMORM").Return(f.Mocks.evmORM) f.App.On("GetChains").Return(chainlink.Chains{EVM: f.Mocks.chainSet}) - f.Mocks.scfg.On("EVM").Return(&mockEvmConfig{linkAddr: "0x5431F5F973781809D18643b87B44921b11355d81", maxGasPrice: assets.NewWeiI(1)}) + f.Mocks.scfg.On("EVM").Return(&evmMockConfig) }, query: query, result: ` @@ -297,7 +299,7 @@ func TestResolver_ETHKeys(t *testing.T) { f.Mocks.chain.On("Config").Return(f.Mocks.scfg) f.Mocks.evmORM.PutChains(v2.EVMConfig{ChainID: &chainID}) f.App.On("EVMORM").Return(f.Mocks.evmORM) - f.Mocks.scfg.On("EVM").Return(&mockEvmConfig{linkAddr: "0x5431F5F973781809D18643b87B44921b11355d81", maxGasPrice: assets.NewWeiI(1)}) + f.Mocks.scfg.On("EVM").Return(&evmMockConfig) }, query: query, result: ` @@ -349,7 +351,7 @@ func TestResolver_ETHKeys(t *testing.T) { f.App.On("GetKeyStore").Return(f.Mocks.keystore) f.App.On("EVMORM").Return(f.Mocks.evmORM) f.App.On("GetChains").Return(chainlink.Chains{EVM: f.Mocks.chainSet}) - f.Mocks.scfg.On("EVM").Return(&mockEvmConfig{linkAddr: "0x5431F5F973781809D18643b87B44921b11355d81", maxGasPrice: assets.NewWeiI(1)}) + f.Mocks.scfg.On("EVM").Return(&evmMockConfig) }, query: query, result: `