From 58ba638437dda1c9c898f0fd07d547f98f5a6943 Mon Sep 17 00:00:00 2001 From: Jordan Krage Date: Tue, 25 Feb 2025 21:52:28 -0600 Subject: [PATCH] evm exaction: use agnostic keystore --- common/txmgr/types/mocks/key_store.go | 136 +++------ .../ocrimpls/contract_transmitter_test.go | 19 +- .../gateway_connector/service_wrapper.go | 42 ++- .../gateway_connector/service_wrapper_test.go | 6 +- core/chains/evm/log/broadcaster.go | 40 ++- core/chains/evm/log/helpers_test.go | 4 +- core/chains/evm/log/integration_test.go | 7 +- core/chains/evm/txm/attempt_builder.go | 16 +- core/chains/evm/txm/attempt_builder_test.go | 19 +- .../clientwrappers/dual_broadcast_client.go | 9 +- core/chains/evm/txm/orchestrator.go | 21 +- core/chains/evm/txm/txm.go | 8 +- core/chains/evm/txm/txm_test.go | 17 +- core/chains/evm/txmgr/attempts.go | 14 +- core/chains/evm/txmgr/attempts_test.go | 32 +-- .../evm/txmgr/broadcaster_benchmark_test.go | 11 +- core/chains/evm/txmgr/broadcaster_test.go | 178 ++++++------ core/chains/evm/txmgr/builder.go | 11 +- .../evm/txmgr/confirmer_benchmark_test.go | 50 ++-- core/chains/evm/txmgr/confirmer_test.go | 267 ++++++++---------- core/chains/evm/txmgr/models.go | 6 +- core/chains/evm/txmgr/resender_test.go | 25 +- core/chains/evm/txmgr/tracker_test.go | 24 +- core/chains/evm/txmgr/txmgr_test.go | 110 +++----- core/chains/legacyevm/chain.go | 23 +- core/chains/legacyevm/evm_txm.go | 6 +- core/chains/legacyevm/mocks/chain.go | 2 +- core/cmd/csa_keys_commands_test.go | 9 +- core/cmd/shell.go | 116 ++------ core/cmd/shell_local.go | 7 +- core/cmd/shell_local_test.go | 16 +- core/cmd/shell_test.go | 20 +- core/internal/cltest/cltest.go | 158 ++++------- core/internal/features/features_test.go | 7 +- .../features/ocr2/features_ocr2_helper.go | 5 +- .../features/ocr2/features_ocr2_test.go | 5 +- core/internal/testutils/evmtest/evmtest.go | 39 +-- core/scripts/go.mod | 8 +- core/scripts/go.sum | 16 +- core/services/blockhashstore/batch_bhs.go | 9 - core/services/blockhashstore/bhs.go | 15 +- core/services/blockhashstore/bhs_test.go | 27 +- core/services/blockhashstore/delegate.go | 17 +- .../blockheaderfeeder/block_header_feeder.go | 11 +- .../block_header_feeder_test.go | 11 +- core/services/blockheaderfeeder/delegate.go | 39 ++- core/services/chainlink/application.go | 185 +++++++----- .../chainlink/relayer_chain_interoperators.go | 31 +- .../relayer_chain_interoperators_test.go | 24 +- core/services/chainlink/relayer_factory.go | 59 ++-- core/services/feeds/connection_manager.go | 8 +- core/services/feeds/service.go | 72 ++--- core/services/feeds/service_test.go | 17 +- core/services/functions/connector_handler.go | 37 ++- .../functions/connector_handler_test.go | 7 +- core/services/gateway/api/message.go | 17 ++ core/services/gateway/common/utils.go | 3 + .../headreporter/prometheus_reporter_test.go | 3 +- core/services/job/job_orm_test.go | 26 +- .../job/job_pipeline_orm_integration_test.go | 2 +- core/services/job/orm.go | 18 +- core/services/job/runner_integration_test.go | 18 +- core/services/job/spawner_test.go | 20 +- core/services/keystore/beholder.go | 6 +- core/services/keystore/cosmos.go | 12 +- core/services/keystore/csa.go | 33 ++- core/services/keystore/eth.go | 51 +++- core/services/keystore/keystore.go | 26 ++ core/services/keystore/mocks/eth.go | 52 ++-- core/services/keystore/models.go | 68 ----- core/services/keystore/models_test.go | 74 ----- core/services/keystore/solana.go | 10 +- core/services/keystore/starknet.go | 11 +- core/services/keystore/tron.go | 10 +- core/services/llo/grpc/client.go | 17 +- core/services/llo/grpc/client_test.go | 16 +- .../llo/mercurytransmitter/transmitter.go | 11 +- .../mercurytransmitter/transmitter_test.go | 5 +- core/services/ocr/delegate.go | 19 +- core/services/ocr2/delegate.go | 11 +- .../ccip/testhelpers/integration/chainlink.go | 70 +---- .../testhelpers_1_4_0/chainlink.go | 75 ++--- .../plugins/ccip/transmitter/transmitter.go | 9 +- .../ccip/transmitter/transmitter_test.go | 38 +-- .../services/ocr2/plugins/functions/plugin.go | 30 +- .../ocr2/plugins/functions/plugin_test.go | 21 +- core/services/ocr2/plugins/ocr2keeper/util.go | 7 +- core/services/ocrcommon/dual_transmitter.go | 9 +- core/services/ocrcommon/transmitter.go | 65 ++--- core/services/ocrcommon/transmitter_test.go | 57 ++-- .../relay/evm/contract_transmitter.go | 20 +- .../relay/evm/contract_transmitter_test.go | 22 +- .../relay/evm/dual_contract_transmitter.go | 34 +-- .../evm/dual_contract_transmitter_test.go | 16 +- core/services/relay/evm/evm.go | 240 ++++------------ core/services/relay/evm/evm_test.go | 22 +- core/services/relay/evm/functions.go | 10 +- .../evm/functions/contract_transmitter.go | 15 +- .../functions/contract_transmitter_test.go | 35 +-- core/services/relay/evm/llo_provider.go | 136 +++++++-- .../relay/evm/mercury/helpers_test.go | 8 +- .../services/relay/evm/mercury/transmitter.go | 5 +- .../relay/evm/mercury/wsrpc/client.go | 22 +- .../relay/evm/mercury/wsrpc/client_test.go | 6 +- core/services/relay/evm/mercury/wsrpc/pool.go | 54 ++-- .../relay/evm/mercury/wsrpc/pool_test.go | 7 +- core/services/relay/evm/mercury_provider.go | 85 +++++- core/services/relay/evm/ocr2keeper.go | 6 +- core/services/relay/evm/relayer_extender.go | 48 ++-- .../relay/evm/relayer_extender_test.go | 76 ----- core/services/relay/evm/write_target_test.go | 11 +- core/services/synchronization/helpers_test.go | 8 +- .../telemetry_ingress_batch_client.go | 63 +++-- .../telemetry_ingress_batch_client_test.go | 6 +- .../telemetry_ingress_client.go | 58 ++-- .../telemetry_ingress_client_test.go | 10 +- core/services/telemetry/manager.go | 5 +- core/services/telemetry/manager_test.go | 15 +- core/services/vrf/delegate_test.go | 6 +- core/services/vrf/v2/integration_v2_test.go | 10 +- core/services/vrf/v2/listener_v2_test.go | 5 +- core/web/eth_keys_controller_test.go | 2 +- deployment/environment/memory/node.go | 116 ++------ deployment/go.mod | 8 +- deployment/go.sum | 16 +- go.mod | 8 +- go.sum | 16 +- integration-tests/go.mod | 8 +- integration-tests/go.sum | 16 +- integration-tests/load/go.mod | 8 +- integration-tests/load/go.sum | 16 +- system-tests/lib/go.mod | 8 +- system-tests/lib/go.sum | 16 +- system-tests/tests/go.mod | 8 +- system-tests/tests/go.sum | 16 +- 135 files changed, 1898 insertions(+), 2426 deletions(-) create mode 100644 core/services/keystore/keystore.go delete mode 100644 core/services/relay/evm/relayer_extender_test.go diff --git a/common/txmgr/types/mocks/key_store.go b/common/txmgr/types/mocks/key_store.go index 98c631f0e08..93651260995 100644 --- a/common/txmgr/types/mocks/key_store.go +++ b/common/txmgr/types/mocks/key_store.go @@ -11,29 +11,29 @@ import ( ) // KeyStore is an autogenerated mock type for the KeyStore type -type KeyStore[ADDR chains.Hashable, CHAIN_ID chains.ID] struct { +type KeyStore[ADDR chains.Hashable] struct { mock.Mock } -type KeyStore_Expecter[ADDR chains.Hashable, CHAIN_ID chains.ID] struct { +type KeyStore_Expecter[ADDR chains.Hashable] struct { mock *mock.Mock } -func (_m *KeyStore[ADDR, CHAIN_ID]) EXPECT() *KeyStore_Expecter[ADDR, CHAIN_ID] { - return &KeyStore_Expecter[ADDR, CHAIN_ID]{mock: &_m.Mock} +func (_m *KeyStore[ADDR]) EXPECT() *KeyStore_Expecter[ADDR] { + return &KeyStore_Expecter[ADDR]{mock: &_m.Mock} } -// CheckEnabled provides a mock function with given fields: ctx, address, chainID -func (_m *KeyStore[ADDR, CHAIN_ID]) CheckEnabled(ctx context.Context, address ADDR, chainID CHAIN_ID) error { - ret := _m.Called(ctx, address, chainID) +// CheckEnabled provides a mock function with given fields: ctx, address +func (_m *KeyStore[ADDR]) CheckEnabled(ctx context.Context, address ADDR) error { + ret := _m.Called(ctx, address) if len(ret) == 0 { panic("no return value specified for CheckEnabled") } var r0 error - if rf, ok := ret.Get(0).(func(context.Context, ADDR, CHAIN_ID) error); ok { - r0 = rf(ctx, address, chainID) + if rf, ok := ret.Get(0).(func(context.Context, ADDR) error); ok { + r0 = rf(ctx, address) } else { r0 = ret.Error(0) } @@ -42,161 +42,99 @@ func (_m *KeyStore[ADDR, CHAIN_ID]) CheckEnabled(ctx context.Context, address AD } // KeyStore_CheckEnabled_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'CheckEnabled' -type KeyStore_CheckEnabled_Call[ADDR chains.Hashable, CHAIN_ID chains.ID] struct { +type KeyStore_CheckEnabled_Call[ADDR chains.Hashable] struct { *mock.Call } // CheckEnabled is a helper method to define mock.On call // - ctx context.Context // - address ADDR -// - chainID CHAIN_ID -func (_e *KeyStore_Expecter[ADDR, CHAIN_ID]) CheckEnabled(ctx interface{}, address interface{}, chainID interface{}) *KeyStore_CheckEnabled_Call[ADDR, CHAIN_ID] { - return &KeyStore_CheckEnabled_Call[ADDR, CHAIN_ID]{Call: _e.mock.On("CheckEnabled", ctx, address, chainID)} +func (_e *KeyStore_Expecter[ADDR]) CheckEnabled(ctx interface{}, address interface{}) *KeyStore_CheckEnabled_Call[ADDR] { + return &KeyStore_CheckEnabled_Call[ADDR]{Call: _e.mock.On("CheckEnabled", ctx, address)} } -func (_c *KeyStore_CheckEnabled_Call[ADDR, CHAIN_ID]) Run(run func(ctx context.Context, address ADDR, chainID CHAIN_ID)) *KeyStore_CheckEnabled_Call[ADDR, CHAIN_ID] { +func (_c *KeyStore_CheckEnabled_Call[ADDR]) Run(run func(ctx context.Context, address ADDR)) *KeyStore_CheckEnabled_Call[ADDR] { _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(ADDR), args[2].(CHAIN_ID)) + run(args[0].(context.Context), args[1].(ADDR)) }) return _c } -func (_c *KeyStore_CheckEnabled_Call[ADDR, CHAIN_ID]) Return(_a0 error) *KeyStore_CheckEnabled_Call[ADDR, CHAIN_ID] { +func (_c *KeyStore_CheckEnabled_Call[ADDR]) Return(_a0 error) *KeyStore_CheckEnabled_Call[ADDR] { _c.Call.Return(_a0) return _c } -func (_c *KeyStore_CheckEnabled_Call[ADDR, CHAIN_ID]) RunAndReturn(run func(context.Context, ADDR, CHAIN_ID) error) *KeyStore_CheckEnabled_Call[ADDR, CHAIN_ID] { +func (_c *KeyStore_CheckEnabled_Call[ADDR]) RunAndReturn(run func(context.Context, ADDR) error) *KeyStore_CheckEnabled_Call[ADDR] { _c.Call.Return(run) return _c } -// EnabledAddressesForChain provides a mock function with given fields: ctx, chainID -func (_m *KeyStore[ADDR, CHAIN_ID]) EnabledAddressesForChain(ctx context.Context, chainID CHAIN_ID) ([]ADDR, error) { - ret := _m.Called(ctx, chainID) +// EnabledAddresses provides a mock function with given fields: ctx +func (_m *KeyStore[ADDR]) EnabledAddresses(ctx context.Context) ([]ADDR, error) { + ret := _m.Called(ctx) if len(ret) == 0 { - panic("no return value specified for EnabledAddressesForChain") + panic("no return value specified for EnabledAddresses") } var r0 []ADDR var r1 error - if rf, ok := ret.Get(0).(func(context.Context, CHAIN_ID) ([]ADDR, error)); ok { - return rf(ctx, chainID) - } - if rf, ok := ret.Get(0).(func(context.Context, CHAIN_ID) []ADDR); ok { - r0 = rf(ctx, chainID) - } else { - if ret.Get(0) != nil { - r0 = ret.Get(0).([]ADDR) - } - } - - if rf, ok := ret.Get(1).(func(context.Context, CHAIN_ID) error); ok { - r1 = rf(ctx, chainID) - } else { - r1 = ret.Error(1) - } - - return r0, r1 -} - -// KeyStore_EnabledAddressesForChain_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'EnabledAddressesForChain' -type KeyStore_EnabledAddressesForChain_Call[ADDR chains.Hashable, CHAIN_ID chains.ID] struct { - *mock.Call -} - -// EnabledAddressesForChain is a helper method to define mock.On call -// - ctx context.Context -// - chainID CHAIN_ID -func (_e *KeyStore_Expecter[ADDR, CHAIN_ID]) EnabledAddressesForChain(ctx interface{}, chainID interface{}) *KeyStore_EnabledAddressesForChain_Call[ADDR, CHAIN_ID] { - return &KeyStore_EnabledAddressesForChain_Call[ADDR, CHAIN_ID]{Call: _e.mock.On("EnabledAddressesForChain", ctx, chainID)} -} - -func (_c *KeyStore_EnabledAddressesForChain_Call[ADDR, CHAIN_ID]) Run(run func(ctx context.Context, chainID CHAIN_ID)) *KeyStore_EnabledAddressesForChain_Call[ADDR, CHAIN_ID] { - _c.Call.Run(func(args mock.Arguments) { - run(args[0].(context.Context), args[1].(CHAIN_ID)) - }) - return _c -} - -func (_c *KeyStore_EnabledAddressesForChain_Call[ADDR, CHAIN_ID]) Return(_a0 []ADDR, _a1 error) *KeyStore_EnabledAddressesForChain_Call[ADDR, CHAIN_ID] { - _c.Call.Return(_a0, _a1) - return _c -} - -func (_c *KeyStore_EnabledAddressesForChain_Call[ADDR, CHAIN_ID]) RunAndReturn(run func(context.Context, CHAIN_ID) ([]ADDR, error)) *KeyStore_EnabledAddressesForChain_Call[ADDR, CHAIN_ID] { - _c.Call.Return(run) - return _c -} - -// SubscribeToKeyChanges provides a mock function with given fields: ctx -func (_m *KeyStore[ADDR, CHAIN_ID]) SubscribeToKeyChanges(ctx context.Context) (chan struct{}, func()) { - ret := _m.Called(ctx) - - if len(ret) == 0 { - panic("no return value specified for SubscribeToKeyChanges") - } - - var r0 chan struct{} - var r1 func() - if rf, ok := ret.Get(0).(func(context.Context) (chan struct{}, func())); ok { + if rf, ok := ret.Get(0).(func(context.Context) ([]ADDR, error)); ok { return rf(ctx) } - if rf, ok := ret.Get(0).(func(context.Context) chan struct{}); ok { + if rf, ok := ret.Get(0).(func(context.Context) []ADDR); ok { r0 = rf(ctx) } else { if ret.Get(0) != nil { - r0 = ret.Get(0).(chan struct{}) + r0 = ret.Get(0).([]ADDR) } } - if rf, ok := ret.Get(1).(func(context.Context) func()); ok { + if rf, ok := ret.Get(1).(func(context.Context) error); ok { r1 = rf(ctx) } else { - if ret.Get(1) != nil { - r1 = ret.Get(1).(func()) - } + r1 = ret.Error(1) } return r0, r1 } -// KeyStore_SubscribeToKeyChanges_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'SubscribeToKeyChanges' -type KeyStore_SubscribeToKeyChanges_Call[ADDR chains.Hashable, CHAIN_ID chains.ID] struct { +// KeyStore_EnabledAddresses_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'EnabledAddresses' +type KeyStore_EnabledAddresses_Call[ADDR chains.Hashable] struct { *mock.Call } -// SubscribeToKeyChanges is a helper method to define mock.On call +// EnabledAddresses is a helper method to define mock.On call // - ctx context.Context -func (_e *KeyStore_Expecter[ADDR, CHAIN_ID]) SubscribeToKeyChanges(ctx interface{}) *KeyStore_SubscribeToKeyChanges_Call[ADDR, CHAIN_ID] { - return &KeyStore_SubscribeToKeyChanges_Call[ADDR, CHAIN_ID]{Call: _e.mock.On("SubscribeToKeyChanges", ctx)} +func (_e *KeyStore_Expecter[ADDR]) EnabledAddresses(ctx interface{}) *KeyStore_EnabledAddresses_Call[ADDR] { + return &KeyStore_EnabledAddresses_Call[ADDR]{Call: _e.mock.On("EnabledAddresses", ctx)} } -func (_c *KeyStore_SubscribeToKeyChanges_Call[ADDR, CHAIN_ID]) Run(run func(ctx context.Context)) *KeyStore_SubscribeToKeyChanges_Call[ADDR, CHAIN_ID] { +func (_c *KeyStore_EnabledAddresses_Call[ADDR]) Run(run func(ctx context.Context)) *KeyStore_EnabledAddresses_Call[ADDR] { _c.Call.Run(func(args mock.Arguments) { run(args[0].(context.Context)) }) return _c } -func (_c *KeyStore_SubscribeToKeyChanges_Call[ADDR, CHAIN_ID]) Return(ch chan struct{}, unsub func()) *KeyStore_SubscribeToKeyChanges_Call[ADDR, CHAIN_ID] { - _c.Call.Return(ch, unsub) +func (_c *KeyStore_EnabledAddresses_Call[ADDR]) Return(_a0 []ADDR, _a1 error) *KeyStore_EnabledAddresses_Call[ADDR] { + _c.Call.Return(_a0, _a1) return _c } -func (_c *KeyStore_SubscribeToKeyChanges_Call[ADDR, CHAIN_ID]) RunAndReturn(run func(context.Context) (chan struct{}, func())) *KeyStore_SubscribeToKeyChanges_Call[ADDR, CHAIN_ID] { +func (_c *KeyStore_EnabledAddresses_Call[ADDR]) RunAndReturn(run func(context.Context) ([]ADDR, error)) *KeyStore_EnabledAddresses_Call[ADDR] { _c.Call.Return(run) return _c } // NewKeyStore creates a new instance of KeyStore. It also registers a testing interface on the mock and a cleanup function to assert the mocks expectations. // The first argument is typically a *testing.T value. -func NewKeyStore[ADDR chains.Hashable, CHAIN_ID chains.ID](t interface { +func NewKeyStore[ADDR chains.Hashable](t interface { mock.TestingT Cleanup(func()) -}) *KeyStore[ADDR, CHAIN_ID] { - mock := &KeyStore[ADDR, CHAIN_ID]{} +}) *KeyStore[ADDR] { + mock := &KeyStore[ADDR]{} mock.Mock.Test(t) t.Cleanup(func() { mock.AssertExpectations(t) }) diff --git a/core/capabilities/ccip/ocrimpls/contract_transmitter_test.go b/core/capabilities/ccip/ocrimpls/contract_transmitter_test.go index ddfcfb52b05..b2c1c3bd81b 100644 --- a/core/capabilities/ccip/ocrimpls/contract_transmitter_test.go +++ b/core/capabilities/ccip/ocrimpls/contract_transmitter_test.go @@ -30,7 +30,8 @@ import ( "github.com/smartcontractkit/chainlink-integrations/evm/config/toml" "github.com/smartcontractkit/chainlink-integrations/evm/gas" "github.com/smartcontractkit/chainlink-integrations/evm/heads" - "github.com/smartcontractkit/chainlink-integrations/evm/keystore" + "github.com/smartcontractkit/chainlink-integrations/evm/keys" + "github.com/smartcontractkit/chainlink-integrations/evm/keys/keystest" "github.com/smartcontractkit/chainlink-integrations/evm/logpoller" evmtestutils "github.com/smartcontractkit/chainlink-integrations/evm/testutils" evmtypes "github.com/smartcontractkit/chainlink-integrations/evm/types" @@ -40,7 +41,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" "github.com/smartcontractkit/chainlink/v2/core/config" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/v1_6_0/multi_ocr3_helper" - "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" @@ -207,14 +207,15 @@ func newTestUniverse(t *testing.T, ks *keyringsAndSigners[[]byte]) *testUniverse db := pgtest.NewSqlxDB(t) owner := evmtestutils.MustNewSimTransactor(t) + keyStore := keystest.NewMemoryChainStore() // create many transmitters but only need to fund one, rest are to get // setOCR3Config to pass. - keyStore := cltest.NewKeyStore(t, db) + chainStore := keys.NewChainStore(keyStore, big.NewInt(1337)) var transmitters []common.Address for i := 0; i < 4; i++ { - key, err := keyStore.Eth().Create(testutils.Context(t), big.NewInt(1337)) + addr, err := keyStore.Create() require.NoError(t, err, "failed to create key") - transmitters = append(transmitters, key.Address) + transmitters = append(transmitters, addr) } backend := simulated.NewBackend(types.GenesisAlloc{ @@ -297,7 +298,7 @@ func newTestUniverse(t *testing.T, ks *keyringsAndSigners[[]byte]) *testUniverse simClient := client.NewSimulatedBackendClient(t, backend, testutils.SimulatedChainID) // create the chain writer service - txm, gasEstimator := makeTestEvmTxm(t, db, simClient, keyStore.Eth()) + txm, gasEstimator := makeTestEvmTxm(t, db, simClient, chainStore) require.NoError(t, txm.Start(testutils.Context(t)), "failed to start tx manager") t.Cleanup(func() { require.NoError(t, txm.Close()) }) @@ -408,11 +409,7 @@ func chainWriterConfigRaw(fromAddress common.Address, maxGasPrice *assets.Wei) e } } -func makeTestEvmTxm( - t *testing.T, - db *sqlx.DB, - ethClient client.Client, - keyStore keystore.Eth) (txmgr.TxManager, gas.EvmFeeEstimator) { +func makeTestEvmTxm(t *testing.T, db *sqlx.DB, ethClient client.Client, keyStore keys.ChainStore) (txmgr.TxManager, gas.EvmFeeEstimator) { config, dbConfig, evmConfig := MakeTestConfigs(t) estimator, err := gas.NewEstimator(logger.TestLogger(t), ethClient, config.ChainType(), ethClient.ConfiguredChainID(), evmConfig.GasEstimator(), nil) diff --git a/core/capabilities/gateway_connector/service_wrapper.go b/core/capabilities/gateway_connector/service_wrapper.go index 7aa9efd59b3..9bf111bb252 100644 --- a/core/capabilities/gateway_connector/service_wrapper.go +++ b/core/capabilities/gateway_connector/service_wrapper.go @@ -2,31 +2,31 @@ package gatewayconnector import ( "context" - "crypto/ecdsa" - "errors" - "math/big" - "slices" "github.com/ethereum/go-ethereum/common" "github.com/jonboulle/clockwork" "github.com/smartcontractkit/chainlink-common/pkg/services" + "github.com/smartcontractkit/chainlink-integrations/evm/keys" "github.com/smartcontractkit/chainlink/v2/core/config" "github.com/smartcontractkit/chainlink/v2/core/logger" gwcommon "github.com/smartcontractkit/chainlink/v2/core/services/gateway/common" "github.com/smartcontractkit/chainlink/v2/core/services/gateway/connector" "github.com/smartcontractkit/chainlink/v2/core/services/gateway/network" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" ) +type Keystore interface { + keys.AddressChecker + keys.MessageSigner +} + type ServiceWrapper struct { services.StateMachine + stopCh services.StopChan config config.GatewayConnector - keystore keystore.Eth + keystore Keystore connector connector.GatewayConnector - signerKey *ecdsa.PrivateKey lggr logger.Logger clock clockwork.Clock } @@ -50,8 +50,9 @@ func translateConfigs(f config.GatewayConnector) connector.ConnectorConfig { } // NOTE: this wrapper is needed to make sure that our services are started after Keystore. -func NewGatewayConnectorServiceWrapper(config config.GatewayConnector, keystore keystore.Eth, clock clockwork.Clock, lggr logger.Logger) *ServiceWrapper { +func NewGatewayConnectorServiceWrapper(config config.GatewayConnector, keystore Keystore, clock clockwork.Clock, lggr logger.Logger) *ServiceWrapper { return &ServiceWrapper{ + stopCh: make(services.StopChan), config: config, keystore: keystore, clock: clock, @@ -63,24 +64,11 @@ func (e *ServiceWrapper) Start(ctx context.Context) error { return e.StartOnce("GatewayConnectorServiceWrapper", func() error { conf := e.config nodeAddress := conf.NodeAddress() - chainID, _ := new(big.Int).SetString(conf.ChainIDForNodeKey(), 0) - enabledKeys, err := e.keystore.EnabledKeysForChain(ctx, chainID) + configuredNodeAddress := common.HexToAddress(nodeAddress) + err := e.keystore.CheckEnabled(ctx, configuredNodeAddress) if err != nil { return err } - if len(enabledKeys) == 0 { - return errors.New("no available keys found") - } - configuredNodeAddress := common.HexToAddress(nodeAddress) - idx := slices.IndexFunc(enabledKeys, func(key ethkey.KeyV2) bool { return key.Address == configuredNodeAddress }) - - if idx == -1 { - return errors.New("key for configured node address not found") - } - e.signerKey = enabledKeys[idx].ToEcdsaPrivKey() - if enabledKeys[idx].ID() != nodeAddress { - return errors.New("node address mismatch") - } translated := translateConfigs(conf) e.connector, err = connector.NewGatewayConnector(&translated, e, e.clock, e.lggr) @@ -92,11 +80,15 @@ func (e *ServiceWrapper) Start(ctx context.Context) error { } func (e *ServiceWrapper) Sign(data ...[]byte) ([]byte, error) { - return gwcommon.SignData(e.signerKey, data...) + ctx, cancel := e.stopCh.NewCtx() + defer cancel() + account := common.HexToAddress(e.config.NodeAddress()) + return e.keystore.SignMessage(ctx, account, gwcommon.Flatten(data...)) } func (e *ServiceWrapper) Close() error { return e.StopOnce("GatewayConnectorServiceWrapper", func() (err error) { + close(e.stopCh) return e.connector.Close() }) } diff --git a/core/capabilities/gateway_connector/service_wrapper_test.go b/core/capabilities/gateway_connector/service_wrapper_test.go index c88622fcd27..87295f3cecd 100644 --- a/core/capabilities/gateway_connector/service_wrapper_test.go +++ b/core/capabilities/gateway_connector/service_wrapper_test.go @@ -6,16 +6,15 @@ import ( "github.com/jonboulle/clockwork" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" + "github.com/smartcontractkit/chainlink-integrations/evm/keys/keystest" gatewayconnector "github.com/smartcontractkit/chainlink/v2/core/capabilities/gateway_connector" "github.com/smartcontractkit/chainlink/v2/core/config/toml" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" - ksmocks "github.com/smartcontractkit/chainlink/v2/core/services/keystore/mocks" ) func generateWrapper(t *testing.T, privateKey *ecdsa.PrivateKey, keystoreKey *ecdsa.PrivateKey) (*gatewayconnector.ServiceWrapper, error) { @@ -41,8 +40,7 @@ func generateWrapper(t *testing.T, privateKey *ecdsa.PrivateKey, keystoreKey *ec }, }, }.New() - ethKeystore := ksmocks.NewEth(t) - ethKeystore.On("EnabledKeysForChain", mock.Anything, mock.Anything).Return([]ethkey.KeyV2{keystoreKeyV2}, nil) + ethKeystore := &keystest.FakeChainStore{Addresses: keystest.Addresses{keystoreKeyV2.Address}} gc := config.Capabilities().GatewayConnector() wrapper := gatewayconnector.NewGatewayConnectorServiceWrapper(gc, ethKeystore, clockwork.NewFakeClock(), logger) require.NoError(t, err) diff --git a/core/chains/evm/log/broadcaster.go b/core/chains/evm/log/broadcaster.go index 6180435dcba..aaf5c531a6f 100644 --- a/core/chains/evm/log/broadcaster.go +++ b/core/chains/evm/log/broadcaster.go @@ -112,7 +112,7 @@ type ( wgDone sync.WaitGroup trackedAddressesCount atomic.Uint32 replayChannel chan replayRequest - highestSavedHead *evmtypes.Head + highestSavedHeadFn func(context.Context) (*evmtypes.Head, error) lastSeenHeadNumber atomic.Int64 logger logger.Logger @@ -163,7 +163,7 @@ const ( var _ Broadcaster = (*broadcaster)(nil) // NewBroadcaster creates a new instance of the broadcaster -func NewBroadcaster(orm ORM, ethClient evmclient.Client, config Config, lggr logger.Logger, highestSavedHead *evmtypes.Head, mailMon *mailbox.Monitor) *broadcaster { +func NewBroadcaster(orm ORM, ethClient evmclient.Client, config Config, lggr logger.Logger, highestSavedHead func(context.Context) (*evmtypes.Head, error), mailMon *mailbox.Monitor) *broadcaster { chStop := make(chan struct{}) lggr = logger.Named(lggr, "LogBroadcaster") chainId := ethClient.ConfiguredChainID() @@ -180,7 +180,7 @@ func NewBroadcaster(orm ORM, ethClient evmclient.Client, config Config, lggr log newHeads: mailbox.NewSingle[*evmtypes.Head](), DependentAwaiter: utils.NewDependentAwaiter(), chStop: chStop, - highestSavedHead: highestSavedHead, + highestSavedHeadFn: highestSavedHead, replayChannel: make(chan replayRequest, 1), } } @@ -295,6 +295,29 @@ func (b *broadcaster) IsConnected() bool { return b.connected.Load() } +func (b *broadcaster) highestSavedHead() (*evmtypes.Head, bool) { + if b.highestSavedHeadFn == nil { + return nil, true + } + ctx, cancel := b.chStop.NewCtx() + defer cancel() + var highestSavedHead *evmtypes.Head + for { + var err error + highestSavedHead, err = b.highestSavedHeadFn(ctx) + if err == nil { + break + } + //TODO log about failure + select { + case <-ctx.Done(): + return nil, false + case <-time.After(time.Second): //TODO exponential backoff + } + } + return highestSavedHead, true +} + // The subscription is closed in two cases: // - intentionally, when the set of contracts we're listening to changes // - on a connection error @@ -308,16 +331,21 @@ func (b *broadcaster) startResubscribeLoop() { var subscription managedSubscription = newNoopSubscription() defer func() { subscription.Unsubscribe() }() - if b.config.BlockBackfillSkip() && b.highestSavedHead != nil { + highestSavedHead, ok := b.highestSavedHead() + if !ok { + return + } + + if b.config.BlockBackfillSkip() && highestSavedHead != nil { b.logger.Warn("BlockBackfillSkip is set to true, preventing a deep backfill - some earlier chain events might be missed.") - } else if b.highestSavedHead != nil { + } else if highestSavedHead != nil { // The backfill needs to start at an earlier block than the one last saved in DB, to account for: // - keeping logs in the in-memory buffers in registration.go // (which will be lost on node restart) for MAX(NumConfirmations of subscribers) // - HeadTracker saving the heads to DB asynchronously versus LogBroadcaster, where a head // (or more heads on fast chains) may be saved but not yet processed by LB // using BlockBackfillDepth makes sure the backfill will be dependent on the per-chain configuration - from := b.highestSavedHead.Number - + from := highestSavedHead.Number - int64(b.registrations.highestNumConfirmations) - int64(b.config.BlockBackfillDepth()) if from < 0 { diff --git a/core/chains/evm/log/helpers_test.go b/core/chains/evm/log/helpers_test.go index ef4bcafe6bc..92470fce7e8 100644 --- a/core/chains/evm/log/helpers_test.go +++ b/core/chains/evm/log/helpers_test.go @@ -1,6 +1,8 @@ package log import ( + "context" + "github.com/ethereum/go-ethereum/core/types" "github.com/smartcontractkit/chainlink-common/pkg/logger" @@ -12,7 +14,7 @@ import ( // NewTestBroadcaster creates a broadcaster with Pause/Resume enabled. func NewTestBroadcaster(orm ORM, ethClient evmclient.Client, config Config, lggr logger.Logger, highestSavedHead *evmtypes.Head, mailMon *mailbox.Monitor) *broadcaster { - b := NewBroadcaster(orm, ethClient, config, lggr, highestSavedHead, mailMon) + b := NewBroadcaster(orm, ethClient, config, lggr, func(context.Context) (*evmtypes.Head, error) { return highestSavedHead, nil }, mailMon) b.testPause, b.testResume = make(chan struct{}), make(chan struct{}) return b } diff --git a/core/chains/evm/log/integration_test.go b/core/chains/evm/log/integration_test.go index cfa7464eb12..e9c60c4b988 100644 --- a/core/chains/evm/log/integration_test.go +++ b/core/chains/evm/log/integration_test.go @@ -1682,24 +1682,23 @@ func newBroadcasterHelperWithEthClient(t *testing.T, ethClient evmclient.Client, lb := log.NewTestBroadcaster(orm, ethClient, config, lggr, highestSeenHead, mailMon) kst := cltest.NewKeyStore(t, db) - chainsAndConfig := evmtest.NewLegacyChainsAndConfig(t, evmtest.TestChainOpts{ + legacyChains := evmtest.NewLegacyChains(t, evmtest.TestChainOpts{ Client: ethClient, ChainConfigs: globalConfig.EVMConfigs(), DatabaseConfig: globalConfig.Database(), FeatureConfig: globalConfig.Feature(), ListenerConfig: globalConfig.Database().Listener(), - DB: db, KeyStore: kst.Eth(), + DB: db, LogBroadcaster: &log.NullBroadcaster{}, MailMon: mailMon, }) m := make(map[string]legacyevm.Chain) - for _, r := range chainsAndConfig.Slice() { + for _, r := range legacyChains.Slice() { m[r.ID().String()] = r } - legacyChains := chainsAndConfig.NewLegacyChains() pipelineHelper := cltest.NewJobPipelineV2(t, globalConfig.WebServer(), globalConfig.JobPipeline(), legacyChains, db, kst, nil, nil) return &broadcasterHelper{ diff --git a/core/chains/evm/txm/attempt_builder.go b/core/chains/evm/txm/attempt_builder.go index c8fb098de9b..70faa3673cd 100644 --- a/core/chains/evm/txm/attempt_builder.go +++ b/core/chains/evm/txm/attempt_builder.go @@ -9,26 +9,20 @@ import ( evmtypes "github.com/ethereum/go-ethereum/core/types" "github.com/smartcontractkit/chainlink-common/pkg/logger" - "github.com/smartcontractkit/chainlink-integrations/evm/assets" "github.com/smartcontractkit/chainlink-integrations/evm/gas" + "github.com/smartcontractkit/chainlink-integrations/evm/keys" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txm/types" ) -type AttemptBuilderKeystore interface { - SignTx(ctx context.Context, fromAddress common.Address, tx *evmtypes.Transaction, chainID *big.Int) (*evmtypes.Transaction, error) -} - type attemptBuilder struct { gas.EvmFeeEstimator - chainID *big.Int priceMaxKey func(common.Address) *assets.Wei - keystore AttemptBuilderKeystore + keystore keys.TxSigner } -func NewAttemptBuilder(chainID *big.Int, priceMaxKey func(common.Address) *assets.Wei, estimator gas.EvmFeeEstimator, keystore AttemptBuilderKeystore) *attemptBuilder { +func NewAttemptBuilder(priceMaxKey func(common.Address) *assets.Wei, estimator gas.EvmFeeEstimator, keystore keys.TxSigner) *attemptBuilder { return &attemptBuilder{ - chainID: chainID, priceMaxKey: priceMaxKey, EvmFeeEstimator: estimator, keystore: keystore, @@ -104,7 +98,7 @@ func (a *attemptBuilder) newLegacyAttempt(ctx context.Context, tx *types.Transac Data: data, } - signedTx, err := a.keystore.SignTx(ctx, tx.FromAddress, evmtypes.NewTx(&legacyTx), a.chainID) + signedTx, err := a.keystore.SignTx(ctx, tx.FromAddress, evmtypes.NewTx(&legacyTx)) if err != nil { return nil, fmt.Errorf("failed to sign attempt for txID: %v, err: %w", tx.ID, err) } @@ -143,7 +137,7 @@ func (a *attemptBuilder) newDynamicFeeAttempt(ctx context.Context, tx *types.Tra Data: data, } - signedTx, err := a.keystore.SignTx(ctx, tx.FromAddress, evmtypes.NewTx(&dynamicTx), a.chainID) + signedTx, err := a.keystore.SignTx(ctx, tx.FromAddress, evmtypes.NewTx(&dynamicTx)) if err != nil { return nil, fmt.Errorf("failed to sign attempt for txID: %v, err: %w", tx.ID, err) } diff --git a/core/chains/evm/txm/attempt_builder_test.go b/core/chains/evm/txm/attempt_builder_test.go index bfc06a88ebe..7738a77caf7 100644 --- a/core/chains/evm/txm/attempt_builder_test.go +++ b/core/chains/evm/txm/attempt_builder_test.go @@ -1,29 +1,24 @@ package txm import ( - "math/big" "testing" evmtypes "github.com/ethereum/go-ethereum/core/types" "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/utils/tests" - "github.com/smartcontractkit/chainlink-integrations/evm/assets" "github.com/smartcontractkit/chainlink-integrations/evm/gas" - "github.com/smartcontractkit/chainlink-integrations/evm/keystore/mocks" + "github.com/smartcontractkit/chainlink-integrations/evm/keys/keystest" "github.com/smartcontractkit/chainlink-integrations/evm/testutils" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txm/types" ) func TestAttemptBuilder_newLegacyAttempt(t *testing.T) { - ks := mocks.NewEth(t) - ab := NewAttemptBuilder(testutils.FixtureChainID, nil, nil, ks) + ab := NewAttemptBuilder(nil, nil, keystest.TxSigner(nil)) address := testutils.NewAddress() - toAddress := testutils.NewAddress() lggr := logger.Test(t) var gasLimit uint64 = 100 @@ -44,8 +39,6 @@ func TestAttemptBuilder_newLegacyAttempt(t *testing.T) { t.Run("creates attempt with fields", func(t *testing.T) { var nonce uint64 = 77 tx := &types.Transaction{ID: 10, FromAddress: address, Nonce: &nonce} - legacyTx := evmtypes.NewTx(&evmtypes.LegacyTx{Nonce: nonce, To: &toAddress, Gas: gasLimit, GasPrice: big.NewInt(25)}) - ks.On("SignTx", mock.Anything, mock.Anything, mock.Anything, testutils.FixtureChainID).Return(legacyTx, nil).Once() a, err := ab.newCustomAttempt(tests.Context(t), tx, gas.EvmFee{GasPrice: assets.NewWeiI(25)}, gasLimit, evmtypes.LegacyTxType, lggr) require.NoError(t, err) assert.Equal(t, tx.ID, a.TxID) @@ -59,10 +52,9 @@ func TestAttemptBuilder_newLegacyAttempt(t *testing.T) { } func TestAttemptBuilder_newDynamicFeeAttempt(t *testing.T) { - ks := mocks.NewEth(t) - ab := NewAttemptBuilder(testutils.FixtureChainID, nil, nil, ks) + ab := NewAttemptBuilder(nil, nil, keystest.TxSigner(nil)) address := testutils.NewAddress() - toAddress := testutils.NewAddress() + lggr := logger.Test(t) var gasLimit uint64 = 100 @@ -83,8 +75,7 @@ func TestAttemptBuilder_newDynamicFeeAttempt(t *testing.T) { t.Run("creates attempt with fields", func(t *testing.T) { var nonce uint64 = 77 tx := &types.Transaction{ID: 10, FromAddress: address, Nonce: &nonce} - legacyTx := evmtypes.NewTx(&evmtypes.LegacyTx{Nonce: nonce, To: &toAddress, Gas: gasLimit, GasPrice: big.NewInt(25)}) - ks.On("SignTx", mock.Anything, mock.Anything, mock.Anything, testutils.FixtureChainID).Return(legacyTx, nil).Once() + a, err := ab.newCustomAttempt(tests.Context(t), tx, gas.EvmFee{DynamicFee: gas.DynamicFee{GasTipCap: assets.NewWeiI(1), GasFeeCap: assets.NewWeiI(2)}}, gasLimit, evmtypes.DynamicFeeTxType, lggr) require.NoError(t, err) assert.Equal(t, tx.ID, a.TxID) diff --git a/core/chains/evm/txm/clientwrappers/dual_broadcast_client.go b/core/chains/evm/txm/clientwrappers/dual_broadcast_client.go index 04ab5a8e203..ee86778e84b 100644 --- a/core/chains/evm/txm/clientwrappers/dual_broadcast_client.go +++ b/core/chains/evm/txm/clientwrappers/dual_broadcast_client.go @@ -16,20 +16,17 @@ import ( "github.com/ethereum/go-ethereum/crypto" "github.com/smartcontractkit/chainlink-integrations/evm/client" + "github.com/smartcontractkit/chainlink-integrations/evm/keys" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txm/types" ) -type DualBroadcastClientKeystore interface { - SignMessage(ctx context.Context, address common.Address, message []byte) ([]byte, error) -} - type DualBroadcastClient struct { c client.Client - keystore DualBroadcastClientKeystore + keystore keys.MessageSigner customURL *url.URL } -func NewDualBroadcastClient(c client.Client, keystore DualBroadcastClientKeystore, customURL *url.URL) *DualBroadcastClient { +func NewDualBroadcastClient(c client.Client, keystore keys.MessageSigner, customURL *url.URL) *DualBroadcastClient { return &DualBroadcastClient{ c: c, keystore: keystore, diff --git a/core/chains/evm/txm/orchestrator.go b/core/chains/evm/txm/orchestrator.go index be77029bbae..4c6167d88bd 100644 --- a/core/chains/evm/txm/orchestrator.go +++ b/core/chains/evm/txm/orchestrator.go @@ -18,11 +18,11 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/sqlutil" commontypes "github.com/smartcontractkit/chainlink-common/pkg/types" "github.com/smartcontractkit/chainlink-common/pkg/utils" - "github.com/smartcontractkit/chainlink-framework/chains" "github.com/smartcontractkit/chainlink-framework/chains/txmgr" txmgrtypes "github.com/smartcontractkit/chainlink-framework/chains/txmgr/types" "github.com/smartcontractkit/chainlink-integrations/evm/gas" + "github.com/smartcontractkit/chainlink-integrations/evm/keys" evmtypes "github.com/smartcontractkit/chainlink-integrations/evm/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/forwarders" txmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txm/types" @@ -34,11 +34,6 @@ type OrchestratorTxStore interface { FindTxWithIdempotencyKey(context.Context, string) (*txmtypes.Transaction, error) } -type OrchestratorKeystore interface { - CheckEnabled(ctx context.Context, address common.Address, chainID *big.Int) error - EnabledAddressesForChain(ctx context.Context, chainID *big.Int) (addresses []common.Address, err error) -} - type OrchestratorAttemptBuilder[ BLOCK_HASH chains.Hashable, HEAD chains.Head[BLOCK_HASH], @@ -58,7 +53,7 @@ type Orchestrator[ txm *Txm txStore OrchestratorTxStore fwdMgr *forwarders.FwdMgr - keystore OrchestratorKeystore + keystore keys.Addresses attemptBuilder OrchestratorAttemptBuilder[BLOCK_HASH, HEAD] resumeCallback txmgr.ResumeCallback } @@ -69,7 +64,7 @@ func NewTxmOrchestrator[BLOCK_HASH chains.Hashable, HEAD chains.Head[BLOCK_HASH] txm *Txm, txStore OrchestratorTxStore, fwdMgr *forwarders.FwdMgr, - keystore OrchestratorKeystore, + keystore keys.Addresses, attemptBuilder OrchestratorAttemptBuilder[BLOCK_HASH, HEAD], ) *Orchestrator[BLOCK_HASH, HEAD] { return &Orchestrator[BLOCK_HASH, HEAD]{ @@ -92,7 +87,7 @@ func (o *Orchestrator[BLOCK_HASH, HEAD]) Start(ctx context.Context) error { return fmt.Errorf("Orchestrator: AttemptBuilder failed to start: %w", err) } } - addresses, err := o.keystore.EnabledAddressesForChain(ctx, o.chainID) + addresses, err := o.keystore.EnabledAddresses(ctx) if err != nil { return err } @@ -171,6 +166,8 @@ func (o *Orchestrator[BLOCK_HASH, HEAD]) OnNewLongestChain(ctx context.Context, } } +type NotEnabledError = txmgr.NotEnabledError[common.Address] + func (o *Orchestrator[BLOCK_HASH, HEAD]) CreateTransaction(ctx context.Context, request txmgrtypes.TxRequest[common.Address, common.Hash]) (tx txmgrtypes.Tx[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee], err error) { var wrappedTx *txmtypes.Transaction if request.IdempotencyKey != nil { @@ -183,8 +180,8 @@ func (o *Orchestrator[BLOCK_HASH, HEAD]) CreateTransaction(ctx context.Context, if wrappedTx != nil { o.lggr.Infof("Found Tx with IdempotencyKey: %v. Returning existing Tx without creating a new one.", *wrappedTx.IdempotencyKey) } else { - if kErr := o.keystore.CheckEnabled(ctx, request.FromAddress, o.chainID); kErr != nil { - return tx, fmt.Errorf("cannot send transaction from %s on chain ID %s: %w", request.FromAddress, o.chainID.String(), kErr) + if kErr := o.keystore.CheckEnabled(ctx, request.FromAddress); kErr != nil { + return tx, NotEnabledError{FromAddress: request.FromAddress, Err: err} } var pipelineTaskRunID uuid.NullUUID @@ -271,7 +268,7 @@ func (o *Orchestrator[BLOCK_HASH, HEAD]) CreateTransaction(ctx context.Context, // CountTransactionsByState was required for backwards compatibility and it's used only for unconfirmed transactions. func (o *Orchestrator[BLOCK_HASH, HEAD]) CountTransactionsByState(ctx context.Context, state txmgrtypes.TxState) (uint32, error) { - addresses, err := o.keystore.EnabledAddressesForChain(ctx, o.chainID) + addresses, err := o.keystore.EnabledAddresses(ctx) if err != nil { return 0, err } diff --git a/core/chains/evm/txm/txm.go b/core/chains/evm/txm/txm.go index 71e6031bad7..ac161069cea 100644 --- a/core/chains/evm/txm/txm.go +++ b/core/chains/evm/txm/txm.go @@ -13,7 +13,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/services" "github.com/smartcontractkit/chainlink-common/pkg/utils" - + "github.com/smartcontractkit/chainlink-integrations/evm/keys" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txm/types" ) @@ -81,7 +81,7 @@ type Txm struct { errorHandler ErrorHandler stuckTxDetector StuckTxDetector txStore TxStore - keystore Keystore + keystore keys.AddressLister config Config metrics *txmMetrics @@ -93,7 +93,7 @@ type Txm struct { wg sync.WaitGroup } -func NewTxm(lggr logger.Logger, chainID *big.Int, client Client, attemptBuilder AttemptBuilder, txStore TxStore, stuckTxDetector StuckTxDetector, config Config, keystore Keystore) *Txm { +func NewTxm(lggr logger.Logger, chainID *big.Int, client Client, attemptBuilder AttemptBuilder, txStore TxStore, stuckTxDetector StuckTxDetector, config Config, keystore keys.AddressLister) *Txm { return &Txm{ lggr: logger.Sugared(logger.Named(lggr, "Txm")), keystore: keystore, @@ -117,7 +117,7 @@ func (t *Txm) Start(ctx context.Context) error { t.metrics = tm t.stopCh = make(chan struct{}) - addresses, err := t.keystore.EnabledAddressesForChain(ctx, t.chainID) + addresses, err := t.keystore.EnabledAddresses(ctx) if err != nil { return err } diff --git a/core/chains/evm/txm/txm_test.go b/core/chains/evm/txm/txm_test.go index 13b987000ed..ea5f22abf6e 100644 --- a/core/chains/evm/txm/txm_test.go +++ b/core/chains/evm/txm/txm_test.go @@ -15,9 +15,9 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" "github.com/smartcontractkit/chainlink-common/pkg/utils/tests" - "github.com/smartcontractkit/chainlink-integrations/evm/assets" "github.com/smartcontractkit/chainlink-integrations/evm/gas" + "github.com/smartcontractkit/chainlink-integrations/evm/keys/keystest" "github.com/smartcontractkit/chainlink-integrations/evm/testutils" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txm/storage" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txm/types" @@ -32,14 +32,13 @@ func TestLifecycle(t *testing.T) { address2 := testutils.NewAddress() assert.NotEqual(t, address1, address2) addresses := []common.Address{address1, address2} - keystore := newMockKeystore(t) t.Run("retries if initial pending nonce call fails", func(t *testing.T) { lggr, observedLogs := logger.TestObserved(t, zap.DebugLevel) config := Config{BlockTime: 1 * time.Minute} txStore := storage.NewInMemoryStoreManager(lggr, testutils.FixtureChainID) require.NoError(t, txStore.Add(address1)) - keystore.On("EnabledAddressesForChain", mock.Anything, mock.Anything).Return([]common.Address{address1}, nil).Once() + keystore := keystest.Addresses{address1} txm := NewTxm(lggr, testutils.FixtureChainID, client, nil, txStore, nil, config, keystore) client.On("PendingNonceAt", mock.Anything, address1).Return(uint64(0), errors.New("error")).Once() client.On("PendingNonceAt", mock.Anything, address1).Return(uint64(100), nil).Once() @@ -50,7 +49,7 @@ func TestLifecycle(t *testing.T) { t.Run("tests lifecycle successfully without any transactions", func(t *testing.T) { config := Config{BlockTime: 200 * time.Millisecond} - keystore.On("EnabledAddressesForChain", mock.Anything, mock.Anything).Return(addresses, nil).Once() + keystore := keystest.Addresses(addresses) lggr, observedLogs := logger.TestObserved(t, zap.DebugLevel) txStore := storage.NewInMemoryStoreManager(lggr, testutils.FixtureChainID) require.NoError(t, txStore.Add(addresses...)) @@ -72,10 +71,10 @@ func TestTrigger(t *testing.T) { t.Parallel() address := testutils.NewAddress() - keystore := newMockKeystore(t) + t.Run("Trigger fails if Txm is unstarted", func(t *testing.T) { lggr, observedLogs := logger.TestObserved(t, zap.ErrorLevel) - txm := NewTxm(lggr, nil, nil, nil, nil, nil, Config{}, keystore) + txm := NewTxm(lggr, nil, nil, nil, nil, nil, Config{}, keystest.Addresses{}) txm.Trigger(address) tests.AssertLogEventually(t, observedLogs, "Txm unstarted") }) @@ -87,7 +86,7 @@ func TestTrigger(t *testing.T) { client := newMockClient(t) ab := newMockAttemptBuilder(t) config := Config{BlockTime: 1 * time.Minute, RetryBlockThreshold: 10} - keystore.On("EnabledAddressesForChain", mock.Anything, mock.Anything).Return([]common.Address{address}, nil) + keystore := keystest.Addresses{address} txm := NewTxm(lggr, testutils.FixtureChainID, client, ab, txStore, nil, config, keystore) var nonce uint64 // Start @@ -105,7 +104,7 @@ func TestBroadcastTransaction(t *testing.T) { ab := newMockAttemptBuilder(t) config := Config{} address := testutils.NewAddress() - keystore := newMockKeystore(t) + keystore := keystest.Addresses{} t.Run("fails if FetchUnconfirmedTransactionAtNonceWithCount for unconfirmed transactions fails", func(t *testing.T) { mTxStore := newMockTxStore(t) @@ -221,7 +220,7 @@ func TestBackfillTransactions(t *testing.T) { txStore := newMockTxStore(t) config := Config{} address := testutils.NewAddress() - keystore := newMockKeystore(t) + keystore := keystest.Addresses{} t.Run("fails if latest nonce fetching fails", func(t *testing.T) { txm := NewTxm(logger.Test(t), testutils.FixtureChainID, client, ab, txStore, nil, config, keystore) diff --git a/core/chains/evm/txmgr/attempts.go b/core/chains/evm/txmgr/attempts.go index 2028b47de2a..4ea4f0e7573 100644 --- a/core/chains/evm/txmgr/attempts.go +++ b/core/chains/evm/txmgr/attempts.go @@ -11,26 +11,20 @@ import ( pkgerrors "github.com/pkg/errors" "github.com/smartcontractkit/chainlink-common/pkg/logger" - - commontypes "github.com/smartcontractkit/chainlink-framework/chains" "github.com/smartcontractkit/chainlink-framework/chains/fees" txmgrtypes "github.com/smartcontractkit/chainlink-framework/chains/txmgr/types" - "github.com/smartcontractkit/chainlink-integrations/evm/assets" "github.com/smartcontractkit/chainlink-integrations/evm/gas" + "github.com/smartcontractkit/chainlink-integrations/evm/keys" evmtypes "github.com/smartcontractkit/chainlink-integrations/evm/types" ) -type TxAttemptSigner[ADDR commontypes.Hashable] interface { - SignTx(ctx context.Context, fromAddress ADDR, tx *types.Transaction, chainID *big.Int) (*types.Transaction, error) -} - var _ TxAttemptBuilder = (*evmTxAttemptBuilder)(nil) type evmTxAttemptBuilder struct { chainID big.Int feeConfig evmTxAttemptBuilderFeeConfig - keystore TxAttemptSigner[common.Address] + keystore keys.TxSigner gas.EvmFeeEstimator } @@ -40,7 +34,7 @@ type evmTxAttemptBuilderFeeConfig interface { LimitDefault() uint64 } -func NewEvmTxAttemptBuilder(chainID big.Int, feeConfig evmTxAttemptBuilderFeeConfig, keystore TxAttemptSigner[common.Address], estimator gas.EvmFeeEstimator) *evmTxAttemptBuilder { +func NewEvmTxAttemptBuilder(chainID big.Int, feeConfig evmTxAttemptBuilderFeeConfig, keystore keys.TxSigner, estimator gas.EvmFeeEstimator) *evmTxAttemptBuilder { return &evmTxAttemptBuilder{chainID, feeConfig, keystore, estimator} } @@ -322,7 +316,7 @@ func newLegacyTransaction(nonce uint64, to common.Address, value *big.Int, gasLi } func (c *evmTxAttemptBuilder) SignTx(ctx context.Context, address common.Address, tx *types.Transaction) (common.Hash, []byte, error) { - signedTx, err := c.keystore.SignTx(ctx, address, tx, &c.chainID) + signedTx, err := c.keystore.SignTx(ctx, address, tx) if err != nil { return common.Hash{}, nil, fmt.Errorf("failed to sign tx: %w", err) } diff --git a/core/chains/evm/txmgr/attempts_test.go b/core/chains/evm/txmgr/attempts_test.go index 9f83ac9e44b..43f56491572 100644 --- a/core/chains/evm/txmgr/attempts_test.go +++ b/core/chains/evm/txmgr/attempts_test.go @@ -7,7 +7,6 @@ import ( gethcommon "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" - "github.com/ethereum/go-ethereum/core/types" gethtypes "github.com/ethereum/go-ethereum/core/types" pkgerrors "github.com/pkg/errors" "github.com/stretchr/testify/assert" @@ -16,12 +15,11 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/utils/tests" - "github.com/smartcontractkit/chainlink-integrations/evm/assets" "github.com/smartcontractkit/chainlink-integrations/evm/config/toml" "github.com/smartcontractkit/chainlink-integrations/evm/gas" gasmocks "github.com/smartcontractkit/chainlink-integrations/evm/gas/mocks" - ksmocks "github.com/smartcontractkit/chainlink-integrations/evm/keystore/mocks" + "github.com/smartcontractkit/chainlink-integrations/evm/keys/keystest" "github.com/smartcontractkit/chainlink-integrations/evm/testutils" evmtypes "github.com/smartcontractkit/chainlink-integrations/evm/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" @@ -69,8 +67,7 @@ func TestTxm_SignTx(t *testing.T) { t.Run("returns correct hash for non-okex chains", func(t *testing.T) { chainID := big.NewInt(1) - kst := ksmocks.NewEth(t) - kst.On("SignTx", mock.Anything, to, tx, chainID).Return(tx, nil).Once() + kst := keystest.TxSigner(nil) cks := txmgr.NewEvmTxAttemptBuilder(*chainID, newFeeConfig(), kst, nil) hash, rawBytes, err := cks.SignTx(tests.Context(t), addr, tx) require.NoError(t, err) @@ -80,8 +77,7 @@ 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) - kst := ksmocks.NewEth(t) - kst.On("SignTx", mock.Anything, to, tx, chainID).Return(tx, nil).Once() + kst := keystest.TxSigner(nil) cks := txmgr.NewEvmTxAttemptBuilder(*chainID, newFeeConfig(), kst, nil) hash, rawBytes, err := cks.SignTx(tests.Context(t), addr, tx) require.NoError(t, err) @@ -90,8 +86,7 @@ func TestTxm_SignTx(t *testing.T) { }) t.Run("can properly encoded and decode raw transaction for LegacyTx", func(t *testing.T) { chainID := big.NewInt(1) - kst := ksmocks.NewEth(t) - kst.On("SignTx", mock.Anything, to, tx, chainID).Return(tx, nil).Once() + kst := keystest.TxSigner(nil) cks := txmgr.NewEvmTxAttemptBuilder(*chainID, newFeeConfig(), kst, nil) _, rawBytes, err := cks.SignTx(tests.Context(t), addr, tx) @@ -106,7 +101,7 @@ func TestTxm_SignTx(t *testing.T) { }) t.Run("can properly encoded and decode raw transaction for DynamicFeeTx", func(t *testing.T) { chainID := big.NewInt(1) - kst := ksmocks.NewEth(t) + kst := keystest.TxSigner(nil) typedTx := gethtypes.NewTx(&gethtypes.DynamicFeeTx{ Nonce: 42, To: &to, @@ -114,7 +109,6 @@ func TestTxm_SignTx(t *testing.T) { Gas: 242, Data: []byte{1, 2, 3}, }) - kst.On("SignTx", mock.Anything, to, typedTx, chainID).Return(typedTx, nil).Once() cks := txmgr.NewEvmTxAttemptBuilder(*chainID, newFeeConfig(), kst, nil) _, rawBytes, err := cks.SignTx(tests.Context(t), addr, typedTx) require.NoError(t, err) @@ -130,9 +124,7 @@ func TestTxm_SignTx(t *testing.T) { func TestTxm_NewDynamicFeeTx(t *testing.T) { addr := NewEvmAddress() - tx := types.NewTx(&types.DynamicFeeTx{}) - kst := ksmocks.NewEth(t) - kst.On("SignTx", mock.Anything, addr, mock.Anything, big.NewInt(1)).Return(tx, nil) + kst := keystest.TxSigner(nil) var n evmtypes.Nonce lggr := logger.Test(t) @@ -193,9 +185,7 @@ func TestTxm_NewDynamicFeeTx(t *testing.T) { func TestTxm_NewLegacyAttempt(t *testing.T) { addr := NewEvmAddress() - kst := ksmocks.NewEth(t) - tx := types.NewTx(&types.LegacyTx{}) - kst.On("SignTx", mock.Anything, addr, mock.Anything, big.NewInt(1)).Return(tx, nil) + kst := keystest.TxSigner(nil) gc := newFeeConfig() gc.priceMin = assets.NewWeiI(10) gc.priceMax = assets.NewWeiI(50) @@ -222,9 +212,7 @@ func TestTxm_NewLegacyAttempt(t *testing.T) { func TestTxm_NewPurgeAttempt(t *testing.T) { addr := NewEvmAddress() - kst := ksmocks.NewEth(t) - tx := types.NewTx(&types.LegacyTx{}) - kst.On("SignTx", mock.Anything, addr, mock.Anything, big.NewInt(1)).Return(tx, nil) + kst := keystest.TxSigner(nil) gc := newFeeConfig() gc.priceMin = assets.GWei(10) gc.priceMax = assets.GWei(50) @@ -304,7 +292,7 @@ func TestTxm_NewPurgeAttempt(t *testing.T) { func TestTxm_NewCustomTxAttempt_NonRetryableErrors(t *testing.T) { t.Parallel() - kst := ksmocks.NewEth(t) + kst := keystest.TxSigner(nil) lggr := logger.Test(t) cks := txmgr.NewEvmTxAttemptBuilder(*big.NewInt(1), newFeeConfig(), kst, nil) @@ -336,7 +324,7 @@ func TestTxm_EvmTxAttemptBuilder_RetryableEstimatorError(t *testing.T) { est.On("GetFee", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(gas.EvmFee{}, uint64(0), pkgerrors.New("fail")) est.On("BumpFee", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(gas.EvmFee{}, uint64(0), pkgerrors.New("fail")) - kst := ksmocks.NewEth(t) + kst := keystest.TxSigner(nil) lggr := logger.Test(t) ctx := tests.Context(t) cks := txmgr.NewEvmTxAttemptBuilder(*big.NewInt(1), &feeConfig{eip1559DynamicFees: true}, kst, est) diff --git a/core/chains/evm/txmgr/broadcaster_benchmark_test.go b/core/chains/evm/txmgr/broadcaster_benchmark_test.go index 05ced89525c..36470db1a53 100644 --- a/core/chains/evm/txmgr/broadcaster_benchmark_test.go +++ b/core/chains/evm/txmgr/broadcaster_benchmark_test.go @@ -9,6 +9,8 @@ import ( gethCommon "github.com/ethereum/go-ethereum/common" "github.com/jmoiron/sqlx" + "github.com/smartcontractkit/chainlink-integrations/evm/keys" + "github.com/smartcontractkit/chainlink-integrations/evm/keys/keystest" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" @@ -21,6 +23,7 @@ import ( "github.com/smartcontractkit/chainlink-integrations/evm/client/clienttest" "github.com/smartcontractkit/chainlink-integrations/evm/config/configtest" "github.com/smartcontractkit/chainlink-integrations/evm/testutils" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" ) @@ -29,9 +32,12 @@ import ( func BenchmarkEthBroadcaster_ProcessUnstartedEthTxs_Success(b *testing.B) { db := testutils.NewSqlxDB(b) ctx := tests.Context(b) + + ethClient := clienttest.NewClientWithDefaultChainID(b) txStore := cltest.NewTestTxStore(b, db) - ethKeyStore := cltest.NewKeyStore(b, db).Eth() - _, fromAddress := cltest.MustInsertRandomKey(b, ethKeyStore) + memKeystore := keystest.NewMemoryChainStore() + ethKeyStore := keys.NewChainStore(memKeystore, ethClient.ConfiguredChainID()) + fromAddress := memKeystore.MustCreate(b) toAddress := gethCommon.HexToAddress("0x6C03DDA95a2AEd917EeCc6eddD4b9D16E6380411") @@ -48,7 +54,6 @@ func BenchmarkEthBroadcaster_ProcessUnstartedEthTxs_Success(b *testing.B) { State: txmgrcommon.TxUnstarted, } - ethClient := clienttest.NewClientWithDefaultChainID(b) evmcfg := configtest.NewChainScopedConfig(b, nil) checkerFactory := &txmgr.CheckerFactory{Client: ethClient} lggr := logger.Test(b) diff --git a/core/chains/evm/txmgr/broadcaster_test.go b/core/chains/evm/txmgr/broadcaster_test.go index 5fa28ed5303..ba53a57e8ff 100644 --- a/core/chains/evm/txmgr/broadcaster_test.go +++ b/core/chains/evm/txmgr/broadcaster_test.go @@ -27,6 +27,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/sqlutil" commonutils "github.com/smartcontractkit/chainlink-common/pkg/utils" "github.com/smartcontractkit/chainlink-common/pkg/utils/tests" + "github.com/smartcontractkit/chainlink-integrations/evm/keys/keystest" "github.com/smartcontractkit/chainlink-framework/chains/fees" txmgrcommon "github.com/smartcontractkit/chainlink-framework/chains/txmgr" @@ -42,8 +43,7 @@ import ( "github.com/smartcontractkit/chainlink-integrations/evm/config/toml" "github.com/smartcontractkit/chainlink-integrations/evm/gas" gasmocks "github.com/smartcontractkit/chainlink-integrations/evm/gas/mocks" - "github.com/smartcontractkit/chainlink-integrations/evm/keystore" - ksmocks "github.com/smartcontractkit/chainlink-integrations/evm/keystore/mocks" + "github.com/smartcontractkit/chainlink-integrations/evm/keys" "github.com/smartcontractkit/chainlink-integrations/evm/testutils" evmtypes "github.com/smartcontractkit/chainlink-integrations/evm/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" @@ -63,7 +63,7 @@ func NewTestEthBroadcaster( t testing.TB, txStore txmgr.TestEvmTxStore, ethClient client.Client, - keyStore keystore.Eth, + keyStore keys.ChainStore, databaseListener txmgr.ListenerConfig, config evmconfig.EVM, checkerFactory txmgr.TransmitCheckerFactory, @@ -99,8 +99,10 @@ func TestEthBroadcaster_Lifecycle(t *testing.T) { txStore := cltest.NewTestTxStore(t, db) evmcfg := configtest.NewChainScopedConfig(t, nil) ethClient := clienttest.NewClientWithDefaultChainID(t) - ethKeyStore := cltest.NewKeyStore(t, db).Eth() - cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) + memKS := keystest.NewMemoryChainStore() + memKS.MustCreate(t) + ethKeyStore := keys.NewChainStore(memKS, ethClient.ConfiguredChainID()) + estimator := gasmocks.NewEvmFeeEstimator(t) txBuilder := txmgr.NewEvmTxAttemptBuilder(*ethClient.ConfiguredChainID(), evmcfg.EVM().GasEstimator(), ethKeyStore, estimator) txmClient := txmgr.NewEvmTxmClient(ethClient, nil) @@ -157,8 +159,10 @@ func TestEthBroadcaster_LoadNextSequenceMapFailure_StartupSuccess(t *testing.T) txStore := cltest.NewTestTxStore(t, db) evmcfg := configtest.NewChainScopedConfig(t, nil) ethClient := clienttest.NewClientWithDefaultChainID(t) - ethKeyStore := cltest.NewKeyStore(t, db).Eth() - cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) + memKS := keystest.NewMemoryChainStore() + memKS.MustCreate(t) + ethKeyStore := keys.NewChainStore(memKS, ethClient.ConfiguredChainID()) + estimator := gasmocks.NewEvmFeeEstimator(t) txBuilder := txmgr.NewEvmTxAttemptBuilder(*ethClient.ConfiguredChainID(), evmcfg.EVM().GasEstimator(), ethKeyStore, estimator) ethClient.On("NonceAt", mock.Anything, mock.Anything, mock.Anything).Return(uint64(0), errors.New("Getting on-chain nonce failed")).Once() @@ -188,11 +192,13 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Success(t *testing.T) { db := testutils.NewSqlxDB(t) ctx := tests.Context(t) txStore := cltest.NewTestTxStore(t, db) - ethKeyStore := cltest.NewKeyStore(t, db).Eth() - _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore) - _, otherAddress := cltest.MustInsertRandomKey(t, ethKeyStore) + memKS := keystest.NewMemoryChainStore() + fromAddress := memKS.MustCreate(t) + otherAddress := memKS.MustCreate(t) ethClient := clienttest.NewClientWithDefaultChainID(t) + ethKeyStore := keys.NewChainStore(memKS, ethClient.ConfiguredChainID()) + evmcfg := configtest.NewChainScopedConfig(t, nil) checkerFactory := &txmgr.CheckerFactory{Client: ethClient} @@ -559,10 +565,10 @@ func TestEthBroadcaster_TransmitChecking(t *testing.T) { db := testutils.NewSqlxDB(t) ctx := tests.Context(t) txStore := cltest.NewTestTxStore(t, db) - ethKeyStore := cltest.NewKeyStore(t, db).Eth() - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) - + memKS := keystest.NewMemoryChainStore() + fromAddress := memKS.MustCreate(t) ethClient := clienttest.NewClientWithDefaultChainID(t) + ethKeyStore := keys.NewChainStore(memKS, ethClient.ConfiguredChainID()) evmcfg := configtest.NewChainScopedConfig(t, nil) checkerFactory := &testCheckerFactory{} ethClient.On("NonceAt", mock.Anything, fromAddress, mock.Anything).Return(uint64(0), nil).Once() @@ -645,8 +651,9 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_OptimisticLockingOnEthTx(t *testi ccfg := configtest.NewChainScopedConfig(t, nil) evmcfg := txmgr.NewEvmTxmConfig(ccfg.EVM()) ethClient := clienttest.NewClientWithDefaultChainID(t) - ethKeyStore := cltest.NewKeyStore(t, db).Eth() - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) + memKS := keystest.NewMemoryChainStore() + fromAddress := memKS.MustCreate(t) + ethKeyStore := keys.NewChainStore(memKS, ethClient.ConfiguredChainID()) estimator := gasmocks.NewEvmFeeEstimator(t) txBuilder := txmgr.NewEvmTxAttemptBuilder(*ethClient.ConfiguredChainID(), ccfg.EVM().GasEstimator(), ethKeyStore, estimator) @@ -704,8 +711,10 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Success_WithMultiplier(t *testing db := testutils.NewSqlxDB(t) txStore := cltest.NewTestTxStore(t, db) - ethKeyStore := cltest.NewKeyStore(t, db).Eth() - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) + memKS := keystest.NewMemoryChainStore() + fromAddress := memKS.MustCreate(t) + ethClient := clienttest.NewClientWithDefaultChainID(t) + ethKeyStore := keys.NewChainStore(memKS, ethClient.ConfiguredChainID()) evmcfg := configtest.NewChainScopedConfig(t, func(c *toml.EVMConfig) { // Configured gas price changed @@ -713,7 +722,6 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Success_WithMultiplier(t *testing c.GasEstimator.LimitMultiplier = &lm }) - ethClient := clienttest.NewClientWithDefaultChainID(t) ethClient.On("NonceAt", mock.Anything, fromAddress, mock.Anything).Return(uint64(0), nil).Once() nonceTracker := txmgr.NewNonceTracker(logger.Test(t), txStore, txmgr.NewEvmTxmClient(ethClient, nil)) eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, dbListenerCfg, evmcfg.EVM(), &testCheckerFactory{}, false, nonceTracker) @@ -790,10 +798,11 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_ResumingFromCrash(t *testing.T) { db := testutils.NewSqlxDB(t) txStore := cltest.NewTestTxStore(t, db) evmcfg := configtest.NewChainScopedConfig(t, nil) - ethKeyStore := cltest.NewKeyStore(t, db).Eth() - _, fromAddress := cltest.RandomKey{Nonce: nextNonce.Int64()}.MustInsertWithState(t, ethKeyStore) - + memKS := keystest.NewMemoryChainStore() + fromAddress := memKS.MustCreate(t) ethClient := clienttest.NewClientWithDefaultChainID(t) + ethKeyStore := keys.NewChainStore(memKS, ethClient.ConfiguredChainID()) + ethClient.On("NonceAt", mock.Anything, fromAddress, mock.Anything).Return(uint64(0), nil).Once() nonceTracker := txmgr.NewNonceTracker(logger.Test(t), txStore, txmgr.NewEvmTxmClient(ethClient, nil)) eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, dbListenerCfg, evmcfg.EVM(), &testCheckerFactory{}, false, nonceTracker) @@ -829,10 +838,11 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_ResumingFromCrash(t *testing.T) { db := testutils.NewSqlxDB(t) txStore := cltest.NewTestTxStore(t, db) evmcfg := configtest.NewChainScopedConfig(t, nil) - ethKeyStore := cltest.NewKeyStore(t, db).Eth() - _, fromAddress := cltest.RandomKey{Nonce: nextNonce.Int64()}.MustInsertWithState(t, ethKeyStore) - + memKS := keystest.NewMemoryChainStore() + fromAddress := memKS.MustCreate(t) ethClient := clienttest.NewClientWithDefaultChainID(t) + ethKeyStore := keys.NewChainStore(memKS, ethClient.ConfiguredChainID()) + ethClient.On("NonceAt", mock.Anything, fromAddress, mock.Anything).Return(uint64(0), nil).Once() nonceTracker := txmgr.NewNonceTracker(logger.Test(t), txStore, txmgr.NewEvmTxmClient(ethClient, nil)) eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, dbListenerCfg, evmcfg.EVM(), &testCheckerFactory{}, false, nonceTracker) @@ -866,10 +876,11 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_ResumingFromCrash(t *testing.T) { db := testutils.NewSqlxDB(t) txStore := cltest.NewTestTxStore(t, db) evmcfg := configtest.NewChainScopedConfig(t, nil) - ethKeyStore := cltest.NewKeyStore(t, db).Eth() - _, fromAddress := cltest.RandomKey{Nonce: nextNonce.Int64()}.MustInsertWithState(t, ethKeyStore) - + memKS := keystest.NewMemoryChainStore() + fromAddress := memKS.MustCreate(t) ethClient := clienttest.NewClientWithDefaultChainID(t) + ethKeyStore := keys.NewChainStore(memKS, ethClient.ConfiguredChainID()) + ethClient.On("NonceAt", mock.Anything, fromAddress, mock.Anything).Return(uint64(0), nil).Once() nonceTracker := txmgr.NewNonceTracker(logger.Test(t), txStore, txmgr.NewEvmTxmClient(ethClient, nil)) eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, dbListenerCfg, evmcfg.EVM(), &testCheckerFactory{}, false, nonceTracker) @@ -902,10 +913,10 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_ResumingFromCrash(t *testing.T) { db := testutils.NewSqlxDB(t) txStore := cltest.NewTestTxStore(t, db) evmcfg := configtest.NewChainScopedConfig(t, nil) - ethKeyStore := cltest.NewKeyStore(t, db).Eth() - _, fromAddress := cltest.RandomKey{Nonce: nextNonce.Int64()}.MustInsertWithState(t, ethKeyStore) - + memKS := keystest.NewMemoryChainStore() + fromAddress := memKS.MustCreate(t) ethClient := clienttest.NewClientWithDefaultChainID(t) + ethKeyStore := keys.NewChainStore(memKS, ethClient.ConfiguredChainID()) ethClient.On("NonceAt", mock.Anything, fromAddress, mock.Anything).Return(uint64(0), nil).Once() nonceTracker := txmgr.NewNonceTracker(logger.Test(t), txStore, txmgr.NewEvmTxmClient(ethClient, nil)) eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, dbListenerCfg, evmcfg.EVM(), &testCheckerFactory{}, false, nonceTracker) @@ -940,10 +951,11 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_ResumingFromCrash(t *testing.T) { db := testutils.NewSqlxDB(t) txStore := cltest.NewTestTxStore(t, db) evmcfg := configtest.NewChainScopedConfig(t, nil) - ethKeyStore := cltest.NewKeyStore(t, db).Eth() - _, fromAddress := cltest.RandomKey{Nonce: nextNonce.Int64()}.MustInsertWithState(t, ethKeyStore) - + memKS := keystest.NewMemoryChainStore() + fromAddress := memKS.MustCreate(t) ethClient := clienttest.NewClientWithDefaultChainID(t) + ethKeyStore := keys.NewChainStore(memKS, ethClient.ConfiguredChainID()) + ethClient.On("NonceAt", mock.Anything, fromAddress, mock.Anything).Return(uint64(0), nil).Once() nonceTracker := txmgr.NewNonceTracker(logger.Test(t), txStore, txmgr.NewEvmTxmClient(ethClient, nil)) eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, dbListenerCfg, evmcfg.EVM(), &testCheckerFactory{}, false, nonceTracker) @@ -976,15 +988,16 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_ResumingFromCrash(t *testing.T) { db := testutils.NewSqlxDB(t) txStore := cltest.NewTestTxStore(t, db) - ethKeyStore := cltest.NewKeyStore(t, db).Eth() - _, fromAddress := cltest.RandomKey{Nonce: nextNonce.Int64()}.MustInsertWithState(t, ethKeyStore) + memKS := keystest.NewMemoryChainStore() + fromAddress := memKS.MustCreate(t) + ethClient := clienttest.NewClientWithDefaultChainID(t) + ethKeyStore := keys.NewChainStore(memKS, ethClient.ConfiguredChainID()) evmcfg := configtest.NewChainScopedConfig(t, func(c *toml.EVMConfig) { // Configured gas price changed c.GasEstimator.PriceDefault = assets.NewWeiI(500000000000) }) - ethClient := clienttest.NewClientWithDefaultChainID(t) ethClient.On("NonceAt", mock.Anything, fromAddress, mock.Anything).Return(uint64(0), nil).Once() nonceTracker := txmgr.NewNonceTracker(logger.Test(t), txStore, txmgr.NewEvmTxmClient(ethClient, nil)) eb := NewTestEthBroadcaster(t, txStore, ethClient, ethKeyStore, dbListenerCfg, evmcfg.EVM(), &testCheckerFactory{}, false, nonceTracker) @@ -1043,10 +1056,11 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_Errors(t *testing.T) { db := testutils.NewSqlxDB(t) txStore := cltest.NewTestTxStore(t, db) - ethKeyStore := cltest.NewKeyStore(t, db).Eth() - _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore) - + memKS := keystest.NewMemoryChainStore() + fromAddress := memKS.MustCreate(t) ethClient := clienttest.NewClientWithDefaultChainID(t) + ethKeyStore := keys.NewChainStore(memKS, ethClient.ConfiguredChainID()) + ethClient.On("NonceAt", mock.Anything, fromAddress, mock.Anything).Return(uint64(0), nil).Once() lggr := logger.Test(t) txmClient := txmgr.NewEvmTxmClient(ethClient, nil) @@ -1667,15 +1681,16 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_GasEstimationError(t *testing.T) db := testutils.NewSqlxDB(t) txStore := cltest.NewTestTxStore(t, db) - ethKeyStore := cltest.NewKeyStore(t, db).Eth() - _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore) + memKS := keystest.NewMemoryChainStore() + fromAddress := memKS.MustCreate(t) + ethClient := clienttest.NewClientWithDefaultChainID(t) + ethKeyStore := keys.NewChainStore(memKS, ethClient.ConfiguredChainID()) const limitMultiplier = float32(1.25) config := configtest.NewChainScopedConfig(t, func(c *toml.EVMConfig) { c.GasEstimator.EstimateLimit = ptr(true) // Enabled gas limit estimation c.GasEstimator.LimitMultiplier = ptr(decimal.NewFromFloat32(limitMultiplier)) // Set LimitMultiplier for the buffer }) - ethClient := clienttest.NewClientWithDefaultChainID(t) ethClient.On("NonceAt", mock.Anything, fromAddress, mock.Anything).Return(uint64(0), nil).Once() lggr := logger.Test(t) txmClient := txmgr.NewEvmTxmClient(ethClient, nil) @@ -1735,15 +1750,12 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_KeystoreErrors(t *testing.T) { db := testutils.NewSqlxDB(t) txStore := cltest.NewTestTxStore(t, db) - realKeystore := cltest.NewKeyStore(t, db) - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, realKeystore.Eth()) - - evmcfg := configtest.NewChainScopedConfig(t, nil) + memKS := keystest.NewMemoryChainStore() + fromAddress := memKS.MustCreate(t) ethClient := clienttest.NewClientWithDefaultChainID(t) + kst := keys.NewChainStore(memKS, ethClient.ConfiguredChainID()) + evmcfg := configtest.NewChainScopedConfig(t, nil) - kst := ksmocks.NewEth(t) - addresses := []gethCommon.Address{fromAddress} - kst.On("EnabledAddressesForChain", mock.Anything, testutils.FixtureChainID).Return(addresses, nil).Once() ethClient.On("NonceAt", mock.Anything, fromAddress, mock.Anything).Return(uint64(0), nil).Once() lggr := logger.Test(t) nonceTracker := txmgr.NewNonceTracker(lggr, txStore, txmgr.NewEvmTxmClient(ethClient, nil)) @@ -1752,35 +1764,27 @@ func TestEthBroadcaster_ProcessUnstartedEthTxs_KeystoreErrors(t *testing.T) { _, err := nonceTracker.GetNextSequence(ctx, fromAddress) require.NoError(t, err) - t.Run("tx signing fails", func(t *testing.T) { - etx := mustCreateUnstartedTx(t, txStore, fromAddress, toAddress, encodedPayload, gasLimit, value, testutils.FixtureChainID) - tx := *gethTypes.NewTx(&gethTypes.LegacyTx{}) - kst.On("SignTx", mock.Anything, - fromAddress, - mock.AnythingOfType("*types.Transaction"), - mock.MatchedBy(func(chainID *big.Int) bool { - return chainID.Cmp(evmcfg.EVM().ChainID()) == 0 - })).Return(&tx, errors.New("could not sign transaction")) + // tx signing fails + etx := mustCreateUnstartedTx(t, txStore, fromAddress, toAddress, encodedPayload, gasLimit, value, testutils.FixtureChainID) - // Do the thing - retryable, err := eb.ProcessUnstartedTxs(ctx, fromAddress) - require.Error(t, err) - require.Contains(t, err.Error(), "could not sign transaction") - assert.True(t, retryable) + // Do the thing + retryable, err := eb.ProcessUnstartedTxs(ctx, fromAddress) + require.Error(t, err) + require.Contains(t, err.Error(), "could not sign transaction") + assert.True(t, retryable) - // Check that the transaction is left in unstarted state - etx, err = txStore.FindTxWithAttempts(ctx, etx.ID) - require.NoError(t, err) + // Check that the transaction is left in unstarted state + etx, err = txStore.FindTxWithAttempts(ctx, etx.ID) + require.NoError(t, err) - assert.Equal(t, txmgrcommon.TxUnstarted, etx.State) - assert.Len(t, etx.TxAttempts, 0) + assert.Equal(t, txmgrcommon.TxUnstarted, etx.State) + assert.Len(t, etx.TxAttempts, 0) - // Check that the key did not have its nonce incremented - var nonce evmtypes.Nonce - nonce, err = nonceTracker.GetNextSequence(ctx, fromAddress) - require.NoError(t, err) - require.Equal(t, int64(localNonce), int64(nonce)) - }) + // Check that the key did not have its nonce incremented + var nonce evmtypes.Nonce + nonce, err = nonceTracker.GetNextSequence(ctx, fromAddress) + require.NoError(t, err) + require.Equal(t, int64(localNonce), int64(nonce)) } func TestEthBroadcaster_Trigger(t *testing.T) { @@ -1791,7 +1795,7 @@ func TestEthBroadcaster_Trigger(t *testing.T) { txStore := cltest.NewTestTxStore(t, db) evmcfg := configtest.NewChainScopedConfig(t, nil) - ethKeyStore := cltest.NewKeyStore(t, db).Eth() + ethKeyStore := &keystest.FakeChainStore{} ethClient := clienttest.NewClientWithDefaultChainID(t) lggr := logger.Test(t) nonceTracker := txmgr.NewNonceTracker(lggr, txStore, txmgr.NewEvmTxmClient(ethClient, nil)) @@ -1813,10 +1817,11 @@ func TestEthBroadcaster_SyncNonce(t *testing.T) { evmTxmCfg := txmgr.NewEvmTxmConfig(evmcfg.EVM()) txStore := cltest.NewTestTxStore(t, db) - kst := cltest.NewKeyStore(t, db).Eth() - _, fromAddress := cltest.RandomKey{Disabled: false}.MustInsertWithState(t, kst) - + memKS := keystest.NewMemoryChainStore() + fromAddress := memKS.MustCreate(t) ethClient := clienttest.NewClientWithDefaultChainID(t) + kst := keys.NewChainStore(memKS, ethClient.ConfiguredChainID()) + estimator := gas.NewEvmFeeEstimator(lggr, func(lggr logger.Logger) gas.EvmEstimator { return gas.NewFixedPriceEstimator(evmcfg.EVM().GasEstimator(), nil, evmcfg.EVM().GasEstimator().BlockHistory(), lggr, nil) }, evmcfg.EVM().GasEstimator().EIP1559DynamicFees(), evmcfg.EVM().GasEstimator(), ethClient) @@ -1827,9 +1832,6 @@ func TestEthBroadcaster_SyncNonce(t *testing.T) { t.Run("does nothing if nonce sync is disabled", func(t *testing.T) { txBuilder := txmgr.NewEvmTxAttemptBuilder(*ethClient.ConfiguredChainID(), ge, kst, estimator) - kst := ksmocks.NewEth(t) - addresses := []gethCommon.Address{fromAddress} - kst.On("EnabledAddressesForChain", mock.Anything, testutils.FixtureChainID).Return(addresses, nil).Once() ethClient.On("NonceAt", mock.Anything, fromAddress, mock.Anything).Return(uint64(0), nil).Once() txmClient := txmgr.NewEvmTxmClient(ethClient, nil) eb := txmgr.NewEvmBroadcaster(txStore, txmClient, evmTxmCfg, txmgr.NewEvmTxmFeeConfig(ge), evmcfg.EVM().Transactions(), dbListenerCfg, kst, txBuilder, lggr, checkerFactory, false, "") @@ -1847,8 +1849,9 @@ func TestEthBroadcaster_NonceTracker_InProgressTx(t *testing.T) { db := testutils.NewSqlxDB(t) txStore := cltest.NewTestTxStore(t, db) - ethKeyStore := cltest.NewKeyStore(t, db).Eth() - _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore) + memKS := keystest.NewMemoryChainStore() + fromAddress := memKS.MustCreate(t) + ethKeyStore := keys.NewChainStore(memKS, big.NewInt(0)) ethClient := clienttest.NewClientWithDefaultChainID(t) evmcfg := configtest.NewChainScopedConfig(t, nil) @@ -1885,7 +1888,8 @@ func TestEthBroadcaster_HederaBroadcastValidation(t *testing.T) { db := testutils.NewSqlxDB(t) txStore := cltest.NewTestTxStore(t, db) - ethKeyStore := cltest.NewKeyStore(t, db).Eth() + memKS := keystest.NewMemoryChainStore() + ethKeyStore := keys.NewChainStore(memKS, big.NewInt(0)) evmcfg := configtest.NewChainScopedConfig(t, nil) ethClient := clienttest.NewClientWithDefaultChainID(t) lggr, observed := logger.TestObserved(t, zapcore.DebugLevel) @@ -1898,7 +1902,7 @@ func TestEthBroadcaster_HederaBroadcastValidation(t *testing.T) { ctx := tests.Context(t) t.Run("transaction successfully broadcasted and increments on-chain nonce", func(t *testing.T) { - _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore) + fromAddress := memKS.MustCreate(t) localNonce := uint64(0) ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *gethTypes.Transaction) bool { return tx.Nonce() == localNonce @@ -1918,7 +1922,7 @@ func TestEthBroadcaster_HederaBroadcastValidation(t *testing.T) { }) t.Run("transaction successfully broadcasted, failed to increment on-chain nonce, succeeded on bumped retry attempt", func(t *testing.T) { - _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore) + fromAddress := memKS.MustCreate(t) localNonce := uint64(0) ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *gethTypes.Transaction) bool { return tx.Nonce() == localNonce @@ -1940,7 +1944,7 @@ func TestEthBroadcaster_HederaBroadcastValidation(t *testing.T) { }) t.Run("transaction successfully broadcasted, failed to increment on-chain nonce on every retry", func(t *testing.T) { - _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore) + fromAddress := memKS.MustCreate(t) localNonce := uint64(0) ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *gethTypes.Transaction) bool { return tx.Nonce() == localNonce diff --git a/core/chains/evm/txmgr/builder.go b/core/chains/evm/txmgr/builder.go index 86751dcfadb..4ac1e1e79f7 100644 --- a/core/chains/evm/txmgr/builder.go +++ b/core/chains/evm/txmgr/builder.go @@ -11,12 +11,12 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/sqlutil" "github.com/smartcontractkit/chainlink-framework/chains/txmgr" txmgrtypes "github.com/smartcontractkit/chainlink-framework/chains/txmgr/types" + "github.com/smartcontractkit/chainlink-integrations/evm/keys" "github.com/smartcontractkit/chainlink-integrations/evm/client" "github.com/smartcontractkit/chainlink-integrations/evm/config" "github.com/smartcontractkit/chainlink-integrations/evm/config/chaintype" "github.com/smartcontractkit/chainlink-integrations/evm/gas" - "github.com/smartcontractkit/chainlink-integrations/evm/keystore" "github.com/smartcontractkit/chainlink-integrations/evm/logpoller" "github.com/smartcontractkit/chainlink-integrations/evm/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/forwarders" @@ -41,7 +41,7 @@ func NewTxm( client client.Client, lggr logger.Logger, logPoller logpoller.LogPoller, - keyStore keystore.Eth, + keyStore keys.ChainStore, estimator gas.EvmFeeEstimator, headTracker latestAndFinalizedBlockHeadTracker, txmv2wrapper TxManager, @@ -66,7 +66,7 @@ func NewTxm( evmBroadcaster := NewEvmBroadcaster(txStore, txmClient, txmCfg, feeCfg, txConfig, listenerConfig, keyStore, txAttemptBuilder, lggr, checker, chainConfig.NonceAutoSync(), chainConfig.ChainType()) evmTracker := NewEvmTracker(txStore, keyStore, chainID, lggr) stuckTxDetector := NewStuckTxDetector(lggr, client.ConfiguredChainID(), chainConfig.ChainType(), fCfg.PriceMax(), txConfig.AutoPurge(), estimator, txStore, client) - evmConfirmer := NewEvmConfirmer(txStore, txmClient, feeCfg, txConfig, dbConfig, keyStore, txAttemptBuilder, lggr, stuckTxDetector, headTracker) + evmConfirmer := NewEvmConfirmer(txStore, txmClient, feeCfg, txConfig, dbConfig, keyStore, txAttemptBuilder, lggr, stuckTxDetector) evmFinalizer := NewEvmFinalizer(lggr, client.ConfiguredChainID(), chainConfig.RPCDefaultBatchSize(), txConfig.ForwardersEnabled(), txStore, txmClient, headTracker) var evmResender *Resender if txConfig.ResendAfterThreshold() > 0 { @@ -106,7 +106,7 @@ func NewTxmV2( client client.Client, lggr logger.Logger, logPoller logpoller.LogPoller, - keyStore keystore.Eth, + keyStore keys.ChainStore, estimator gas.EvmFeeEstimator, ) (TxManager, error) { var fwdMgr *forwarders.FwdMgr @@ -128,7 +128,7 @@ func NewTxmV2( stuckTxDetector = txm.NewStuckTxDetector(lggr, chainConfig.ChainType(), stuckTxDetectorConfig) } - attemptBuilder := txm.NewAttemptBuilder(chainID, fCfg.PriceMaxKey, estimator, keyStore) + attemptBuilder := txm.NewAttemptBuilder(fCfg.PriceMaxKey, estimator, keyStore) inMemoryStoreManager := storage.NewInMemoryStoreManager(lggr, chainID) config := txm.Config{ EIP1559: fCfg.EIP1559DynamicFees(), @@ -177,7 +177,6 @@ func NewEvmConfirmer( txAttemptBuilder TxAttemptBuilder, lggr logger.Logger, stuckTxDetector StuckTxDetector, - headTracker latestAndFinalizedBlockHeadTracker, ) *Confirmer { return txmgr.NewConfirmer(txStore, client, feeConfig, txConfig, dbConfig, keystore, txAttemptBuilder, lggr, func(r *types.Receipt) bool { return r == nil }, stuckTxDetector) } diff --git a/core/chains/evm/txmgr/confirmer_benchmark_test.go b/core/chains/evm/txmgr/confirmer_benchmark_test.go index de7246fb2b2..0478c06e45b 100644 --- a/core/chains/evm/txmgr/confirmer_benchmark_test.go +++ b/core/chains/evm/txmgr/confirmer_benchmark_test.go @@ -9,18 +9,21 @@ import ( "github.com/smartcontractkit/chainlink-integrations/evm/client/clienttest" "github.com/smartcontractkit/chainlink-integrations/evm/config/configtest" "github.com/smartcontractkit/chainlink-integrations/evm/config/toml" + "github.com/smartcontractkit/chainlink-integrations/evm/keys" + "github.com/smartcontractkit/chainlink-integrations/evm/keys/keystest" "github.com/smartcontractkit/chainlink-integrations/evm/testutils" evmtypes "github.com/smartcontractkit/chainlink-integrations/evm/types" - "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" + + "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" ) -func BenchmarkEthConfirmer(t *testing.B) { - db := testutils.NewSqlxDB(t) - txStore := cltest.NewTestTxStore(t, db) - ethClient := clienttest.NewClientWithDefaultChainID(t) - evmcfg := configtest.NewChainScopedConfig(t, func(c *toml.EVMConfig) { +func BenchmarkEthConfirmer(b *testing.B) { + db := testutils.NewSqlxDB(b) + txStore := cltest.NewTestTxStore(b, db) + ethClient := clienttest.NewClientWithDefaultChainID(b) + evmcfg := configtest.NewChainScopedConfig(b, func(c *toml.EVMConfig) { c.GasEstimator.PriceMax = assets.GWei(500) }) @@ -31,32 +34,33 @@ func BenchmarkEthConfirmer(t *testing.B) { } head.IsFinalized.Store(true) - ethKeyStore := cltest.NewKeyStore(t, db).Eth() - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) - ec := newEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, nil) + memKeystore := keystest.NewMemoryChainStore() + ethKeyStore := keys.NewChainStore(memKeystore, ethClient.ConfiguredChainID()) + fromAddress := memKeystore.MustCreate(b) + ec := newEthConfirmer(b, txStore, ethClient, evmcfg, ethKeyStore, nil) ethClient.On("NonceAt", mock.Anything, fromAddress, mock.Anything).Return(uint64(1), nil).Maybe() - ctx := tests.Context(t) + ctx := tests.Context(b) - t.ResetTimer() - for n := 0; n < t.N; n++ { - etx1 := mustInsertConfirmedEthTxWithReceipt(t, txStore, fromAddress, 0, blockNum) - etx2 := mustInsertUnconfirmedTxWithBroadcastAttempts(t, txStore, 4, fromAddress, 1, blockNum, assets.NewWeiI(1)) + b.ResetTimer() + for n := 0; n < b.N; n++ { + etx1 := mustInsertConfirmedEthTxWithReceipt(b, txStore, fromAddress, 0, blockNum) + etx2 := mustInsertUnconfirmedTxWithBroadcastAttempts(b, txStore, 4, fromAddress, 1, blockNum, assets.NewWeiI(1)) var err error - t.StartTimer() + b.StartTimer() err = ec.CheckForConfirmation(ctx, &head) - t.StopTimer() - require.NoError(t, err) + b.StopTimer() + require.NoError(b, err) etx1, err = txStore.FindTxWithAttempts(ctx, etx1.ID) - require.NoError(t, err) - require.Equal(t, txmgrcommon.TxConfirmed, etx1.State) + require.NoError(b, err) + require.Equal(b, txmgrcommon.TxConfirmed, etx1.State) etx2, err = txStore.FindTxWithAttempts(ctx, etx2.ID) - require.NoError(t, err) - require.Equal(t, txmgrcommon.TxUnconfirmed, etx2.State) + require.NoError(b, err) + require.Equal(b, txmgrcommon.TxUnconfirmed, etx2.State) - deleteTx(ctx, t, &etx1, db) - deleteTx(ctx, t, &etx2, db) + deleteTx(ctx, b, &etx1, db) + deleteTx(ctx, b, &etx2, db) } } diff --git a/core/chains/evm/txmgr/confirmer_test.go b/core/chains/evm/txmgr/confirmer_test.go index 44cd7dafa46..c686e502c4f 100644 --- a/core/chains/evm/txmgr/confirmer_test.go +++ b/core/chains/evm/txmgr/confirmer_test.go @@ -20,11 +20,12 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" "github.com/smartcontractkit/chainlink-common/pkg/utils/tests" - "github.com/smartcontractkit/chainlink-framework/chains/fees" txmgrcommon "github.com/smartcontractkit/chainlink-framework/chains/txmgr" txmgrtypes "github.com/smartcontractkit/chainlink-framework/chains/txmgr/types" "github.com/smartcontractkit/chainlink-framework/multinode" + "github.com/smartcontractkit/chainlink-integrations/evm/keys" + "github.com/smartcontractkit/chainlink-integrations/evm/keys/keystest" "github.com/smartcontractkit/chainlink-integrations/evm/assets" "github.com/smartcontractkit/chainlink-integrations/evm/client" @@ -34,9 +35,6 @@ import ( "github.com/smartcontractkit/chainlink-integrations/evm/config/toml" "github.com/smartcontractkit/chainlink-integrations/evm/gas" gasmocks "github.com/smartcontractkit/chainlink-integrations/evm/gas/mocks" - "github.com/smartcontractkit/chainlink-integrations/evm/heads/headstest" - "github.com/smartcontractkit/chainlink-integrations/evm/keystore" - ksmocks "github.com/smartcontractkit/chainlink-integrations/evm/keystore/mocks" "github.com/smartcontractkit/chainlink-integrations/evm/testutils" evmtypes "github.com/smartcontractkit/chainlink-integrations/evm/types" "github.com/smartcontractkit/chainlink-integrations/evm/utils" @@ -105,12 +103,13 @@ func TestEthConfirmer_Lifecycle(t *testing.T) { config := configtest.NewChainScopedConfig(t, nil) txStore := newTxStore(t, db) + memKS := keystest.NewMemoryChainStore() ethClient := clienttest.NewClientWithDefaultChainID(t) - ethKeyStore := cltest.NewKeyStore(t, db).Eth() + ethKeyStore := keys.NewChainStore(memKS, ethClient.ConfiguredChainID()) // Add some fromAddresses - cltest.MustInsertRandomKey(t, ethKeyStore) - cltest.MustInsertRandomKey(t, ethKeyStore) + memKS.MustCreate(t) + memKS.MustCreate(t) estimator := gasmocks.NewEvmEstimator(t) newEst := func(logger.Logger) gas.EvmEstimator { return estimator } lggr := logger.Test(t) @@ -118,8 +117,7 @@ func TestEthConfirmer_Lifecycle(t *testing.T) { feeEstimator := gas.NewEvmFeeEstimator(lggr, newEst, ge.EIP1559DynamicFees(), ge, ethClient) txBuilder := txmgr.NewEvmTxAttemptBuilder(*ethClient.ConfiguredChainID(), ge, ethKeyStore, feeEstimator) stuckTxDetector := txmgr.NewStuckTxDetector(lggr, testutils.FixtureChainID, "", assets.NewWei(assets.NewEth(100).ToInt()), config.EVM().Transactions().AutoPurge(), feeEstimator, txStore, ethClient) - ht := headstest.NewSimulatedHeadTracker(ethClient, true, 0) - ec := txmgr.NewEvmConfirmer(txStore, txmgr.NewEvmTxmClient(ethClient, nil), txmgr.NewEvmTxmFeeConfig(ge), config.EVM().Transactions(), confirmerConfig{}, ethKeyStore, txBuilder, lggr, stuckTxDetector, ht) + ec := txmgr.NewEvmConfirmer(txStore, txmgr.NewEvmTxmClient(ethClient, nil), txmgr.NewEvmTxmFeeConfig(ge), config.EVM().Transactions(), confirmerConfig{}, ethKeyStore, txBuilder, lggr, stuckTxDetector) ctx := tests.Context(t) // Can't close unstarted instance @@ -197,8 +195,8 @@ func TestEthConfirmer_CheckForConfirmation(t *testing.T) { head.IsFinalized.Store(true) t.Run("does nothing if no re-org'd or included transactions found", func(t *testing.T) { - ethKeyStore := cltest.NewKeyStore(t, db).Eth() - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) + fromAddress := cltest.MustGenerateRandomKey(t).Address + ethKeyStore := &keystest.FakeChainStore{Addresses: keystest.Addresses{fromAddress}} etx1 := mustInsertConfirmedEthTxWithReceipt(t, txStore, fromAddress, 0, blockNum) etx2 := mustInsertUnconfirmedTxWithBroadcastAttempts(t, txStore, 4, fromAddress, 1, blockNum, assets.NewWeiI(1)) ec := newEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, nil) @@ -217,8 +215,9 @@ func TestEthConfirmer_CheckForConfirmation(t *testing.T) { }) t.Run("marks re-org'd confirmed transaction as unconfirmed, marks latest attempt as in-progress, deletes receipt", func(t *testing.T) { - ethKeyStore := cltest.NewKeyStore(t, db).Eth() - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) + memKS := keystest.NewMemoryChainStore() + fromAddress := memKS.MustCreate(t) + ethKeyStore := keys.NewChainStore(memKS, ethClient.ConfiguredChainID()) // Insert confirmed transaction that stays confirmed etx := mustInsertConfirmedEthTxWithReceipt(t, txStore, fromAddress, 0, blockNum) ec := newEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, nil) @@ -236,8 +235,9 @@ func TestEthConfirmer_CheckForConfirmation(t *testing.T) { }) t.Run("marks re-org'd terminally stuck transaction as unconfirmed, marks latest attempt as in-progress, deletes receipt, removed error", func(t *testing.T) { - ethKeyStore := cltest.NewKeyStore(t, db).Eth() - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) + memKS := keystest.NewMemoryChainStore() + fromAddress := memKS.MustCreate(t) + ethKeyStore := keys.NewChainStore(memKS, ethClient.ConfiguredChainID()) // Insert terminally stuck transaction that stays fatal error etx := mustInsertTerminallyStuckTxWithAttempt(t, txStore, fromAddress, 0, blockNum) mustInsertEthReceipt(t, txStore, blockNum, utils.NewHash(), etx.TxAttempts[0].Hash) @@ -257,8 +257,9 @@ func TestEthConfirmer_CheckForConfirmation(t *testing.T) { }) t.Run("handles multiple re-org transactions at a time", func(t *testing.T) { - ethKeyStore := cltest.NewKeyStore(t, db).Eth() - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) + memKS := keystest.NewMemoryChainStore() + fromAddress := memKS.MustCreate(t) + ethKeyStore := keys.NewChainStore(memKS, ethClient.ConfiguredChainID()) // Insert confirmed transaction that stays confirmed etx1 := mustInsertConfirmedEthTxWithReceipt(t, txStore, fromAddress, 0, blockNum) // Insert terminally stuck transaction that stays fatal error @@ -316,8 +317,9 @@ func TestEthConfirmer_CheckForConfirmation(t *testing.T) { }) t.Run("marks valid transaction as confirmed if nonce less than mined tx count", func(t *testing.T) { - ethKeyStore := cltest.NewKeyStore(t, db).Eth() - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) + memKS := keystest.NewMemoryChainStore() + fromAddress := memKS.MustCreate(t) + ethKeyStore := keys.NewChainStore(memKS, ethClient.ConfiguredChainID()) etx := mustInsertUnconfirmedTxWithBroadcastAttempts(t, txStore, 0, fromAddress, 1, blockNum, assets.NewWeiI(1)) ec := newEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, nil) @@ -331,8 +333,9 @@ func TestEthConfirmer_CheckForConfirmation(t *testing.T) { }) t.Run("marks purge transaction as terminally stuck if nonce less than mined tx count", func(t *testing.T) { - ethKeyStore := cltest.NewKeyStore(t, db).Eth() - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) + memKS := keystest.NewMemoryChainStore() + fromAddress := memKS.MustCreate(t) + ethKeyStore := keys.NewChainStore(memKS, ethClient.ConfiguredChainID()) etx := mustInsertUnconfirmedEthTxWithBroadcastPurgeAttempt(t, txStore, 0, fromAddress) ec := newEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, nil) @@ -347,8 +350,9 @@ func TestEthConfirmer_CheckForConfirmation(t *testing.T) { }) t.Run("handles multiple confirmed transactions at a time", func(t *testing.T) { - ethKeyStore := cltest.NewKeyStore(t, db).Eth() - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) + memKS := keystest.NewMemoryChainStore() + fromAddress := memKS.MustCreate(t) + ethKeyStore := keys.NewChainStore(memKS, ethClient.ConfiguredChainID()) // Insert valid confirmed transaction that is untouched etx1 := mustInsertConfirmedEthTxWithReceipt(t, txStore, fromAddress, 0, blockNum) // Insert terminally stuck transaction that is untouched @@ -417,9 +421,9 @@ func TestEthConfirmer_FindTxsRequiringRebroadcast(t *testing.T) { evmcfg := configtest.NewChainScopedConfig(t, nil) - ethKeyStore := cltest.NewKeyStore(t, db).Eth() - - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) + memKS := keystest.NewMemoryChainStore() + fromAddress := memKS.MustCreate(t) + ethKeyStore := keys.NewChainStore(memKS, ethClient.ConfiguredChainID()) evmFromAddress := fromAddress currentHead := int64(30) gasBumpThreshold := int64(10) @@ -431,8 +435,7 @@ func TestEthConfirmer_FindTxsRequiringRebroadcast(t *testing.T) { mustInsertConfirmedEthTx(t, txStore, nonce, fromAddress) nonce++ - _, otherAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) - evmOtherAddress := otherAddress + evmOtherAddress := memKS.MustCreate(t) lggr := logger.Test(t) @@ -540,7 +543,7 @@ func TestEthConfirmer_FindTxsRequiringRebroadcast(t *testing.T) { require.NoError(t, db.Get(&dbAttempt, `UPDATE evm.tx_attempts SET broadcast_before_block_num=$1 WHERE id=$2 RETURNING *`, oldEnough, attempt3_1.ID)) // NOTE: It should ignore qualifying eth_txes from a different address - etxOther := cltest.MustInsertUnconfirmedEthTxWithBroadcastLegacyAttempt(t, txStore, 0, otherAddress) + etxOther := cltest.MustInsertUnconfirmedEthTxWithBroadcastLegacyAttempt(t, txStore, 0, evmOtherAddress) attemptOther1 := etxOther.TxAttempts[0] dbAttempt = txmgr.DbEthTxAttempt{} dbAttempt.FromTxAttempt(&attemptOther1) @@ -599,7 +602,7 @@ func TestEthConfirmer_FindTxsRequiringRebroadcast(t *testing.T) { t.Run("ignores pending transactions for another key", func(t *testing.T) { // Re-use etx3 nonce for another key, it should not affect the results for this key - etxOther := cltest.MustInsertUnconfirmedEthTxWithBroadcastLegacyAttempt(t, txStore, (*etx3.Sequence).Int64(), otherAddress) + etxOther := cltest.MustInsertUnconfirmedEthTxWithBroadcastLegacyAttempt(t, txStore, (*etx3.Sequence).Int64(), evmOtherAddress) aOther := etxOther.TxAttempts[0] dbAttempt = txmgr.DbEthTxAttempt{} dbAttempt.FromTxAttempt(&aOther) @@ -716,20 +719,17 @@ func TestEthConfirmer_RebroadcastWhereNecessary_WithConnectivityCheck(t *testing txStore := cltest.NewTestTxStore(t, db) ethKeyStore := cltest.NewKeyStore(t, db).Eth() _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) - kst := ksmocks.NewEth(t) estimator := gasmocks.NewEvmEstimator(t) newEst := func(logger.Logger) gas.EvmEstimator { return estimator } estimator.On("BumpLegacyGas", mock.Anything, mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(nil, uint64(0), pkgerrors.Wrapf(fees.ErrConnectivity, "transaction...")) ge := ccfg.EVM().GasEstimator() feeEstimator := gas.NewEvmFeeEstimator(lggr, newEst, ge.EIP1559DynamicFees(), ge, ethClient) - txBuilder := txmgr.NewEvmTxAttemptBuilder(*ethClient.ConfiguredChainID(), ge, kst, feeEstimator) - addresses := []gethCommon.Address{fromAddress} - kst.On("EnabledAddressesForChain", mock.Anything, &cltest.FixtureChainID).Return(addresses, nil).Maybe() + kst := keystest.Addresses{fromAddress} + txBuilder := txmgr.NewEvmTxAttemptBuilder(*ethClient.ConfiguredChainID(), ge, keystest.TxSigner(nil), feeEstimator) stuckTxDetector := txmgr.NewStuckTxDetector(lggr, testutils.FixtureChainID, "", assets.NewWei(assets.NewEth(100).ToInt()), ccfg.EVM().Transactions().AutoPurge(), feeEstimator, txStore, ethClient) - ht := headstest.NewSimulatedHeadTracker(ethClient, true, 0) // Create confirmer with necessary state - ec := txmgr.NewEvmConfirmer(txStore, txmgr.NewEvmTxmClient(ethClient, nil), txmgr.NewEvmTxmFeeConfig(ccfg.EVM().GasEstimator()), ccfg.EVM().Transactions(), confirmerConfig{}, kst, txBuilder, lggr, stuckTxDetector, ht) + ec := txmgr.NewEvmConfirmer(txStore, txmgr.NewEvmTxmClient(ethClient, nil), txmgr.NewEvmTxmFeeConfig(ccfg.EVM().GasEstimator()), ccfg.EVM().Transactions(), confirmerConfig{}, kst, txBuilder, lggr, stuckTxDetector) servicetest.Run(t, ec) currentHead := int64(30) oldEnough := int64(15) @@ -764,7 +764,6 @@ func TestEthConfirmer_RebroadcastWhereNecessary_WithConnectivityCheck(t *testing txStore := cltest.NewTestTxStore(t, db) ethKeyStore := cltest.NewKeyStore(t, db).Eth() _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) - kst := ksmocks.NewEth(t) estimator := gasmocks.NewEvmEstimator(t) estimator.On("BumpDynamicFee", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(gas.DynamicFee{}, pkgerrors.Wrapf(fees.ErrConnectivity, "transaction...")) @@ -772,12 +771,10 @@ func TestEthConfirmer_RebroadcastWhereNecessary_WithConnectivityCheck(t *testing // Create confirmer with necessary state ge := ccfg.EVM().GasEstimator() feeEstimator := gas.NewEvmFeeEstimator(lggr, newEst, ge.EIP1559DynamicFees(), ge, ethClient) - txBuilder := txmgr.NewEvmTxAttemptBuilder(*ethClient.ConfiguredChainID(), ge, kst, feeEstimator) - addresses := []gethCommon.Address{fromAddress} - kst.On("EnabledAddressesForChain", mock.Anything, &cltest.FixtureChainID).Return(addresses, nil).Maybe() + kst := keystest.Addresses{fromAddress} + txBuilder := txmgr.NewEvmTxAttemptBuilder(*ethClient.ConfiguredChainID(), ge, keystest.TxSigner(nil), feeEstimator) stuckTxDetector := txmgr.NewStuckTxDetector(lggr, testutils.FixtureChainID, "", assets.NewWei(assets.NewEth(100).ToInt()), ccfg.EVM().Transactions().AutoPurge(), feeEstimator, txStore, ethClient) - ht := headstest.NewSimulatedHeadTracker(ethClient, true, 0) - ec := txmgr.NewEvmConfirmer(txStore, txmgr.NewEvmTxmClient(ethClient, nil), txmgr.NewEvmTxmFeeConfig(ccfg.EVM().GasEstimator()), ccfg.EVM().Transactions(), confirmerConfig{}, kst, txBuilder, lggr, stuckTxDetector, ht) + ec := txmgr.NewEvmConfirmer(txStore, txmgr.NewEvmTxmClient(ethClient, nil), txmgr.NewEvmTxmFeeConfig(ccfg.EVM().GasEstimator()), ccfg.EVM().Transactions(), confirmerConfig{}, kst, txBuilder, lggr, stuckTxDetector) servicetest.Run(t, ec) currentHead := int64(30) oldEnough := int64(15) @@ -819,9 +816,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary_MaxFeeScenario(t *testing.T) { _, _ = cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) - kst := ksmocks.NewEth(t) - addresses := []gethCommon.Address{fromAddress} - kst.On("EnabledAddressesForChain", mock.Anything, &cltest.FixtureChainID).Return(addresses, nil).Maybe() + kst := &keystest.FakeChainStore{Addresses: keystest.Addresses{fromAddress}} // Use a mock keystore for this test ec := newEthConfirmer(t, txStore, ethClient, evmcfg, kst, nil) currentHead := int64(30) @@ -835,20 +830,6 @@ func TestEthConfirmer_RebroadcastWhereNecessary_MaxFeeScenario(t *testing.T) { require.NoError(t, db.Get(&dbAttempt, `UPDATE evm.tx_attempts SET broadcast_before_block_num=$1 WHERE id=$2 RETURNING *`, oldEnough, attempt1_1.ID)) t.Run("treats an exceeds max fee attempt as a success", func(t *testing.T) { - ethTx := *types.NewTx(&types.LegacyTx{}) - kst.On("SignTx", mock.Anything, - fromAddress, - mock.MatchedBy(func(tx *types.Transaction) bool { - if tx.Nonce() != uint64(*etx.Sequence) { - return false - } - ethTx = *tx - return true - }), - mock.MatchedBy(func(chainID *big.Int) bool { - return chainID.Cmp(evmcfg.EVM().ChainID()) == 0 - })).Return(ðTx, nil).Once() - // Once for the bumped attempt which exceeds limit ethClient.On("SendTransactionReturnCode", mock.Anything, mock.MatchedBy(func(tx *types.Transaction) bool { return tx.GasPrice().Int64() == int64(20000000000) && tx.Nonce() == uint64(*etx.Sequence) //nolint:gosec // disable G115 @@ -883,8 +864,9 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { t.Run("does nothing if no transactions require bumping", func(t *testing.T) { db := testutils.NewSqlxDB(t) txStore := cltest.NewTestTxStore(t, db) - ethKeyStore := cltest.NewKeyStore(t, db).Eth() - cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) + memKS := keystest.NewMemoryChainStore() + memKS.MustCreate(t) + ethKeyStore := keys.NewChainStore(memKS, ethClient.ConfiguredChainID()) ec := newEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, nil) require.NoError(t, ec.RebroadcastWhereNecessary(ctx, currentHead)) @@ -893,18 +875,12 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { t.Run("re-sends previous transaction on keystore error", func(t *testing.T) { db := testutils.NewSqlxDB(t) txStore := cltest.NewTestTxStore(t, db) - ethKeyStore := cltest.NewKeyStore(t, db).Eth() - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) + memKS := keystest.NewMemoryChainStore() + fromAddress := memKS.MustCreate(t) + kst := keys.NewChainStore(memKS, ethClient.ConfiguredChainID()) + etx := mustInsertUnconfirmedTxWithBroadcastAttempts(t, txStore, 0, fromAddress, 1, 25, assets.NewWeiI(100)) - kst := ksmocks.NewEth(t) - addresses := []gethCommon.Address{fromAddress} - kst.On("EnabledAddressesForChain", mock.Anything, &cltest.FixtureChainID).Return(addresses, nil).Maybe() - // simulate bumped transaction that is somehow impossible to sign - kst.On("SignTx", mock.Anything, fromAddress, - mock.MatchedBy(func(tx *types.Transaction) bool { - return tx.Nonce() == uint64(*etx.Sequence) //nolint:gosec // disable G115 - }), - mock.Anything).Return(nil, errors.New("signing error")).Once() + // Use a mock keystore for this test ec := newEthConfirmer(t, txStore, ethClient, evmcfg, kst, nil) @@ -922,8 +898,9 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { t.Run("does nothing and continues on fatal error", func(t *testing.T) { db := testutils.NewSqlxDB(t) txStore := cltest.NewTestTxStore(t, db) - ethKeyStore := cltest.NewKeyStore(t, db).Eth() - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) + memKS := keystest.NewMemoryChainStore() + fromAddress := memKS.MustCreate(t) + ethKeyStore := keys.NewChainStore(memKS, ethClient.ConfiguredChainID()) etx := mustInsertUnconfirmedTxWithBroadcastAttempts(t, txStore, 0, fromAddress, 1, 25, assets.NewWeiI(100)) ec := newEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, nil) @@ -941,8 +918,9 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { t.Run("creates new attempt with higher gas price if transaction has an attempt older than threshold", func(t *testing.T) { db := testutils.NewSqlxDB(t) txStore := cltest.NewTestTxStore(t, db) - ethKeyStore := cltest.NewKeyStore(t, db).Eth() - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) + memKS := keystest.NewMemoryChainStore() + fromAddress := memKS.MustCreate(t) + ethKeyStore := keys.NewChainStore(memKS, ethClient.ConfiguredChainID()) latestGasPrice := assets.GWei(20) etx := mustInsertUnconfirmedTxWithBroadcastAttempts(t, txStore, 0, fromAddress, 1, 25, latestGasPrice) ec := newEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, nil) @@ -968,8 +946,9 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { t.Run("does nothing if there is an attempt without BroadcastBeforeBlockNum set", func(t *testing.T) { db := testutils.NewSqlxDB(t) txStore := cltest.NewTestTxStore(t, db) - ethKeyStore := cltest.NewKeyStore(t, db).Eth() - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) + memKS := keystest.NewMemoryChainStore() + fromAddress := memKS.MustCreate(t) + ethKeyStore := keys.NewChainStore(memKS, ethClient.ConfiguredChainID()) etx := mustInsertUnconfirmedEthTxWithAttemptState(t, txStore, 0, fromAddress, txmgrtypes.TxAttemptBroadcast) ec := newEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, nil) @@ -984,8 +963,9 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { t.Run("creates new attempt with higher gas price if transaction is already in mempool (e.g. due to previous crash before we could save the new attempt)", func(t *testing.T) { db := testutils.NewSqlxDB(t) txStore := cltest.NewTestTxStore(t, db) - ethKeyStore := cltest.NewKeyStore(t, db).Eth() - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) + memKS := keystest.NewMemoryChainStore() + fromAddress := memKS.MustCreate(t) + ethKeyStore := keys.NewChainStore(memKS, ethClient.ConfiguredChainID()) latestGasPrice := assets.GWei(20) etx := mustInsertUnconfirmedTxWithBroadcastAttempts(t, txStore, 0, fromAddress, 1, 25, latestGasPrice) ec := newEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, nil) @@ -1011,8 +991,9 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { t.Run("saves new attempt even for transaction that has already been confirmed (nonce already used)", func(t *testing.T) { db := testutils.NewSqlxDB(t) txStore := cltest.NewTestTxStore(t, db) - ethKeyStore := cltest.NewKeyStore(t, db).Eth() - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) + memKS := keystest.NewMemoryChainStore() + fromAddress := memKS.MustCreate(t) + ethKeyStore := keys.NewChainStore(memKS, ethClient.ConfiguredChainID()) latestGasPrice := assets.GWei(20) etx := mustInsertUnconfirmedTxWithBroadcastAttempts(t, txStore, 0, fromAddress, 1, 25, latestGasPrice) ec := newEthConfirmer(t, txStore, ethClient, evmcfg, ethKeyStore, nil) @@ -1041,8 +1022,9 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { t.Run("saves in-progress attempt on temporary error and returns error", func(t *testing.T) { db := testutils.NewSqlxDB(t) txStore := cltest.NewTestTxStore(t, db) - ethKeyStore := cltest.NewKeyStore(t, db).Eth() - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) + memKS := keystest.NewMemoryChainStore() + fromAddress := memKS.MustCreate(t) + ethKeyStore := keys.NewChainStore(memKS, ethClient.ConfiguredChainID()) latestGasPrice := assets.GWei(20) broadcastBlockNum := int64(25) etx := mustInsertUnconfirmedTxWithBroadcastAttempts(t, txStore, 0, fromAddress, 1, broadcastBlockNum, latestGasPrice) @@ -1092,8 +1074,9 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { t.Run("re-bumps attempt if initial bump is underpriced because the bumped gas price is insufficiently higher than the previous one", func(t *testing.T) { db := testutils.NewSqlxDB(t) txStore := cltest.NewTestTxStore(t, db) - ethKeyStore := cltest.NewKeyStore(t, db).Eth() - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) + memKS := keystest.NewMemoryChainStore() + fromAddress := memKS.MustCreate(t) + ethKeyStore := keys.NewChainStore(memKS, ethClient.ConfiguredChainID()) latestGasPrice := assets.GWei(20) broadcastBlockNum := int64(25) etx := mustInsertUnconfirmedTxWithBroadcastAttempts(t, txStore, 0, fromAddress, 1, broadcastBlockNum, latestGasPrice) @@ -1127,8 +1110,9 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { newCfg := configtest.NewChainScopedConfig(t, func(c *toml.EVMConfig) { c.GasEstimator.PriceMax = priceMax }) - ethKeyStore := cltest.NewKeyStore(t, db).Eth() - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) + memKS := keystest.NewMemoryChainStore() + fromAddress := memKS.MustCreate(t) + ethKeyStore := keys.NewChainStore(memKS, ethClient.ConfiguredChainID()) broadcastBlockNum := int64(25) currentAttemptPrice := priceMax.Sub(assets.GWei(1)) etx := mustInsertUnconfirmedTxWithBroadcastAttempts(t, txStore, 0, fromAddress, 1, broadcastBlockNum, currentAttemptPrice) @@ -1158,8 +1142,9 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { newCfg := configtest.NewChainScopedConfig(t, func(c *toml.EVMConfig) { c.GasEstimator.PriceMax = priceMax }) - ethKeyStore := cltest.NewKeyStore(t, db).Eth() - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) + memKS := keystest.NewMemoryChainStore() + fromAddress := memKS.MustCreate(t) + ethKeyStore := keys.NewChainStore(memKS, ethClient.ConfiguredChainID()) broadcastBlockNum := int64(25) etx := mustInsertUnconfirmedTxWithBroadcastAttempts(t, txStore, 0, fromAddress, 1, broadcastBlockNum, priceMax) ec := newEthConfirmer(t, txStore, ethClient, newCfg, ethKeyStore, nil) @@ -1187,8 +1172,9 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { newCfg := configtest.NewChainScopedConfig(t, func(c *toml.EVMConfig) { c.GasEstimator.BumpMin = assets.GWei(1) }) - ethKeyStore := cltest.NewKeyStore(t, db).Eth() - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) + memKS := keystest.NewMemoryChainStore() + fromAddress := memKS.MustCreate(t) + ethKeyStore := keys.NewChainStore(memKS, ethClient.ConfiguredChainID()) etx := mustInsertUnconfirmedEthTxWithBroadcastDynamicFeeAttempt(t, txStore, 0, fromAddress) err := txStore.UpdateTxAttemptBroadcastBeforeBlockNum(ctx, etx.ID, uint(25)) require.NoError(t, err) @@ -1218,8 +1204,9 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { newCfg := configtest.NewChainScopedConfig(t, func(c *toml.EVMConfig) { c.GasEstimator.PriceMax = assets.NewWeiI(1) }) - ethKeyStore := cltest.NewKeyStore(t, db).Eth() - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) + memKS := keystest.NewMemoryChainStore() + fromAddress := memKS.MustCreate(t) + ethKeyStore := keys.NewChainStore(memKS, ethClient.ConfiguredChainID()) etx := mustInsertUnconfirmedEthTxWithBroadcastDynamicFeeAttempt(t, txStore, 0, fromAddress) err := txStore.UpdateTxAttemptBroadcastBeforeBlockNum(ctx, etx.ID, uint(25)) require.NoError(t, err) @@ -1248,8 +1235,9 @@ func TestEthConfirmer_RebroadcastWhereNecessary(t *testing.T) { c.GasEstimator.BumpMin = assets.GWei(1) }) // NOTE: This test case was empirically impossible when I tried it on eth mainnet (any EIP1559 transaction with a higher tip cap is accepted even if it's only 1 wei more) but appears to be possible on Polygon/Matic, probably due to poor design that applies the 10% minimum to the overall value (base fee + tip cap) - ethKeyStore := cltest.NewKeyStore(t, db).Eth() - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) + memKS := keystest.NewMemoryChainStore() + fromAddress := memKS.MustCreate(t) + ethKeyStore := keys.NewChainStore(memKS, ethClient.ConfiguredChainID()) etx := mustInsertUnconfirmedEthTxWithBroadcastDynamicFeeAttempt(t, txStore, 0, fromAddress) err := txStore.UpdateTxAttemptBroadcastBeforeBlockNum(ctx, etx.ID, uint(25)) require.NoError(t, err) @@ -1282,19 +1270,14 @@ func TestEthConfirmer_RebroadcastWhereNecessary_TerminallyUnderpriced_ThenGoesTh db := testutils.NewSqlxDB(t) txStore := cltest.NewTestTxStore(t, db) - ethKeyStore := cltest.NewKeyStore(t, db).Eth() + memKS := keystest.NewMemoryChainStore() + fromAddress := memKS.MustCreate(t) + kst := keys.NewChainStore(memKS, big.NewInt(0)) evmcfg := configtest.NewChainScopedConfig(t, func(c *toml.EVMConfig) { c.GasEstimator.PriceMax = assets.GWei(500) }) - _, _ = cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) - - // Use a mock keystore for this test - kst := ksmocks.NewEth(t) - addresses := []gethCommon.Address{fromAddress} - kst.On("EnabledAddressesForChain", mock.Anything, &cltest.FixtureChainID).Return(addresses, nil).Maybe() currentHead := int64(30) oldEnough := 5 nonce := int64(0) @@ -1307,9 +1290,6 @@ func TestEthConfirmer_RebroadcastWhereNecessary_TerminallyUnderpriced_ThenGoesTh etx := mustInsertUnconfirmedEthTxWithAttemptState(t, txStore, nonce, fromAddress, txmgrtypes.TxAttemptInProgress, originalBroadcastAt) require.Equal(t, originalBroadcastAt, *etx.BroadcastAt) nonce++ - attempt := etx.TxAttempts[0] - signedTx, err := txmgr.GetGethSignedTx(attempt.SignedRawTx) - require.NoError(t, err) // Fail the first time with terminally underpriced. ethClient.On("SendTransactionReturnCode", mock.Anything, mock.Anything, fromAddress).Return( @@ -1317,9 +1297,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary_TerminallyUnderpriced_ThenGoesTh // Succeed the second time after bumping gas. ethClient.On("SendTransactionReturnCode", mock.Anything, mock.Anything, fromAddress).Return( multinode.Successful, nil).Once() - kst.On("SignTx", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return( - signedTx, nil, - ).Once() + require.NoError(t, ec.RebroadcastWhereNecessary(tests.Context(t), currentHead)) }) @@ -1340,18 +1318,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary_TerminallyUnderpriced_ThenGoesTh // Succeed the second time after bumping gas. ethClient.On("SendTransactionReturnCode", mock.Anything, mock.Anything, fromAddress).Return( multinode.Successful, nil).Once() - signedLegacyTx := new(types.Transaction) - kst.On("SignTx", mock.Anything, mock.Anything, mock.MatchedBy(func(tx *types.Transaction) bool { - return tx.Type() == 0x0 && tx.Nonce() == uint64(*etx.Sequence) //nolint:gosec // disable G115 - }), mock.Anything).Return( - signedLegacyTx, nil, - ).Run(func(args mock.Arguments) { - unsignedLegacyTx := args.Get(2).(*types.Transaction) - // Use the real keystore to do the actual signing - thisSignedLegacyTx, err := ethKeyStore.SignTx(tests.Context(t), fromAddress, unsignedLegacyTx, testutils.FixtureChainID) - require.NoError(t, err) - *signedLegacyTx = *thisSignedLegacyTx - }).Times(4) // 3 failures 1 success + require.NoError(t, ec.RebroadcastWhereNecessary(tests.Context(t), currentHead)) }) @@ -1372,18 +1339,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary_TerminallyUnderpriced_ThenGoesTh // Succeed the second time after bumping gas. ethClient.On("SendTransactionReturnCode", mock.Anything, mock.Anything, fromAddress).Return( multinode.Successful, nil).Once() - signedDxFeeTx := new(types.Transaction) - kst.On("SignTx", mock.Anything, mock.Anything, mock.MatchedBy(func(tx *types.Transaction) bool { - return tx.Type() == 0x2 && tx.Nonce() == uint64(*etx.Sequence) //nolint:gosec // disable G115 - }), mock.Anything).Return( - signedDxFeeTx, nil, - ).Run(func(args mock.Arguments) { - unsignedDxFeeTx := args.Get(2).(*types.Transaction) - // Use the real keystore to do the actual signing - thisSignedDxFeeTx, err := ethKeyStore.SignTx(tests.Context(t), fromAddress, unsignedDxFeeTx, testutils.FixtureChainID) - require.NoError(t, err) - *signedDxFeeTx = *thisSignedDxFeeTx - }).Times(4) // 3 failures 1 success + require.NoError(t, ec.RebroadcastWhereNecessary(tests.Context(t), currentHead)) }) } @@ -1395,15 +1351,9 @@ func TestEthConfirmer_RebroadcastWhereNecessary_WhenOutOfEth(t *testing.T) { ctx := tests.Context(t) ethClient := clienttest.NewClientWithDefaultChainID(t) - ethKeyStore := cltest.NewKeyStore(t, db).Eth() - - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) - - _, err := ethKeyStore.EnabledKeysForChain(tests.Context(t), testutils.FixtureChainID) - require.NoError(t, err) - require.NoError(t, err) - // keyStates, err := ethKeyStore.GetStatesForKeys(keys) - // require.NoError(t, err) + memKS := keystest.NewMemoryChainStore() + fromAddress := memKS.MustCreate(t) + ethKeyStore := keys.NewChainStore(memKS, ethClient.ConfiguredChainID()) config := configtest.NewChainScopedConfig(t, nil) currentHead := int64(30) @@ -1433,6 +1383,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary_WhenOutOfEth(t *testing.T) { // Do the thing require.NoError(t, ec.RebroadcastWhereNecessary(tests.Context(t), currentHead)) + var err error etx, err = txStore.FindTxWithAttempts(ctx, etx.ID) require.NoError(t, err) @@ -1459,6 +1410,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary_WhenOutOfEth(t *testing.T) { // Do the thing require.NoError(t, ec.RebroadcastWhereNecessary(tests.Context(t), currentHead)) + var err error etx, err = txStore.FindTxWithAttempts(ctx, etx.ID) require.NoError(t, err) @@ -1484,6 +1436,7 @@ func TestEthConfirmer_RebroadcastWhereNecessary_WhenOutOfEth(t *testing.T) { // Do the thing require.NoError(t, ec.RebroadcastWhereNecessary(tests.Context(t), currentHead)) + var err error etx, err = txStore.FindTxWithAttempts(ctx, etx.ID) require.NoError(t, err) @@ -1532,8 +1485,9 @@ func TestEthConfirmer_RebroadcastWhereNecessary_TerminallyStuckError(t *testing. ctx := tests.Context(t) ethClient := clienttest.NewClientWithDefaultChainID(t) - ethKeyStore := cltest.NewKeyStore(t, db).Eth() - _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore) + memKS := keystest.NewMemoryChainStore() + fromAddress := memKS.MustCreate(t) + ethKeyStore := keys.NewChainStore(memKS, ethClient.ConfiguredChainID()) evmcfg := configtest.NewChainScopedConfig(t, func(c *toml.EVMConfig) { c.GasEstimator.PriceMax = assets.GWei(500) @@ -1581,10 +1535,11 @@ func TestEthConfirmer_ForceRebroadcast(t *testing.T) { db := testutils.NewSqlxDB(t) txStore := cltest.NewTestTxStore(t, db) - ethKeyStore := cltest.NewKeyStore(t, db).Eth() - _, fromAddress := cltest.MustInsertRandomKeyReturningState(t, ethKeyStore) - + memKS := keystest.NewMemoryChainStore() + fromAddress := memKS.MustCreate(t) config := configtest.NewChainScopedConfig(t, nil) + ethKeyStore := keys.NewChainStore(memKS, big.NewInt(0)) + mustCreateUnstartedGeneratedTx(t, txStore, fromAddress, config.EVM().ChainID()) mustInsertInProgressEthTx(t, txStore, 0, fromAddress) etx1 := cltest.MustInsertUnconfirmedEthTxWithBroadcastLegacyAttempt(t, txStore, 1, fromAddress) @@ -1680,10 +1635,10 @@ func TestEthConfirmer_ProcessStuckTransactions(t *testing.T) { db := testutils.NewSqlxDB(t) txStore := cltest.NewTestTxStore(t, db) - ethKeyStore := cltest.NewKeyStore(t, db).Eth() - _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore) + fromAddress := cltest.MustGenerateRandomKey(t) + ethKeyStore := &keystest.FakeChainStore{Addresses: keystest.Addresses{fromAddress.Address}} ethClient := clienttest.NewClientWithDefaultChainID(t) - ethClient.On("SendTransactionReturnCode", mock.Anything, mock.Anything, fromAddress).Return(multinode.Successful, nil).Once() + ethClient.On("SendTransactionReturnCode", mock.Anything, mock.Anything, fromAddress.Address).Return(multinode.Successful, nil).Once() lggr := logger.Test(t) feeEstimator := gasmocks.NewEvmFeeEstimator(t) @@ -1706,8 +1661,7 @@ func TestEthConfirmer_ProcessStuckTransactions(t *testing.T) { ge := evmcfg.EVM().GasEstimator() txBuilder := txmgr.NewEvmTxAttemptBuilder(*ethClient.ConfiguredChainID(), ge, ethKeyStore, feeEstimator) stuckTxDetector := txmgr.NewStuckTxDetector(lggr, testutils.FixtureChainID, "", assets.NewWei(assets.NewEth(100).ToInt()), evmcfg.EVM().Transactions().AutoPurge(), feeEstimator, txStore, ethClient) - ht := headstest.NewSimulatedHeadTracker(ethClient, true, 0) - ec := txmgr.NewEvmConfirmer(txStore, txmgr.NewEvmTxmClient(ethClient, nil), txmgr.NewEvmTxmFeeConfig(ge), evmcfg.EVM().Transactions(), confirmerConfig{}, ethKeyStore, txBuilder, lggr, stuckTxDetector, ht) + ec := txmgr.NewEvmConfirmer(txStore, txmgr.NewEvmTxmClient(ethClient, nil), txmgr.NewEvmTxmFeeConfig(ge), evmcfg.EVM().Transactions(), confirmerConfig{}, ethKeyStore, txBuilder, lggr, stuckTxDetector) fn := func(ctx context.Context, id uuid.UUID, result interface{}, err error) error { require.ErrorContains(t, err, client.TerminallyStuckMsg) return nil @@ -1723,7 +1677,7 @@ func TestEthConfirmer_ProcessStuckTransactions(t *testing.T) { // Create attempts so that the oldest broadcast attempt's block num is what meets the threshold check // Create autoPurgeMinAttempts number of attempts to ensure the broadcast attempt count check is not being triggered // Create attempts broadcasted autoPurgeThreshold block ago to ensure broadcast block num check is not being triggered - tx := mustInsertUnconfirmedTxWithBroadcastAttempts(t, txStore, nonce, fromAddress, autoPurgeMinAttempts, blockNum-int64(autoPurgeThreshold), marketGasPrice.Add(oneGwei)) + tx := mustInsertUnconfirmedTxWithBroadcastAttempts(t, txStore, nonce, fromAddress.Address, autoPurgeMinAttempts, blockNum-int64(autoPurgeThreshold), marketGasPrice.Add(oneGwei)) // Update tx to signal callback once it is identified as terminally stuck testutils.MustExec(t, db, `UPDATE evm.txes SET pipeline_task_run_id = $1, signal_callback = TRUE WHERE id = $2`, uuid.New(), tx.ID) head := evmtypes.Head{ @@ -1775,7 +1729,7 @@ func TestEthConfirmer_ProcessStuckTransactions(t *testing.T) { func ptr[T any](t T) *T { return &t } -func newEthConfirmer(t testing.TB, txStore txmgr.EvmTxStore, ethClient client.Client, config evmconfig.ChainScopedConfig, ks keystore.Eth, fn txmgrcommon.ResumeCallback) *txmgr.Confirmer { +func newEthConfirmer(t testing.TB, txStore txmgr.EvmTxStore, ethClient client.Client, config evmconfig.ChainScopedConfig, ks keys.ChainStore, fn txmgrcommon.ResumeCallback) *txmgr.Confirmer { lggr := logger.Test(t) ge := config.EVM().GasEstimator() estimator := gas.NewEvmFeeEstimator(lggr, func(lggr logger.Logger) gas.EvmEstimator { @@ -1783,8 +1737,7 @@ func newEthConfirmer(t testing.TB, txStore txmgr.EvmTxStore, ethClient client.Cl }, ge.EIP1559DynamicFees(), ge, ethClient) txBuilder := txmgr.NewEvmTxAttemptBuilder(*ethClient.ConfiguredChainID(), ge, ks, estimator) stuckTxDetector := txmgr.NewStuckTxDetector(lggr, testutils.FixtureChainID, "", assets.NewWei(assets.NewEth(100).ToInt()), config.EVM().Transactions().AutoPurge(), estimator, txStore, ethClient) - ht := headstest.NewSimulatedHeadTracker(ethClient, true, 0) - ec := txmgr.NewEvmConfirmer(txStore, txmgr.NewEvmTxmClient(ethClient, nil), txmgr.NewEvmTxmFeeConfig(ge), config.EVM().Transactions(), confirmerConfig{}, ks, txBuilder, lggr, stuckTxDetector, ht) + ec := txmgr.NewEvmConfirmer(txStore, txmgr.NewEvmTxmClient(ethClient, nil), txmgr.NewEvmTxmFeeConfig(ge), config.EVM().Transactions(), confirmerConfig{}, ks, txBuilder, lggr, stuckTxDetector) ec.SetResumeCallback(fn) servicetest.Run(t, ec) return ec diff --git a/core/chains/evm/txmgr/models.go b/core/chains/evm/txmgr/models.go index ed29f807aea..ce7383fd8ee 100644 --- a/core/chains/evm/txmgr/models.go +++ b/core/chains/evm/txmgr/models.go @@ -11,7 +11,7 @@ import ( "github.com/smartcontractkit/chainlink-framework/chains/txmgr" txmgrtypes "github.com/smartcontractkit/chainlink-framework/chains/txmgr/types" "github.com/smartcontractkit/chainlink-integrations/evm/gas" - "github.com/smartcontractkit/chainlink-integrations/evm/keystore" + "github.com/smartcontractkit/chainlink-integrations/evm/keys" evmtypes "github.com/smartcontractkit/chainlink-integrations/evm/types" ) @@ -24,7 +24,7 @@ type ( Reaper = txmgr.Reaper[*big.Int] TxStore = txmgrtypes.TxStore[common.Address, *big.Int, common.Hash, common.Hash, *evmtypes.Receipt, evmtypes.Nonce, gas.EvmFee] TransactionStore = txmgrtypes.TransactionStore[common.Address, *big.Int, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee] - KeyStore = txmgrtypes.KeyStore[common.Address, *big.Int] + KeyStore = txmgrtypes.KeyStore[common.Address] TxAttemptBuilder = txmgrtypes.TxAttemptBuilder[*big.Int, *evmtypes.Head, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee] NonceTracker = txmgrtypes.SequenceTracker[common.Address, evmtypes.Nonce] TransmitCheckerFactory = txmgr.TransmitCheckerFactory[*big.Int, common.Address, common.Hash, common.Hash, evmtypes.Nonce, gas.EvmFee] @@ -45,7 +45,7 @@ type ( Finalizer = txmgrtypes.Finalizer[common.Hash, *evmtypes.Head] ) -var _ KeyStore = (keystore.Eth)(nil) // check interface in txmgr to avoid circular import +var _ KeyStore = (keys.Addresses)(nil) // check interface in txmgr to avoid circular import const ( // TransmitCheckerTypeSimulate is a checker that simulates the transaction before executing on diff --git a/core/chains/evm/txmgr/resender_test.go b/core/chains/evm/txmgr/resender_test.go index 5d314be4024..562a35e957c 100644 --- a/core/chains/evm/txmgr/resender_test.go +++ b/core/chains/evm/txmgr/resender_test.go @@ -16,6 +16,8 @@ import ( commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/utils/tests" + "github.com/smartcontractkit/chainlink-integrations/evm/keys" + "github.com/smartcontractkit/chainlink-integrations/evm/keys/keystest" "github.com/smartcontractkit/chainlink-integrations/evm/client/clienttest" "github.com/smartcontractkit/chainlink-integrations/evm/config/toml" @@ -30,14 +32,16 @@ func Test_EthResender_resendUnconfirmed(t *testing.T) { db := testutils.NewSqlxDB(t) lggr := logger.Test(t) - ethKeyStore := cltest.NewKeyStore(t, db).Eth() + ethClient := clienttest.NewClientWithDefaultChainID(t) ethClient.On("IsL2").Return(false).Maybe() ccfg := testutils.NewTestChainScopedConfig(t, nil) - _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore) - _, fromAddress2 := cltest.MustInsertRandomKey(t, ethKeyStore) - _, fromAddress3 := cltest.MustInsertRandomKey(t, ethKeyStore) + memKS := keystest.NewMemoryChainStore() + fromAddress := memKS.MustCreate(t) + fromAddress2 := memKS.MustCreate(t) + fromAddress3 := memKS.MustCreate(t) + ethKeyStore := keys.NewChainStore(memKS, big.NewInt(0)) txStore := cltest.NewTestTxStore(t, db) @@ -100,8 +104,12 @@ func Test_EthResender_alertUnconfirmed(t *testing.T) { db := testutils.NewSqlxDB(t) lggr, o := logger.TestObserved(t, zapcore.DebugLevel) - ethKeyStore := cltest.NewKeyStore(t, db).Eth() + ethClient := clienttest.NewClientWithDefaultChainID(t) + memKS := keystest.NewMemoryChainStore() + fromAddress := memKS.MustCreate(t) + ethKeyStore := keys.NewChainStore(memKS, big.NewInt(0)) + ethClient.On("IsL2").Return(false).Maybe() // Set this to the smallest non-zero value possible for the attempt to be eligible for resend delay := commonconfig.MustNewDuration(1 * time.Nanosecond) @@ -111,8 +119,6 @@ func Test_EthResender_alertUnconfirmed(t *testing.T) { }) }) - _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore) - txStore := cltest.NewTestTxStore(t, db) originalBroadcastAt := time.Unix(1616509100, 0) @@ -145,8 +151,9 @@ func Test_EthResender_Start(t *testing.T) { }) txStore := cltest.NewTestTxStore(t, db) - ethKeyStore := cltest.NewKeyStore(t, db).Eth() - _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore) + memKS := keystest.NewMemoryChainStore() + fromAddress := memKS.MustCreate(t) + ethKeyStore := keys.NewChainStore(memKS, big.NewInt(0)) lggr := logger.Test(t) t.Run("resends transactions that have been languishing unconfirmed for too long", func(t *testing.T) { diff --git a/core/chains/evm/txmgr/tracker_test.go b/core/chains/evm/txmgr/tracker_test.go index 80263311bc5..93cc3a6afd1 100644 --- a/core/chains/evm/txmgr/tracker_test.go +++ b/core/chains/evm/txmgr/tracker_test.go @@ -6,31 +6,29 @@ import ( "testing" "time" - "github.com/ethereum/go-ethereum/common" "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/utils/tests" - "github.com/smartcontractkit/chainlink-integrations/evm/client/clienttest" - "github.com/smartcontractkit/chainlink-integrations/evm/keystore" + "github.com/smartcontractkit/chainlink-integrations/evm/keys" + "github.com/smartcontractkit/chainlink-integrations/evm/keys/keystest" "github.com/smartcontractkit/chainlink-integrations/evm/testutils" - ubig "github.com/smartcontractkit/chainlink-integrations/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" ) -func newTestEvmTrackerSetup(t *testing.T) (*txmgr.Tracker, txmgr.TestEvmTxStore, keystore.Eth, []common.Address) { +func newTestEvmTrackerSetup(t *testing.T) (*txmgr.Tracker, txmgr.TestEvmTxStore) { db := testutils.NewSqlxDB(t) txStore := cltest.NewTestTxStore(t, db) - ethKeyStore := cltest.NewKeyStore(t, db).Eth() chainID := big.NewInt(0) - var enabledAddresses []common.Address - _, addr1 := cltest.MustInsertRandomKey(t, ethKeyStore, *ubig.NewI(chainID.Int64())) - _, addr2 := cltest.MustInsertRandomKey(t, ethKeyStore, *ubig.NewI(chainID.Int64())) + memKS := keystest.NewMemoryChainStore() + var enabledAddresses keystest.Addresses + addr1 := memKS.MustCreate(t) + addr2 := memKS.MustCreate(t) enabledAddresses = append(enabledAddresses, addr1, addr2) lggr := logger.Test(t) - return txmgr.NewEvmTracker(txStore, ethKeyStore, chainID, lggr), txStore, ethKeyStore, enabledAddresses + return txmgr.NewEvmTracker(txStore, keys.NewStore(memKS), chainID, lggr), txStore } func containsID(txes []*txmgr.Tx, id int64) bool { @@ -45,7 +43,7 @@ func containsID(txes []*txmgr.Tx, id int64) bool { func TestEvmTracker_Initialization(t *testing.T) { t.Parallel() - tracker, _, _, _ := newTestEvmTrackerSetup(t) + tracker, _ := newTestEvmTrackerSetup(t) ctx := tests.Context(t) require.NoError(t, tracker.Start(ctx)) @@ -63,7 +61,7 @@ func TestEvmTracker_AddressTracking(t *testing.T) { t.Run("track abandoned addresses", func(t *testing.T) { ethClient := clienttest.NewClientWithDefaultChainID(t) - tracker, txStore, _, _ := newTestEvmTrackerSetup(t) + tracker, txStore := newTestEvmTrackerSetup(t) inProgressAddr := cltest.MustGenerateRandomKey(t).Address unstartedAddr := cltest.MustGenerateRandomKey(t).Address unconfirmedAddr := cltest.MustGenerateRandomKey(t).Address @@ -123,7 +121,7 @@ func TestEvmTracker_ExceedingTTL(t *testing.T) { ctx := tests.Context(t) t.Run("exceeding ttl", func(t *testing.T) { - tracker, txStore, _, _ := newTestEvmTrackerSetup(t) + tracker, txStore := newTestEvmTrackerSetup(t) addr1 := cltest.MustGenerateRandomKey(t).Address addr2 := cltest.MustGenerateRandomKey(t).Address tx1 := mustInsertInProgressEthTxWithAttempt(t, txStore, 123, addr1) diff --git a/core/chains/evm/txmgr/txmgr_test.go b/core/chains/evm/txmgr/txmgr_test.go index 808340ac219..e38a9db6f61 100644 --- a/core/chains/evm/txmgr/txmgr_test.go +++ b/core/chains/evm/txmgr/txmgr_test.go @@ -24,10 +24,8 @@ import ( commontypes "github.com/smartcontractkit/chainlink-common/pkg/types" commonutils "github.com/smartcontractkit/chainlink-common/pkg/utils" "github.com/smartcontractkit/chainlink-common/pkg/utils/tests" - txmgrcommon "github.com/smartcontractkit/chainlink-framework/chains/txmgr" txmgrtypes "github.com/smartcontractkit/chainlink-framework/chains/txmgr/types" - "github.com/smartcontractkit/chainlink-integrations/evm/assets" evmclient "github.com/smartcontractkit/chainlink-integrations/evm/client" "github.com/smartcontractkit/chainlink-integrations/evm/client/clienttest" @@ -35,8 +33,8 @@ import ( "github.com/smartcontractkit/chainlink-integrations/evm/gas" gasmocks "github.com/smartcontractkit/chainlink-integrations/evm/gas/mocks" "github.com/smartcontractkit/chainlink-integrations/evm/heads/headstest" - "github.com/smartcontractkit/chainlink-integrations/evm/keystore" - ksmocks "github.com/smartcontractkit/chainlink-integrations/evm/keystore/mocks" + "github.com/smartcontractkit/chainlink-integrations/evm/keys" + "github.com/smartcontractkit/chainlink-integrations/evm/keys/keystest" "github.com/smartcontractkit/chainlink-integrations/evm/logpoller" "github.com/smartcontractkit/chainlink-integrations/evm/testutils" evmtypes "github.com/smartcontractkit/chainlink-integrations/evm/types" @@ -45,12 +43,14 @@ import ( commontxmmocks "github.com/smartcontractkit/chainlink/v2/common/txmgr/types/mocks" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/forwarders" + evmtxm "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txm" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" + "github.com/smartcontractkit/chainlink/v2/core/services/keystore" ) func makeTestEvmTxm( - t testing.TB, db *sqlx.DB, ethClient evmclient.Client, estimator gas.EvmFeeEstimator, ccfg txmgr.ChainConfig, fcfg txmgr.FeeConfig, txConfig evmconfig.Transactions, dbConfig txmgr.DatabaseConfig, listenerConfig txmgr.ListenerConfig, keyStore keystore.Eth) (txmgr.TxManager, error) { + t testing.TB, db *sqlx.DB, ethClient evmclient.Client, estimator gas.EvmFeeEstimator, ccfg txmgr.ChainConfig, fcfg txmgr.FeeConfig, txConfig evmconfig.Transactions, dbConfig txmgr.DatabaseConfig, listenerConfig txmgr.ListenerConfig, keyStore keys.ChainStore) (txmgr.TxManager, error) { lggr := logger.Test(t) lpOpts := logpoller.Opts{ PollPeriod: 100 * time.Millisecond, @@ -99,11 +99,10 @@ func TestTxm_SendNativeToken_DoesNotSendToZero(t *testing.T) { config, dbConfig, evmConfig := txmgr.MakeTestConfigs(t) - keyStore := cltest.NewKeyStore(t, db).Eth() ethClient := clienttest.NewClientWithDefaultChainID(t) estimator, err := gas.NewEstimator(logger.Test(t), ethClient, config.ChainType(), ethClient.ConfiguredChainID(), evmConfig.GasEstimator(), nil) require.NoError(t, err) - txm, err := makeTestEvmTxm(t, db, ethClient, estimator, evmConfig, evmConfig.GasEstimator(), evmConfig.Transactions(), dbConfig, dbConfig.Listener(), keyStore) + txm, err := makeTestEvmTxm(t, db, ethClient, estimator, evmConfig, evmConfig.GasEstimator(), evmConfig.Transactions(), dbConfig, dbConfig.Listener(), &keystest.FakeChainStore{}) require.NoError(t, err) _, err = txm.SendNativeToken(tests.Context(t), big.NewInt(0), from, to, *value, 21000) @@ -116,9 +115,10 @@ func TestTxm_CreateTransaction(t *testing.T) { db := testutils.NewSqlxDB(t) txStore := cltest.NewTestTxStore(t, db) - kst := cltest.NewKeyStore(t, db) + memKS := keystest.NewMemoryChainStore() + fromAddress := memKS.MustCreate(t) + ethKeyStore := keys.NewChainStore(memKS, big.NewInt(0)) - _, fromAddress := cltest.MustInsertRandomKey(t, kst.Eth()) toAddress := testutils.NewAddress() gasLimit := uint64(1000) payload := []byte{1, 2, 3} @@ -129,7 +129,7 @@ func TestTxm_CreateTransaction(t *testing.T) { estimator, err := gas.NewEstimator(logger.Test(t), ethClient, config.ChainType(), ethClient.ConfiguredChainID(), evmConfig.GasEstimator(), nil) require.NoError(t, err) - txm, err := makeTestEvmTxm(t, db, ethClient, estimator, evmConfig, evmConfig.GasEstimator(), evmConfig.Transactions(), dbConfig, dbConfig.Listener(), kst.Eth()) + txm, err := makeTestEvmTxm(t, db, ethClient, estimator, evmConfig, evmConfig.GasEstimator(), evmConfig.Transactions(), dbConfig, dbConfig.Listener(), ethKeyStore) require.NoError(t, err) t.Run("with queue under capacity inserts eth_tx", func(t *testing.T) { @@ -212,7 +212,7 @@ func TestTxm_CreateTransaction(t *testing.T) { assert.Equal(t, tx1.GetID(), tx2.GetID()) }) - t.Run("returns error if eth key state is missing or doesn't match chain ID", func(t *testing.T) { + t.Run("returns error if eth key is not enabled", func(t *testing.T) { rndAddr := testutils.NewAddress() _, err := txm.CreateTransaction(tests.Context(t), txmgr.TxRequest{ FromAddress: rndAddr, @@ -222,19 +222,12 @@ func TestTxm_CreateTransaction(t *testing.T) { Strategy: txmgrcommon.NewSendEveryStrategy(), }) require.Error(t, err) - assert.Contains(t, err.Error(), fmt.Sprintf("no eth key exists with address %s", rndAddr.String())) - - _, otherAddress := cltest.MustInsertRandomKey(t, kst.Eth(), *ubig.NewI(1337)) - - _, err = txm.CreateTransaction(tests.Context(t), txmgr.TxRequest{ - FromAddress: otherAddress, - ToAddress: testutils.NewAddress(), - EncodedPayload: []byte{1, 2, 3}, - FeeLimit: 21000, - Strategy: txmgrcommon.NewSendEveryStrategy(), - }) - require.Error(t, err) - assert.Contains(t, err.Error(), fmt.Sprintf("cannot send transaction from %s on chain ID 0: eth key with address %s exists but is has not been enabled for chain 0 (enabled only for chain IDs: 1337)", otherAddress.Hex(), otherAddress.Hex())) + assert.ErrorIs(t, err, evmtxm.NotEnabledError{}) + assert.ErrorIs(t, err, evmtxm.NotEnabledError{FromAddress: rndAddr}) + var as evmtxm.NotEnabledError + if assert.ErrorAs(t, err, &as) { + assert.Equal(t, rndAddr.String(), as.FromAddress.String()) + } }) t.Run("simulate transmit checker", func(t *testing.T) { @@ -406,7 +399,7 @@ func BenchmarkCreateTransaction(b *testing.B) { estimator, err := gas.NewEstimator(logger.Test(b), ethClient, config.ChainType(), ethClient.ConfiguredChainID(), evmConfig.GasEstimator(), nil) require.NoError(b, err) - txm, err := makeTestEvmTxm(b, db, ethClient, estimator, evmConfig, evmConfig.GasEstimator(), evmConfig.Transactions(), dbConfig, dbConfig.Listener(), kst.Eth()) + txm, err := makeTestEvmTxm(b, db, ethClient, estimator, evmConfig, evmConfig.GasEstimator(), evmConfig.Transactions(), dbConfig, dbConfig.Listener(), keys.NewChainStore(keystore.NewEthSigner(kst.Eth(), new(big.Int)), new(big.Int))) require.NoError(b, err) subject := uuid.New() @@ -432,13 +425,12 @@ func newMockTxStrategy(t testing.TB) *commontxmmocks.TxStrategy { func TestTxm_CreateTransaction_OutOfEth(t *testing.T) { db := testutils.NewSqlxDB(t) txStore := cltest.NewTestTxStore(t, db) - etKeyStore := cltest.NewKeyStore(t, db).Eth() - thisKey, _ := cltest.RandomKey{Nonce: 1}.MustInsert(t, etKeyStore) - otherKey, _ := cltest.RandomKey{Nonce: 1}.MustInsert(t, etKeyStore) + memKS := keystest.NewMemoryChainStore() + fromAddress := memKS.MustCreate(t) + otherAddress := memKS.MustCreate(t) + ethKeyStore := keys.NewChainStore(memKS, big.NewInt(0)) - fromAddress := thisKey.Address - evmFromAddress := fromAddress gasLimit := uint64(1000) toAddress := testutils.NewAddress() @@ -447,20 +439,20 @@ func TestTxm_CreateTransaction_OutOfEth(t *testing.T) { ethClient := clienttest.NewClientWithDefaultChainID(t) estimator, err := gas.NewEstimator(logger.Test(t), ethClient, config.ChainType(), ethClient.ConfiguredChainID(), evmConfig.GasEstimator(), nil) require.NoError(t, err) - txm, err := makeTestEvmTxm(t, db, ethClient, estimator, evmConfig, evmConfig.GasEstimator(), evmConfig.Transactions(), dbConfig, dbConfig.Listener(), etKeyStore) + txm, err := makeTestEvmTxm(t, db, ethClient, estimator, evmConfig, evmConfig.GasEstimator(), evmConfig.Transactions(), dbConfig, dbConfig.Listener(), ethKeyStore) require.NoError(t, err) t.Run("if another key has any transactions with insufficient eth errors, transmits as normal", func(t *testing.T) { payload := cltest.MustRandomBytes(t, 100) evmConfig.MaxQueued = uint64(1) - mustInsertUnconfirmedEthTxWithInsufficientEthAttempt(t, txStore, 0, otherKey.Address) + mustInsertUnconfirmedEthTxWithInsufficientEthAttempt(t, txStore, 0, otherAddress) strategy := newMockTxStrategy(t) strategy.On("Subject").Return(uuid.NullUUID{}) strategy.On("PruneQueue", mock.Anything, mock.Anything).Return(nil, nil) etx, err := txm.CreateTransaction(tests.Context(t), txmgr.TxRequest{ - FromAddress: evmFromAddress, + FromAddress: fromAddress, ToAddress: toAddress, EncodedPayload: payload, FeeLimit: gasLimit, @@ -472,19 +464,19 @@ func TestTxm_CreateTransaction_OutOfEth(t *testing.T) { require.Equal(t, payload, etx.EncodedPayload) }) - require.NoError(t, commonutils.JustError(db.Exec(`DELETE FROM evm.txes WHERE from_address = $1`, thisKey.Address))) + require.NoError(t, commonutils.JustError(db.Exec(`DELETE FROM evm.txes WHERE from_address = $1`, fromAddress))) t.Run("if this key has any transactions with insufficient eth errors, inserts it anyway", func(t *testing.T) { payload := cltest.MustRandomBytes(t, 100) evmConfig.MaxQueued = uint64(1) - mustInsertUnconfirmedEthTxWithInsufficientEthAttempt(t, txStore, 0, thisKey.Address) + mustInsertUnconfirmedEthTxWithInsufficientEthAttempt(t, txStore, 0, fromAddress) strategy := newMockTxStrategy(t) strategy.On("Subject").Return(uuid.NullUUID{}) strategy.On("PruneQueue", mock.Anything, mock.Anything).Return(nil, nil) etx, err := txm.CreateTransaction(tests.Context(t), txmgr.TxRequest{ - FromAddress: evmFromAddress, + FromAddress: fromAddress, ToAddress: toAddress, EncodedPayload: payload, FeeLimit: gasLimit, @@ -495,18 +487,18 @@ func TestTxm_CreateTransaction_OutOfEth(t *testing.T) { require.Equal(t, payload, etx.EncodedPayload) }) - require.NoError(t, commonutils.JustError(db.Exec(`DELETE FROM evm.txes WHERE from_address = $1`, thisKey.Address))) + require.NoError(t, commonutils.JustError(db.Exec(`DELETE FROM evm.txes WHERE from_address = $1`, fromAddress))) t.Run("if this key has transactions but no insufficient eth errors, transmits as normal", func(t *testing.T) { payload := cltest.MustRandomBytes(t, 100) - cltest.MustInsertConfirmedEthTxWithLegacyAttempt(t, txStore, 0, 42, thisKey.Address) + cltest.MustInsertConfirmedEthTxWithLegacyAttempt(t, txStore, 0, 42, fromAddress) strategy := newMockTxStrategy(t) strategy.On("Subject").Return(uuid.NullUUID{}) strategy.On("PruneQueue", mock.Anything, mock.Anything).Return(nil, nil) evmConfig.MaxQueued = uint64(1) etx, err := txm.CreateTransaction(tests.Context(t), txmgr.TxRequest{ - FromAddress: evmFromAddress, + FromAddress: fromAddress, ToAddress: toAddress, EncodedPayload: payload, FeeLimit: gasLimit, @@ -522,7 +514,6 @@ func TestTxm_Lifecycle(t *testing.T) { db := testutils.NewSqlxDB(t) ethClient := clienttest.NewClientWithDefaultChainID(t) - kst := ksmocks.NewEth(t) config, dbConfig, evmConfig := txmgr.MakeTestConfigs(t) config.SetFinalityDepth(uint32(42)) @@ -532,7 +523,7 @@ func TestTxm_Lifecycle(t *testing.T) { evmConfig.ReaperThreshold = 1 * time.Hour evmConfig.ReaperInterval = 1 * time.Hour - kst.On("EnabledAddressesForChain", mock.Anything, &cltest.FixtureChainID).Return([]common.Address{}, nil) + kst := &keystest.FakeChainStore{} head := cltest.Head(42) finalizedHead := cltest.Head(0) @@ -540,9 +531,6 @@ func TestTxm_Lifecycle(t *testing.T) { ethClient.On("HeadByNumber", mock.Anything, mock.Anything).Return(head, nil) ethClient.On("HeadByNumber", mock.Anything, mock.Anything).Return(finalizedHead, nil) - keyChangeCh := make(chan struct{}) - unsub := cltest.NewAwaiter() - kst.On("SubscribeToKeyChanges", mock.Anything).Return(keyChangeCh, unsub.ItHappened) estimator, err := gas.NewEstimator(logger.Test(t), ethClient, config.ChainType(), ethClient.ConfiguredChainID(), evmConfig.GasEstimator(), nil) require.NoError(t, err) txm, err := makeTestEvmTxm(t, db, ethClient, estimator, evmConfig, evmConfig.GasEstimator(), evmConfig.Transactions(), dbConfig, dbConfig.Listener(), kst) @@ -560,15 +548,9 @@ func TestTxm_Lifecycle(t *testing.T) { txm.OnNewLongestChain(ctx, head) require.NoError(t, ctx.Err()) - keyState := cltest.MustGenerateRandomKeyState(t) - - addr := []common.Address{keyState.Address.Address()} - kst.On("EnabledAddressesForChain", mock.Anything, &cltest.FixtureChainID).Return(addr, nil) ethClient.On("PendingNonceAt", mock.AnythingOfType("*context.cancelCtx"), common.Address{}).Return(uint64(0), nil).Maybe() - keyChangeCh <- struct{}{} require.NoError(t, txm.Close()) - unsub.AwaitOrFail(t, 1*time.Second) } func TestTxm_Reset(t *testing.T) { @@ -578,10 +560,11 @@ func TestTxm_Reset(t *testing.T) { db := testutils.NewSqlxDB(t) _, dbConfig, evmConfig := txmgr.MakeTestConfigs(t) - kst := cltest.NewKeyStore(t, db) + memKS := keystest.NewMemoryChainStore() + addr := memKS.MustCreate(t) + addr2 := memKS.MustCreate(t) + ethKeyStore := keys.NewChainStore(memKS, big.NewInt(0)) - _, addr := cltest.RandomKey{}.MustInsert(t, kst.Eth()) - _, addr2 := cltest.RandomKey{}.MustInsert(t, kst.Eth()) txStore := cltest.NewTestTxStore(t, db) // 4 confirmed tx from addr1 for i := int64(0); i < 4; i++ { @@ -600,7 +583,7 @@ func TestTxm_Reset(t *testing.T) { estimator, err := gas.NewEstimator(logger.Test(t), ethClient, evmConfig.ChainType(), ethClient.ConfiguredChainID(), evmConfig.GasEstimator(), nil) require.NoError(t, err) - txm, err := makeTestEvmTxm(t, db, ethClient, estimator, evmConfig, evmConfig.GasEstimator(), evmConfig.Transactions(), dbConfig, dbConfig.Listener(), kst.Eth()) + txm, err := makeTestEvmTxm(t, db, ethClient, estimator, evmConfig, evmConfig.GasEstimator(), evmConfig.Transactions(), dbConfig, dbConfig.Listener(), ethKeyStore) require.NoError(t, err) cltest.MustInsertUnconfirmedEthTxWithBroadcastLegacyAttempt(t, txStore, 2, addr2) @@ -644,7 +627,8 @@ func TestTxm_GetTransactionStatus(t *testing.T) { ctx := tests.Context(t) db := testutils.NewSqlxDB(t) txStore := cltest.NewTestTxStore(t, db) - ethKeyStore := cltest.NewKeyStore(t, db).Eth() + memKS := keystest.NewMemoryChainStore() + ethKeyStore := keys.NewChainStore(memKS, big.NewInt(0)) feeLimit := uint64(10_000) _, dbConfig, evmConfig := txmgr.MakeTestConfigs(t) @@ -684,7 +668,7 @@ func TestTxm_GetTransactionStatus(t *testing.T) { t.Run("returns unknown for unstarted state", func(t *testing.T) { idempotencyKey := uuid.New().String() - _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore) + fromAddress := memKS.MustCreate(t) tx := &txmgr.Tx{ IdempotencyKey: &idempotencyKey, FromAddress: fromAddress, @@ -701,7 +685,7 @@ func TestTxm_GetTransactionStatus(t *testing.T) { t.Run("returns unknown for in-progress state", func(t *testing.T) { idempotencyKey := uuid.New().String() - _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore) + fromAddress := memKS.MustCreate(t) nonce := evmtypes.Nonce(0) tx := &txmgr.Tx{ Sequence: &nonce, @@ -720,7 +704,7 @@ func TestTxm_GetTransactionStatus(t *testing.T) { t.Run("returns pending for unconfirmed state", func(t *testing.T) { idempotencyKey := uuid.New().String() - _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore) + fromAddress := memKS.MustCreate(t) nonce := evmtypes.Nonce(0) broadcast := time.Now() tx := &txmgr.Tx{ @@ -742,7 +726,7 @@ func TestTxm_GetTransactionStatus(t *testing.T) { t.Run("returns unconfirmed for confirmed state", func(t *testing.T) { idempotencyKey := uuid.New().String() - _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore) + fromAddress := memKS.MustCreate(t) nonce := evmtypes.Nonce(0) broadcast := time.Now() tx := &txmgr.Tx{ @@ -771,7 +755,7 @@ func TestTxm_GetTransactionStatus(t *testing.T) { t.Run("returns finalized for finalized state", func(t *testing.T) { idempotencyKey := uuid.New().String() - _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore) + fromAddress := memKS.MustCreate(t) nonce := evmtypes.Nonce(0) broadcast := time.Now() tx := &txmgr.Tx{ @@ -800,7 +784,7 @@ func TestTxm_GetTransactionStatus(t *testing.T) { t.Run("returns pending for confirmed missing receipt state", func(t *testing.T) { idempotencyKey := uuid.New().String() - _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore) + fromAddress := memKS.MustCreate(t) nonce := evmtypes.Nonce(0) broadcast := time.Now() tx := &txmgr.Tx{ @@ -822,7 +806,7 @@ func TestTxm_GetTransactionStatus(t *testing.T) { t.Run("returns fatal for fatal error state with terminally stuck error", func(t *testing.T) { idempotencyKey := uuid.New().String() - _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore) + fromAddress := memKS.MustCreate(t) // Test the internal terminally stuck error returns Fatal nonce := evmtypes.Nonce(0) broadcast := time.Now() @@ -869,7 +853,7 @@ func TestTxm_GetTransactionStatus(t *testing.T) { t.Run("returns failed for fatal error state with other error", func(t *testing.T) { idempotencyKey := uuid.New().String() - _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore) + fromAddress := memKS.MustCreate(t) errorMsg := "something went wrong" tx := &txmgr.Tx{ IdempotencyKey: &idempotencyKey, diff --git a/core/chains/legacyevm/chain.go b/core/chains/legacyevm/chain.go index 5b60f3ac0a8..a1d06e01f81 100644 --- a/core/chains/legacyevm/chain.go +++ b/core/chains/legacyevm/chain.go @@ -11,18 +11,18 @@ import ( "go.uber.org/multierr" common "github.com/smartcontractkit/chainlink-common/pkg/chains" + "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/services" "github.com/smartcontractkit/chainlink-common/pkg/sqlutil" "github.com/smartcontractkit/chainlink-common/pkg/types" "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox" - "github.com/smartcontractkit/chainlink-integrations/evm/client" "github.com/smartcontractkit/chainlink-integrations/evm/config" "github.com/smartcontractkit/chainlink-integrations/evm/config/toml" "github.com/smartcontractkit/chainlink-integrations/evm/gas" "github.com/smartcontractkit/chainlink-integrations/evm/gas/rollups" "github.com/smartcontractkit/chainlink-integrations/evm/heads" - "github.com/smartcontractkit/chainlink-integrations/evm/keystore" + "github.com/smartcontractkit/chainlink-integrations/evm/keys" "github.com/smartcontractkit/chainlink-integrations/evm/logpoller" "github.com/smartcontractkit/chainlink-integrations/evm/monitor" evmtypes "github.com/smartcontractkit/chainlink-integrations/evm/types" @@ -30,7 +30,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" - "github.com/smartcontractkit/chainlink/v2/core/logger" ) type Chain interface { @@ -112,7 +111,6 @@ type chain struct { logBroadcaster log.Broadcaster logPoller logpoller.LogPoller balanceMonitor monitor.BalanceMonitor - keyStore keystore.Eth gasEstimator gas.EvmFeeEstimator } @@ -130,7 +128,7 @@ type FeatureConfig interface { type ChainRelayOpts struct { Logger logger.Logger - KeyStore keystore.Eth + KeyStore keys.ChainStore ChainOpts } @@ -182,7 +180,7 @@ func (o ChainOpts) Validate() error { return err } -func NewTOMLChain(ctx context.Context, chain *toml.EVMConfig, opts ChainRelayOpts, clientsByChainID map[string]rollups.DAClient) (Chain, error) { +func NewTOMLChain(chain *toml.EVMConfig, opts ChainRelayOpts, clientsByChainID map[string]rollups.DAClient) (Chain, error) { err := opts.Validate() if err != nil { return nil, err @@ -193,10 +191,10 @@ func NewTOMLChain(ctx context.Context, chain *toml.EVMConfig, opts ChainRelayOpt } cfg := config.NewTOMLChainScopedConfig(chain) // note: per-chain validation is not necessary at this point since everything is checked earlier on boot. - return newChain(ctx, cfg, chain.Nodes, opts, clientsByChainID) + return newChain(cfg, chain.Nodes, opts, clientsByChainID) } -func newChain(ctx context.Context, cfg *config.ChainScoped, nodes []*toml.Node, opts ChainRelayOpts, clientsByChainID map[string]rollups.DAClient) (*chain, error) { +func newChain(cfg *config.ChainScoped, nodes []*toml.Node, opts ChainRelayOpts, clientsByChainID map[string]rollups.DAClient) (*chain, error) { chainID := cfg.EVM().ChainID() l := opts.Logger var cl client.Client @@ -272,12 +270,6 @@ func newChain(ctx context.Context, cfg *config.ChainScoped, nodes []*toml.Node, headBroadcaster.Subscribe(txm) - // Highest seen head height is used as part of the start of LogBroadcaster backfill range - highestSeenHead, err := headSaver.LatestHeadFromDB(ctx) - if err != nil { - return nil, err - } - var balanceMonitor monitor.BalanceMonitor if opts.ChainConfigs.RPCEnabled() && cfg.EVM().BalanceMonitor().Enabled() { balanceMonitor = monitor.NewBalanceMonitor(cl, opts.KeyStore, l) @@ -291,7 +283,7 @@ func newChain(ctx context.Context, cfg *config.ChainScoped, nodes []*toml.Node, logBroadcaster = &log.NullBroadcaster{ErrMsg: fmt.Sprintf("LogBroadcaster disabled for chain %d", chainID)} } else if opts.GenLogBroadcaster == nil { logORM := log.NewORM(opts.DS, *chainID) - logBroadcaster = log.NewBroadcaster(logORM, cl, cfg.EVM(), l, highestSeenHead, opts.MailMon) + logBroadcaster = log.NewBroadcaster(logORM, cl, cfg.EVM(), l, headSaver.LatestHeadFromDB, opts.MailMon) } else { logBroadcaster = opts.GenLogBroadcaster(chainID) } @@ -314,7 +306,6 @@ func newChain(ctx context.Context, cfg *config.ChainScoped, nodes []*toml.Node, logBroadcaster: logBroadcaster, logPoller: logPoller, balanceMonitor: balanceMonitor, - keyStore: opts.KeyStore, gasEstimator: gasEstimator, }, nil } diff --git a/core/chains/legacyevm/evm_txm.go b/core/chains/legacyevm/evm_txm.go index 70c42916e2c..35643939ca2 100644 --- a/core/chains/legacyevm/evm_txm.go +++ b/core/chains/legacyevm/evm_txm.go @@ -3,6 +3,7 @@ package legacyevm import ( "fmt" + "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/sqlutil" evmclient "github.com/smartcontractkit/chainlink-integrations/evm/client" @@ -13,7 +14,6 @@ import ( "github.com/smartcontractkit/chainlink-integrations/evm/logpoller" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" - "github.com/smartcontractkit/chainlink/v2/core/logger" ) func newEvmTxm( @@ -32,7 +32,7 @@ func newEvmTxm( ) { chainID := cfg.ChainID() - lggr = lggr.Named("Txm") + lggr = logger.Named(lggr, "Txm") lggr.Infow("Initializing EVM transaction manager", "bumpTxDepth", cfg.GasEstimator().BumpTxDepth(), "maxInFlightTransactions", cfg.Transactions().MaxInFlight(), @@ -88,7 +88,7 @@ func newGasEstimator( opts ChainRelayOpts, clientsByChainID map[string]rollups.DAClient, ) (estimator gas.EvmFeeEstimator, err error) { - lggr = lggr.Named("Txm") + lggr = logger.Named(lggr, "Txm") chainID := cfg.ChainID() // build estimator from factory if opts.GenGasEstimator == nil { diff --git a/core/chains/legacyevm/mocks/chain.go b/core/chains/legacyevm/mocks/chain.go index 32c5bf2482a..93e561678c7 100644 --- a/core/chains/legacyevm/mocks/chain.go +++ b/core/chains/legacyevm/mocks/chain.go @@ -20,7 +20,7 @@ import ( log "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log" - logger "github.com/smartcontractkit/chainlink/v2/core/logger" + logger "github.com/smartcontractkit/chainlink-common/pkg/logger" logpoller "github.com/smartcontractkit/chainlink-integrations/evm/logpoller" diff --git a/core/cmd/csa_keys_commands_test.go b/core/cmd/csa_keys_commands_test.go index 603e410e199..812e25a24b0 100644 --- a/core/cmd/csa_keys_commands_test.go +++ b/core/cmd/csa_keys_commands_test.go @@ -16,6 +16,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" + "github.com/smartcontractkit/chainlink/v2/core/services/keystore" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/csakey" "github.com/smartcontractkit/chainlink/v2/core/web/presenters" ) @@ -57,7 +58,7 @@ func TestShell_ListCSAKeys(t *testing.T) { ctx := testutils.Context(t) app := startNewApplicationV2(t, nil) - key, err := app.GetKeyStore().CSA().Create(ctx) + key, err := keystore.GetDefault(ctx, app.GetKeyStore().CSA()) require.NoError(t, err) requireCSAKeyCount(t, app, 1) @@ -76,9 +77,9 @@ func TestShell_CreateCSAKey(t *testing.T) { app := startNewApplicationV2(t, nil) client, _ := app.NewShellAndRenderer() - requireCSAKeyCount(t, app, 0) + requireCSAKeyCount(t, app, 1) - require.NoError(t, client.CreateCSAKey(nilContext)) + require.Error(t, client.CreateCSAKey(nilContext)) requireCSAKeyCount(t, app, 1) } @@ -92,7 +93,7 @@ func TestShell_ImportExportCsaKey(t *testing.T) { app := startNewApplicationV2(t, nil) client, _ := app.NewShellAndRenderer() - _, err := app.GetKeyStore().CSA().Create(ctx) + err := app.GetKeyStore().CSA().EnsureKey(ctx) require.NoError(t, err) keys := requireCSAKeyCount(t, app, 1) diff --git a/core/cmd/shell.go b/core/cmd/shell.go index 8061cabc229..db6769e60ea 100644 --- a/core/cmd/shell.go +++ b/core/cmd/shell.go @@ -36,11 +36,9 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/beholder" "github.com/smartcontractkit/chainlink-common/pkg/loop" "github.com/smartcontractkit/chainlink-common/pkg/sqlutil" - "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox" "github.com/smartcontractkit/chainlink/v2/core/build" "github.com/smartcontractkit/chainlink/v2/core/capabilities" - "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" "github.com/smartcontractkit/chainlink/v2/core/config" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/logger/audit" @@ -60,7 +58,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/utils" clhttp "github.com/smartcontractkit/chainlink/v2/core/utils/http" "github.com/smartcontractkit/chainlink/v2/core/web" - "github.com/smartcontractkit/chainlink/v2/plugins" ) var ( @@ -212,12 +209,7 @@ func (n ChainlinkAppFactory) NewApplication(ctx context.Context, cfg chainlink.G return nil, errors.Wrap(err, "error authenticating keystore") } - err = keyStore.CSA().EnsureKey(ctx) - if err != nil { - return nil, errors.Wrap(err, "failed to ensure CSA key") - } - - beholderAuthHeaders, csaPubKeyHex, err := keystore.BuildBeholderAuth(keyStore) + beholderAuthHeaders, csaPubKeyHex, err := keystore.BuildBeholderAuth(ctx, keyStore.CSA()) if err != nil { return nil, errors.Wrap(err, "failed to build Beholder auth") } @@ -227,75 +219,13 @@ func (n ChainlinkAppFactory) NewApplication(ctx context.Context, cfg chainlink.G appLggr.Errorf("Failed to initialize globals: %v", err) } - mailMon := mailbox.NewMonitor(cfg.AppID().String(), appLggr.Named("Mailbox")) - - loopRegistry := plugins.NewLoopRegistry(appLggr, cfg.Database(), cfg.Tracing(), cfg.Telemetry(), beholderAuthHeaders, csaPubKeyHex) - mercuryPool := wsrpc.NewPool(appLggr, cache.Config{ LatestReportTTL: cfg.Mercury().Cache().LatestReportTTL(), MaxStaleAge: cfg.Mercury().Cache().MaxStaleAge(), LatestReportDeadline: cfg.Mercury().Cache().LatestReportDeadline(), }) - capabilitiesRegistry := capabilities.NewRegistry(appLggr) - - retirementReportCache := llo.NewRetirementReportCache(appLggr, ds) - lloReaper := llo.NewTransmissionReaper(ds, appLggr, cfg.Mercury().Transmitter().ReaperFrequency().Duration(), cfg.Mercury().Transmitter().ReaperMaxAge().Duration()) - unrestrictedClient := clhttp.NewUnrestrictedHTTPClient() - // create the relayer-chain interoperators from application configuration - relayerFactory := chainlink.RelayerFactory{ - Logger: appLggr, - Registerer: appRegisterer, - LoopRegistry: loopRegistry, - GRPCOpts: grpcOpts, - MercuryPool: mercuryPool, - CapabilitiesRegistry: capabilitiesRegistry, - HTTPClient: unrestrictedClient, - RetirementReportCache: retirementReportCache, - } - - evmFactoryCfg := chainlink.EVMFactoryConfig{ - CSAETHKeystore: keyStore, - ChainOpts: legacyevm.ChainOpts{ - ChainConfigs: cfg.EVMConfigs(), - DatabaseConfig: cfg.Database(), - ListenerConfig: cfg.Database().Listener(), - FeatureConfig: cfg.Feature(), - MailMon: mailMon, - DS: ds, - }, - MercuryConfig: cfg.Mercury(), - } - // evm always enabled for backward compatibility - // TODO BCF-2510 this needs to change in order to clear the path for EVM extraction - initOps := []chainlink.CoreRelayerChainInitFunc{chainlink.InitDummy(ctx, relayerFactory), chainlink.InitEVM(ctx, relayerFactory, evmFactoryCfg)} - - if cfg.CosmosEnabled() { - initOps = append(initOps, chainlink.InitCosmos(ctx, relayerFactory, keyStore.Cosmos(), cfg.CosmosConfigs())) - } - if cfg.SolanaEnabled() { - solanaCfg := chainlink.SolanaFactoryConfig{ - Keystore: keyStore.Solana(), - TOMLConfigs: cfg.SolanaConfigs(), - DS: ds, - } - initOps = append(initOps, chainlink.InitSolana(ctx, relayerFactory, solanaCfg)) - } - if cfg.StarkNetEnabled() { - initOps = append(initOps, chainlink.InitStarknet(ctx, relayerFactory, keyStore.StarkNet(), cfg.StarknetConfigs())) - } - if cfg.AptosEnabled() { - initOps = append(initOps, chainlink.InitAptos(ctx, relayerFactory, keyStore.Aptos(), cfg.AptosConfigs())) - } - if cfg.TronEnabled() { - initOps = append(initOps, chainlink.InitTron(ctx, relayerFactory, keyStore.Tron(), cfg.TronConfigs())) - } - - relayChainInterops, err := chainlink.NewCoreRelayerChainInteroperators(initOps...) - if err != nil { - return nil, err - } // Configure and optionally start the audit log forwarder service auditLogger, err := audit.NewAuditLogger(appLggr, cfg.AuditLogger()) @@ -303,31 +233,25 @@ func (n ChainlinkAppFactory) NewApplication(ctx context.Context, cfg chainlink.G return nil, err } - restrictedClient := clhttp.NewRestrictedHTTPClient(cfg.Database(), appLggr) - externalInitiatorManager := webhook.NewExternalInitiatorManager(ds, unrestrictedClient) - creOpts := chainlink.CREOpts{ - CapabilitiesRegistry: capabilitiesRegistry, - } - return chainlink.NewApplication(chainlink.ApplicationOpts{ - CREOpts: creOpts, - - Config: cfg, - DS: ds, - KeyStore: keyStore, - RelayerChainInteroperators: relayChainInterops, - MailMon: mailMon, - Logger: appLggr, - AuditLogger: auditLogger, - ExternalInitiatorManager: externalInitiatorManager, - Version: static.Version, - RestrictedHTTPClient: restrictedClient, - UnrestrictedHTTPClient: unrestrictedClient, - SecretGenerator: chainlink.FilePersistedSecretGenerator{}, - LoopRegistry: loopRegistry, - GRPCOpts: grpcOpts, - MercuryPool: mercuryPool, - RetirementReportCache: retirementReportCache, - LLOTransmissionReaper: lloReaper, + return chainlink.NewApplication(ctx, chainlink.ApplicationOpts{ + CREOpts: chainlink.CREOpts{ + CapabilitiesRegistry: capabilities.NewRegistry(appLggr), + }, + Config: cfg, + DS: ds, + KeyStore: keyStore, + Logger: appLggr, + Registerer: appRegisterer, + AuditLogger: auditLogger, + ExternalInitiatorManager: webhook.NewExternalInitiatorManager(ds, unrestrictedClient), + Version: static.Version, + RestrictedHTTPClient: clhttp.NewRestrictedHTTPClient(cfg.Database(), appLggr), + UnrestrictedHTTPClient: unrestrictedClient, + SecretGenerator: chainlink.FilePersistedSecretGenerator{}, + GRPCOpts: grpcOpts, + MercuryPool: mercuryPool, + RetirementReportCache: llo.NewRetirementReportCache(appLggr, ds), + LLOTransmissionReaper: llo.NewTransmissionReaper(ds, appLggr, cfg.Mercury().Transmitter().ReaperFrequency().Duration(), cfg.Mercury().Transmitter().ReaperMaxAge().Duration()), }) } diff --git a/core/cmd/shell_local.go b/core/cmd/shell_local.go index 40b606da77d..db8c6ffd0be 100644 --- a/core/cmd/shell_local.go +++ b/core/cmd/shell_local.go @@ -25,6 +25,7 @@ import ( "github.com/smartcontractkit/chainlink-integrations/evm/assets" "github.com/smartcontractkit/chainlink-integrations/evm/gas" + "github.com/smartcontractkit/chainlink-integrations/evm/keys" evmtypes "github.com/smartcontractkit/chainlink-integrations/evm/types" "github.com/smartcontractkit/chainlink/v2/core/build" @@ -700,14 +701,16 @@ func (s *Shell) RebroadcastTransactions(c *cli.Context) (err error) { return s.errorOut(err) } + ks := keys.NewChainStore(keystore.NewEthSigner(keyStore.Eth(), chain.ID()), chain.ID()) + s.Logger.Infof("Rebroadcasting transactions from %v to %v", beginningNonce, endingNonce) orm := txmgr.NewTxStore(app.GetDB(), lggr) - txBuilder := txmgr.NewEvmTxAttemptBuilder(*ethClient.ConfiguredChainID(), chain.Config().EVM().GasEstimator(), keyStore.Eth(), nil) + txBuilder := txmgr.NewEvmTxAttemptBuilder(*ethClient.ConfiguredChainID(), chain.Config().EVM().GasEstimator(), ks, nil) feeCfg := txmgr.NewEvmTxmFeeConfig(chain.Config().EVM().GasEstimator()) stuckTxDetector := txmgr.NewStuckTxDetector(lggr, ethClient.ConfiguredChainID(), "", assets.NewWei(assets.NewEth(100).ToInt()), chain.Config().EVM().Transactions().AutoPurge(), nil, orm, ethClient) ec := txmgr.NewEvmConfirmer(orm, txmgr.NewEvmTxmClient(ethClient, chain.Config().EVM().NodePool().Errors()), - feeCfg, chain.Config().EVM().Transactions(), app.GetConfig().Database(), keyStore.Eth(), txBuilder, chain.Logger(), stuckTxDetector, chain.HeadTracker()) + feeCfg, chain.Config().EVM().Transactions(), app.GetConfig().Database(), ks, txBuilder, chain.Logger(), stuckTxDetector) totalNonces := endingNonce - beginningNonce + 1 nonces := make([]evmtypes.Nonce, totalNonces) for i := int64(0); i < totalNonces; i++ { diff --git a/core/cmd/shell_local_test.go b/core/cmd/shell_local_test.go index 85aa9a9b430..f28ac067832 100644 --- a/core/cmd/shell_local_test.go +++ b/core/cmd/shell_local_test.go @@ -16,13 +16,17 @@ import ( "github.com/stretchr/testify/require" "github.com/urfave/cli" + "github.com/smartcontractkit/chainlink-common/pkg/types/core" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink-common/pkg/sqlutil" pgcommon "github.com/smartcontractkit/chainlink-common/pkg/sqlutil/pg" "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox" "github.com/smartcontractkit/chainlink-framework/multinode" + "github.com/smartcontractkit/chainlink/v2/core/services/keystore" "github.com/smartcontractkit/chainlink-integrations/evm/client/clienttest" + "github.com/smartcontractkit/chainlink/v2/core/capabilities" "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" "github.com/smartcontractkit/chainlink/v2/core/cmd" @@ -37,7 +41,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/logger/audit" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" chainlinkmocks "github.com/smartcontractkit/chainlink/v2/core/services/chainlink/mocks" - evmrelayer "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm" "github.com/smartcontractkit/chainlink/v2/core/sessions/localauth" "github.com/smartcontractkit/chainlink/v2/core/store/models" "github.com/smartcontractkit/chainlink/v2/core/utils" @@ -45,7 +48,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/plugins" ) -func genTestEVMRelayers(t *testing.T, cfg chainlink.GeneralConfig, ds sqlutil.DataSource, ks evmrelayer.CSAETHKeystore) *chainlink.CoreRelayerChainInteroperators { +func genTestEVMRelayers(t *testing.T, cfg chainlink.GeneralConfig, ds sqlutil.DataSource, ethKeystore keystore.Eth, csaKeystore core.Keystore) *chainlink.CoreRelayerChainInteroperators { lggr := logger.TestLogger(t) f := chainlink.RelayerFactory{ Logger: lggr, @@ -53,7 +56,7 @@ func genTestEVMRelayers(t *testing.T, cfg chainlink.GeneralConfig, ds sqlutil.Da CapabilitiesRegistry: capabilities.NewRegistry(lggr), } - relayers, err := chainlink.NewCoreRelayerChainInteroperators(chainlink.InitEVM(testutils.Context(t), f, chainlink.EVMFactoryConfig{ + relayers, err := chainlink.NewCoreRelayerChainInteroperators(chainlink.InitEVM(f, chainlink.EVMFactoryConfig{ ChainOpts: legacyevm.ChainOpts{ ChainConfigs: cfg.EVMConfigs(), DatabaseConfig: cfg.Database(), @@ -62,7 +65,8 @@ func genTestEVMRelayers(t *testing.T, cfg chainlink.GeneralConfig, ds sqlutil.Da MailMon: &mailbox.Monitor{}, DS: ds, }, - CSAETHKeystore: ks, + EthKeystore: ethKeystore, + CSAKeystore: csaKeystore, })) if err != nil { t.Fatal(err) @@ -95,7 +99,7 @@ func TestShell_RunNodeWithPasswords(t *testing.T) { keyStore := cltest.NewKeyStore(t, db) authProviderORM := localauth.NewORM(db, time.Minute, logger.TestLogger(t), audit.NoopLogger) - testRelayers := genTestEVMRelayers(t, cfg, db, keyStore) + testRelayers := genTestEVMRelayers(t, cfg, db, keyStore.Eth(), &keystore.CSASigner{CSA: keyStore.CSA()}) // Purge the fixture users to test assumption of single admin // initialUser user created above @@ -189,7 +193,7 @@ func TestShell_RunNodeWithAPICredentialsFile(t *testing.T) { ethClient.On("Dial", mock.Anything).Return(nil).Maybe() ethClient.On("BalanceAt", mock.Anything, mock.Anything, mock.Anything).Return(big.NewInt(10), nil).Maybe() - testRelayers := genTestEVMRelayers(t, cfg, db, keyStore) + testRelayers := genTestEVMRelayers(t, cfg, db, keyStore.Eth(), &keystore.CSASigner{CSA: keyStore.CSA()}) app := mocks.NewApplication(t) app.On("BasicAdminUsersORM").Return(authProviderORM) app.On("GetKeyStore").Return(keyStore) diff --git a/core/cmd/shell_test.go b/core/cmd/shell_test.go index 7ba15af3dd7..ae1393d6fe5 100644 --- a/core/cmd/shell_test.go +++ b/core/cmd/shell_test.go @@ -28,6 +28,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/logger/audit" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" + "github.com/smartcontractkit/chainlink/v2/core/services/keystore" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/mocks" "github.com/smartcontractkit/chainlink/v2/core/sessions" "github.com/smartcontractkit/chainlink/v2/core/sessions/localauth" @@ -352,7 +353,7 @@ func TestNewUserCache(t *testing.T) { func TestSetupSolanaRelayer(t *testing.T) { lggr := logger.TestLogger(t) reg := plugins.NewTestLoopRegistry(lggr) - ks := mocks.NewSolana(t) + ks := &keystore.StarknetLooppSigner{StarkNet: mocks.NewStarkNet(t)} ds := sqltest.NewNoOpDataSource() // config 3 chains but only enable 2 => should only be 2 relayer @@ -397,13 +398,12 @@ func TestSetupSolanaRelayer(t *testing.T) { } cfg := chainlink.SolanaFactoryConfig{ - Keystore: ks, TOMLConfigs: tConfig.SolanaConfigs(), DS: ds} // not parallel; shared state t.Run("no plugin", func(t *testing.T) { - relayers, err := rf.NewSolana(cfg) + relayers, err := rf.NewSolana(ks, cfg) require.NoError(t, err) require.NotNil(t, relayers) require.Len(t, relayers, nEnabledChains) @@ -414,7 +414,7 @@ func TestSetupSolanaRelayer(t *testing.T) { t.Run("plugin", func(t *testing.T) { t.Setenv("CL_SOLANA_CMD", "phony_solana_cmd") - relayers, err := rf.NewSolana(cfg) + relayers, err := rf.NewSolana(ks, cfg) require.NoError(t, err) require.NotNil(t, relayers) require.Len(t, relayers, nEnabledChains) @@ -440,20 +440,19 @@ func TestSetupSolanaRelayer(t *testing.T) { } }) dupCfg := chainlink.SolanaFactoryConfig{ - Keystore: ks, TOMLConfigs: duplicateConfig.SolanaConfigs(), DS: ds, } // not parallel; shared state t.Run("no plugin, duplicate chains", func(t *testing.T) { - _, err := rf.NewSolana(dupCfg) + _, err := rf.NewSolana(ks, dupCfg) require.Error(t, err) }) t.Run("plugin, duplicate chains", func(t *testing.T) { t.Setenv("CL_SOLANA_CMD", "phony_solana_cmd") - _, err := rf.NewSolana(dupCfg) + _, err := rf.NewSolana(ks, dupCfg) require.Error(t, err) }) @@ -461,8 +460,7 @@ func TestSetupSolanaRelayer(t *testing.T) { t.Setenv("CL_SOLANA_CMD", "phony_solana_cmd") t.Setenv("CL_SOLANA_ENV", "fake_path") - _, err := rf.NewSolana(chainlink.SolanaFactoryConfig{ - Keystore: ks, + _, err := rf.NewSolana(ks, chainlink.SolanaFactoryConfig{ TOMLConfigs: t2Config.SolanaConfigs(), DS: ds, }) @@ -473,7 +471,7 @@ func TestSetupSolanaRelayer(t *testing.T) { t.Run("plugin already registered", func(t *testing.T) { t.Setenv("CL_SOLANA_CMD", "phony_solana_cmd") - _, err := rf.NewSolana(cfg) + _, err := rf.NewSolana(ks, cfg) require.Error(t, err) require.Contains(t, err.Error(), "failed to create Solana LOOP command") }) @@ -482,7 +480,7 @@ func TestSetupSolanaRelayer(t *testing.T) { func TestSetupStarkNetRelayer(t *testing.T) { lggr := logger.TestLogger(t) reg := plugins.NewTestLoopRegistry(lggr) - ks := mocks.NewStarkNet(t) + ks := &keystore.StarknetLooppSigner{StarkNet: mocks.NewStarkNet(t)} // config 3 chains but only enable 2 => should only be 2 relayer nEnabledChains := 2 tConfig := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { diff --git a/core/internal/cltest/cltest.go b/core/internal/cltest/cltest.go index 4c24c7712ed..200b9f3b1fa 100644 --- a/core/internal/cltest/cltest.go +++ b/core/internal/cltest/cltest.go @@ -40,9 +40,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/capabilities/compute" "github.com/smartcontractkit/chainlink/v2/core/services/workflows/syncer" - "github.com/smartcontractkit/chainlink-common/pkg/loop" "github.com/smartcontractkit/chainlink-common/pkg/sqlutil" - "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox" "github.com/smartcontractkit/chainlink-common/pkg/utils/tests" "github.com/smartcontractkit/chainlink-framework/multinode" @@ -97,7 +95,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/web" webauth "github.com/smartcontractkit/chainlink/v2/core/web/auth" webpresenters "github.com/smartcontractkit/chainlink/v2/core/web/presenters" - "github.com/smartcontractkit/chainlink/v2/plugins" // Force import of pgtest to ensure that txdb is registered as a DB driver _ "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" @@ -277,25 +274,6 @@ func NewApplicationWithConfigAndKey(t testing.TB, c chainlink.GeneralConfig, fla return app } -func setKeys(t testing.TB, app *TestApplication, flagsAndDeps ...interface{}) (chainID ubig.Big) { - ctx := testutils.Context(t) - - for _, dep := range flagsAndDeps { - switch v := dep.(type) { - case ethkey.KeyV2: - app.Keys = append(app.Keys, v) - case p2pkey.KeyV2: - require.NoError(t, app.GetKeyStore().P2P().Add(ctx, v)) - case csakey.KeyV2: - require.NoError(t, app.GetKeyStore().CSA().Add(ctx, v)) - case ocr2key.KeyBundle: - require.NoError(t, app.GetKeyStore().OCR2().Add(ctx, v)) - } - } - - return -} - const ( UseRealExternalInitiatorManager = "UseRealExternalInitiatorManager" ) @@ -409,12 +387,6 @@ func NewApplicationWithConfig(t testing.TB, cfg chainlink.GeneralConfig, flagsAn } } - keyStore := keystore.NewInMemory(ds, utils.FastScryptParams, lggr) - require.NoError(t, keyStore.Unlock(ctx, Password)) - - mailMon := mailbox.NewMonitor(cfg.AppID().String(), lggr.Named("Mailbox")) - loopRegistry := plugins.NewLoopRegistry(lggr, cfg.Database(), cfg.Tracing(), cfg.Telemetry(), nil, "") - mercuryPool := wsrpc.NewPool(lggr, cache.Config{ LatestReportTTL: cfg.Mercury().Cache().LatestReportTTL(), MaxStaleAge: cfg.Mercury().Cache().MaxStaleAge(), @@ -422,98 +394,62 @@ func NewApplicationWithConfig(t testing.TB, cfg chainlink.GeneralConfig, flagsAn }) c := clhttptest.NewTestLocalOnlyHTTPClient() - retirementReportCache := llo.NewRetirementReportCache(lggr, ds) - relayerFactory := chainlink.RelayerFactory{ - Logger: lggr, - LoopRegistry: loopRegistry, - GRPCOpts: loop.GRPCOpts{}, - Registerer: prometheus.NewRegistry(), // Don't use global registry here since otherwise multiple apps can create name conflicts. Could also potentially give a mock registry to test prometheus. - MercuryPool: mercuryPool, - CapabilitiesRegistry: capabilitiesRegistry, - HTTPClient: c, - RetirementReportCache: retirementReportCache, - } - - evmOpts := chainlink.EVMFactoryConfig{ - ChainOpts: legacyevm.ChainOpts{ - ChainConfigs: cfg.EVMConfigs(), - DatabaseConfig: cfg.Database(), - ListenerConfig: cfg.Database().Listener(), - FeatureConfig: cfg.Feature(), - MailMon: mailMon, - DS: ds, - }, - CSAETHKeystore: keyStore, - MercuryConfig: cfg.Mercury(), - } + var evmFactoryConfigFn func(config *chainlink.EVMFactoryConfig) if cfg.EVMEnabled() { if ethClient == nil { ethClient = evmclient.NewNullClient(evmtest.MustGetDefaultChainID(t, cfg.EVMConfigs()), lggr) } chainId := ethClient.ConfiguredChainID() - evmOpts.GenEthClient = func(_ *big.Int) evmclient.Client { - if chainId.Cmp(evmtest.MustGetDefaultChainID(t, cfg.EVMConfigs())) != 0 { - t.Fatalf("expected eth client ChainID %d to match evm config chain id %d", chainId, evmtest.MustGetDefaultChainID(t, cfg.EVMConfigs())) + evmFactoryConfigFn = func(fc *chainlink.EVMFactoryConfig) { + fc.GenEthClient = func(_ *big.Int) evmclient.Client { + if chainId.Cmp(evmtest.MustGetDefaultChainID(t, cfg.EVMConfigs())) != 0 { + t.Fatalf("expected eth client ChainID %d to match evm config chain id %d", chainId, evmtest.MustGetDefaultChainID(t, cfg.EVMConfigs())) + } + return ethClient } - return ethClient } } + keyStore := keystore.NewInMemory(ds, utils.FastScryptParams, lggr) + require.NoError(t, keyStore.Unlock(ctx, Password)) - // evm alway enabled for backward compatibility - initOps := []chainlink.CoreRelayerChainInitFunc{chainlink.InitDummy(ctx, relayerFactory), chainlink.InitEVM(ctx, relayerFactory, evmOpts)} - - if cfg.CosmosEnabled() { - initOps = append(initOps, chainlink.InitCosmos(ctx, relayerFactory, keyStore.Cosmos(), cfg.CosmosConfigs())) - } - if cfg.SolanaEnabled() { - solanaCfg := chainlink.SolanaFactoryConfig{ - Keystore: keyStore.Solana(), - TOMLConfigs: cfg.SolanaConfigs(), - DS: ds, + for _, dep := range flagsAndDeps { + switch v := dep.(type) { + case p2pkey.KeyV2: + require.NoError(t, keyStore.P2P().Add(ctx, v)) + case csakey.KeyV2: + require.NoError(t, keyStore.CSA().Add(ctx, v)) + case ocr2key.KeyBundle: + require.NoError(t, keyStore.OCR2().Add(ctx, v)) } - initOps = append(initOps, chainlink.InitSolana(ctx, relayerFactory, solanaCfg)) - } - if cfg.StarkNetEnabled() { - initOps = append(initOps, chainlink.InitStarknet(ctx, relayerFactory, keyStore.StarkNet(), cfg.StarknetConfigs())) - } - if cfg.AptosEnabled() { - initOps = append(initOps, chainlink.InitAptos(ctx, relayerFactory, keyStore.Aptos(), cfg.AptosConfigs())) - } - if cfg.TronEnabled() { - initOps = append(initOps, chainlink.InitTron(ctx, relayerFactory, keyStore.Tron(), cfg.TronConfigs())) } - relayChainInterops, err := chainlink.NewCoreRelayerChainInteroperators(initOps...) - if err != nil { - t.Fatal(err) - } - creOpts := chainlink.CREOpts{ - CapabilitiesRegistry: capabilitiesRegistry, - CapabilitiesDispatcher: dispatcher, - CapabilitiesPeerWrapper: peerWrapper, - FetcherFunc: syncerFetcherFunc, - FetcherFactoryFn: computeFetcherFactory, - } - appInstance, err := chainlink.NewApplication(chainlink.ApplicationOpts{ - CREOpts: creOpts, - Config: cfg, - MailMon: mailMon, - DS: ds, - KeyStore: keyStore, - RelayerChainInteroperators: relayChainInterops, - Logger: lggr, - AuditLogger: auditLogger, - CloseLogger: lggr.Sync, - ExternalInitiatorManager: externalInitiatorManager, - RestrictedHTTPClient: c, - UnrestrictedHTTPClient: c, - SecretGenerator: MockSecretGenerator{}, - LoopRegistry: plugins.NewTestLoopRegistry(lggr), - MercuryPool: mercuryPool, - NewOracleFactoryFn: newOracleFactoryFn, - RetirementReportCache: retirementReportCache, - LLOTransmissionReaper: llo.NewTransmissionReaper(ds, lggr, cfg.Mercury().Transmitter().ReaperFrequency().Duration(), cfg.Mercury().Transmitter().ReaperMaxAge().Duration()), + appInstance, err := chainlink.NewApplication(ctx, chainlink.ApplicationOpts{ + CREOpts: chainlink.CREOpts{ + CapabilitiesRegistry: capabilitiesRegistry, + CapabilitiesDispatcher: dispatcher, + CapabilitiesPeerWrapper: peerWrapper, + FetcherFunc: syncerFetcherFunc, + FetcherFactoryFn: computeFetcherFactory, + }, + Config: cfg, + DS: ds, + KeyStore: keyStore, + Logger: lggr, + // Don't use global registry here since otherwise multiple apps can create name conflicts. + // Could also potentially give a mock registry to test prometheus. + Registerer: prometheus.NewRegistry(), + AuditLogger: auditLogger, + CloseLogger: lggr.Sync, + ExternalInitiatorManager: externalInitiatorManager, + RestrictedHTTPClient: c, + UnrestrictedHTTPClient: c, + SecretGenerator: MockSecretGenerator{}, + MercuryPool: mercuryPool, + NewOracleFactoryFn: newOracleFactoryFn, + RetirementReportCache: llo.NewRetirementReportCache(lggr, ds), + LLOTransmissionReaper: llo.NewTransmissionReaper(ds, lggr, cfg.Mercury().Transmitter().ReaperFrequency().Duration(), cfg.Mercury().Transmitter().ReaperMaxAge().Duration()), + EVMFactoryConfigFn: evmFactoryConfigFn, }) require.NoError(t, err) @@ -523,6 +459,12 @@ func NewApplicationWithConfig(t testing.TB, cfg chainlink.GeneralConfig, flagsAn ChainlinkApplication: app, Logger: lggr, } + for _, dep := range flagsAndDeps { + switch v := dep.(type) { + case ethkey.KeyV2: + ta.Keys = append(ta.Keys, v) + } + } srvr := httptest.NewUnstartedServer(web.Router(t, app, nil)) srvr.Config.WriteTimeout = cfg.WebServer().HTTPWriteTimeout() @@ -533,8 +475,6 @@ func NewApplicationWithConfig(t testing.TB, cfg chainlink.GeneralConfig, flagsAn app.ExternalInitiatorManager = externalInitiatorManager } - setKeys(t, ta, flagsAndDeps...) - return ta } diff --git a/core/internal/features/features_test.go b/core/internal/features/features_test.go index 810f705bbfd..d3983d25f54 100644 --- a/core/internal/features/features_test.go +++ b/core/internal/features/features_test.go @@ -1285,13 +1285,13 @@ func TestIntegration_BlockHistoryEstimator(t *testing.T) { kst := cltest.NewKeyStore(t, db) require.NoError(t, kst.Unlock(ctx, cltest.Password)) - chainsAndConfig := evmtest.NewLegacyChainsAndConfig(t, evmtest.TestChainOpts{ + legacyChains := evmtest.NewLegacyChains(t, evmtest.TestChainOpts{ ChainConfigs: cfg.EVMConfigs(), DatabaseConfig: cfg.Database(), FeatureConfig: cfg.Feature(), ListenerConfig: cfg.Database().Listener(), - DB: db, KeyStore: kst.Eth(), + DB: db, Client: ethClient, }) @@ -1349,7 +1349,7 @@ func TestIntegration_BlockHistoryEstimator(t *testing.T) { ethClient.On("HeadByHash", mock.Anything, h41.Hash).Return(&h41, nil).Maybe() ethClient.On("HeadByHash", mock.Anything, h42.Hash).Return(&h42, nil).Maybe() - for _, re := range chainsAndConfig.Slice() { + for _, re := range legacyChains.Slice() { servicetest.Run(t, re) } var newHeads evmtestutils.RawSub[*types.Head] @@ -1359,7 +1359,6 @@ func TestIntegration_BlockHistoryEstimator(t *testing.T) { t.Fatal("timed out waiting for app to subscribe") } - legacyChains := chainsAndConfig.NewLegacyChains() chain := evmtest.MustGetDefaultChain(t, legacyChains) estimator := chain.GasEstimator() gasPrice, gasLimit, err := estimator.GetFee(testutils.Context(t), nil, 500_000, maxGasPrice, nil, nil) diff --git a/core/internal/features/ocr2/features_ocr2_helper.go b/core/internal/features/ocr2/features_ocr2_helper.go index 4343ed61ede..82d09c9c7cb 100644 --- a/core/internal/features/ocr2/features_ocr2_helper.go +++ b/core/internal/features/ocr2/features_ocr2_helper.go @@ -34,6 +34,8 @@ import ( ocrtypes2 "github.com/smartcontractkit/libocr/offchainreporting2plus/types" commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" + "github.com/smartcontractkit/chainlink-integrations/evm/keys" + "github.com/smartcontractkit/chainlink/v2/core/services/keystore" "github.com/smartcontractkit/chainlink-integrations/evm/assets" evmtestutils "github.com/smartcontractkit/chainlink-integrations/evm/testutils" @@ -610,7 +612,8 @@ updateInterval = "1m" contractABI, err2 := abi.JSON(strings.NewReader(ocr2aggregator.OCR2AggregatorABI)) require.NoError(t, err2) apps[0].GetRelayers().LegacyEVMChains().Slice() - ct, err2 := evm.NewOCRContractTransmitter(testutils.Context(t), ocrContractAddress, apps[0].GetRelayers().LegacyEVMChains().Slice()[0].Client(), contractABI, nil, apps[0].GetRelayers().LegacyEVMChains().Slice()[0].LogPoller(), lggr, apps[0].KeyStore.Eth()) + store := keys.NewStore(keystore.NewEthSigner(apps[0].KeyStore.Eth(), testutils.SimulatedChainID)) + ct, err2 := evm.NewOCRContractTransmitter(testutils.Context(t), ocrContractAddress, apps[0].GetRelayers().LegacyEVMChains().Slice()[0].Client(), contractABI, nil, apps[0].GetRelayers().LegacyEVMChains().Slice()[0].LogPoller(), lggr, store) require.NoError(t, err2) configDigest, epoch, err2 := ct.LatestConfigDigestAndEpoch(testutils.Context(t)) require.NoError(t, err2) diff --git a/core/internal/features/ocr2/features_ocr2_test.go b/core/internal/features/ocr2/features_ocr2_test.go index 6578a4a9aff..7512565d1f1 100644 --- a/core/internal/features/ocr2/features_ocr2_test.go +++ b/core/internal/features/ocr2/features_ocr2_test.go @@ -27,10 +27,12 @@ import ( confighelper2 "github.com/smartcontractkit/libocr/offchainreporting2plus/confighelper" ocrtypes2 "github.com/smartcontractkit/libocr/offchainreporting2plus/types" + "github.com/smartcontractkit/chainlink-integrations/evm/keys" "github.com/smartcontractkit/chainlink/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/logger" + "github.com/smartcontractkit/chainlink/v2/core/services/keystore" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ocr2key" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/validate" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm" @@ -264,7 +266,8 @@ updateInterval = "1m" // Assert we can read the latest config digest and epoch after a report has been submitted. contractABI, err := abi.JSON(strings.NewReader(ocr2aggregator.OCR2AggregatorABI)) require.NoError(t, err) - ct, err := evm.NewOCRContractTransmitter(testutils.Context(t), ocrContractAddress, apps[0].GetRelayers().LegacyEVMChains().Slice()[0].Client(), contractABI, nil, apps[0].GetRelayers().LegacyEVMChains().Slice()[0].LogPoller(), lggr, apps[0].KeyStore.Eth()) + store := keys.NewStore(keystore.NewEthSigner(apps[0].KeyStore.Eth(), testutils.SimulatedChainID)) + ct, err := evm.NewOCRContractTransmitter(testutils.Context(t), ocrContractAddress, apps[0].GetRelayers().LegacyEVMChains().Slice()[0].Client(), contractABI, nil, apps[0].GetRelayers().LegacyEVMChains().Slice()[0].LogPoller(), lggr, store) require.NoError(t, err) configDigest, epoch, err := ct.LatestConfigDigestAndEpoch(testutils.Context(t)) require.NoError(t, err) diff --git a/core/internal/testutils/evmtest/evmtest.go b/core/internal/testutils/evmtest/evmtest.go index 180f9bd6fe4..dcd0e244866 100644 --- a/core/internal/testutils/evmtest/evmtest.go +++ b/core/internal/testutils/evmtest/evmtest.go @@ -16,6 +16,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/types" "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox" "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox/mailboxtest" + "github.com/smartcontractkit/chainlink/v2/core/services/keystore" evmclient "github.com/smartcontractkit/chainlink-integrations/evm/client" "github.com/smartcontractkit/chainlink-integrations/evm/client/clienttest" @@ -33,7 +34,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore" evmrelay "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm" ) @@ -68,37 +68,26 @@ type TestChainOpts struct { GasEstimator gas.EvmFeeEstimator } -// NewLegacyChainsAndConfig returns a simple chain collection with one chain and +// NewLegacyChains returns a simple chain collection with one chain and // allows to mock client/config on that chain -func NewLegacyChainsAndConfig(t testing.TB, testopts TestChainOpts) *evmrelay.LegacyChainsAndConfig { - opts := NewChainOpts(t, testopts) - cc, err := evmrelay.NewLegacyChainsAndConfig(testutils.Context(t), opts) - require.NoError(t, err) - return cc -} - func NewLegacyChains(t testing.TB, testopts TestChainOpts) *legacyevm.LegacyChains { - opts := NewChainOpts(t, testopts) - cc, err := evmrelay.NewLegacyChainsAndConfig(testutils.Context(t), opts) + lggr, ks, opts := NewChainOpts(t, testopts) + cc, err := evmrelay.NewLegacyChainsAndConfig(lggr, ks, opts) require.NoError(t, err) return cc.NewLegacyChains() } -func NewChainOpts(t testing.TB, testopts TestChainOpts) legacyevm.ChainRelayOpts { +func NewChainOpts(t testing.TB, testopts TestChainOpts) (logger.Logger, keystore.Eth, legacyevm.ChainOpts) { require.NotNil(t, testopts.KeyStore) lggr := logger.TestLogger(t) - opts := legacyevm.ChainRelayOpts{ - Logger: lggr, - KeyStore: testopts.KeyStore, - ChainOpts: legacyevm.ChainOpts{ - ChainConfigs: testopts.ChainConfigs, - DatabaseConfig: testopts.DatabaseConfig, - ListenerConfig: testopts.ListenerConfig, - FeatureConfig: testopts.FeatureConfig, - MailMon: testopts.MailMon, - GasEstimator: testopts.GasEstimator, - DS: testopts.DB, - }, + opts := legacyevm.ChainOpts{ + ChainConfigs: testopts.ChainConfigs, + DatabaseConfig: testopts.DatabaseConfig, + ListenerConfig: testopts.ListenerConfig, + FeatureConfig: testopts.FeatureConfig, + MailMon: testopts.MailMon, + GasEstimator: testopts.GasEstimator, + DS: testopts.DB, } opts.GenEthClient = func(*big.Int) evmclient.Client { if testopts.Client != nil { @@ -135,7 +124,7 @@ func NewChainOpts(t testing.TB, testopts TestChainOpts) legacyevm.ChainRelayOpts } } - return opts + return lggr, testopts.KeyStore, opts } // Deprecated, this is a replacement function for tests for now removed default evmChainID logic diff --git a/core/scripts/go.mod b/core/scripts/go.mod index 79c5af96e02..2b74107845d 100644 --- a/core/scripts/go.mod +++ b/core/scripts/go.mod @@ -32,9 +32,9 @@ require ( github.com/prometheus/client_golang v1.21.0 github.com/shopspring/decimal v1.4.0 github.com/smartcontractkit/chainlink-automation v0.8.1 - github.com/smartcontractkit/chainlink-common v0.4.2-0.20250310180230-58f4a9810e21 + github.com/smartcontractkit/chainlink-common v0.4.2-0.20250311155151-6b258d69b8a4 github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20250228145850-f846693a6fd5 - github.com/smartcontractkit/chainlink-integrations/evm v0.0.0-20250304212534-9eff2fa32bea + github.com/smartcontractkit/chainlink-integrations/evm v0.0.0-20250311123343-5a841c234992 github.com/smartcontractkit/chainlink-testing-framework/lib v1.50.22 github.com/smartcontractkit/libocr v0.0.0-20250220133800-f3b940c4f298 github.com/spf13/cobra v1.8.1 @@ -345,7 +345,7 @@ require ( github.com/smartcontractkit/chainlink-ccip v0.0.0-20250307145254-e603dcbe3db1 // indirect github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20250307105933-7912a5e97ad0 // indirect github.com/smartcontractkit/chainlink-feeds v0.1.2-0.20250227211209-7cd000095135 // indirect - github.com/smartcontractkit/chainlink-framework/chains v0.0.0-20250227163723-3c71fefea680 // indirect + github.com/smartcontractkit/chainlink-framework/chains v0.0.0-20250311143712-d83af6d2a580 // indirect github.com/smartcontractkit/chainlink-framework/multinode v0.0.0-20250211162441-3d6cea220efb // indirect github.com/smartcontractkit/chainlink-protos/job-distributor v0.9.0 // indirect github.com/smartcontractkit/chainlink-protos/orchestrator v0.5.0 // indirect @@ -357,7 +357,7 @@ require ( github.com/smartcontractkit/mcms v0.13.0 // indirect github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20241009055228-33d0c0bf38de // indirect github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20241009055228-33d0c0bf38de // indirect - github.com/smartcontractkit/wsrpc v0.8.3 // indirect + github.com/smartcontractkit/wsrpc v0.8.5-0.20250310183704-ea183816e1d1 // indirect github.com/sourcegraph/conc v0.3.0 // indirect github.com/spf13/afero v1.12.0 // indirect github.com/spf13/cast v1.7.1 // indirect diff --git a/core/scripts/go.sum b/core/scripts/go.sum index bc601e95760..fd9a4c0f428 100644 --- a/core/scripts/go.sum +++ b/core/scripts/go.sum @@ -1122,18 +1122,18 @@ github.com/smartcontractkit/chainlink-ccip v0.0.0-20250307145254-e603dcbe3db1 h1 github.com/smartcontractkit/chainlink-ccip v0.0.0-20250307145254-e603dcbe3db1/go.mod h1:AhqYIeGF2k94J+/gzRx5dQttlgUdZid2N6E4HlHVIVA= github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20250307105933-7912a5e97ad0 h1:q19ElpBhjcA8yklJnHnNA04P9W3R7X+J2NTc1ZJvN4Q= github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20250307105933-7912a5e97ad0/go.mod h1:2Y6JRpvj9EkgKgymvenuqCnra07+NYVB6+0rQGETSGA= -github.com/smartcontractkit/chainlink-common v0.4.2-0.20250310180230-58f4a9810e21 h1:Z+IZ7znVnD2idSmZAT72ilj13rKYLxVt4GVBOCNOPUc= -github.com/smartcontractkit/chainlink-common v0.4.2-0.20250310180230-58f4a9810e21/go.mod h1:YQuXIqQpmpAqstWV0LHaDTJ5nsSWuip5ivEM+Fisb+4= +github.com/smartcontractkit/chainlink-common v0.4.2-0.20250311155151-6b258d69b8a4 h1:1pdgg/h8tYlE8oPP8LIaX5n9bioEzBK5vbAnSqeQAbU= +github.com/smartcontractkit/chainlink-common v0.4.2-0.20250311155151-6b258d69b8a4/go.mod h1:YQuXIqQpmpAqstWV0LHaDTJ5nsSWuip5ivEM+Fisb+4= github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20250228145850-f846693a6fd5 h1:cJpPJ5hEwc6vlMoxmATS60uWPUi62ydnTVBabu6WKEE= github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20250228145850-f846693a6fd5/go.mod h1:2yUpKW1/jFxpozO/Zkh3fKDzI0jthXoEcU2xuDq+vlo= github.com/smartcontractkit/chainlink-feeds v0.1.2-0.20250227211209-7cd000095135 h1:8u9xUrC+yHrTDexOKDd+jrA6LCzFFHeX1G82oj2fsSI= github.com/smartcontractkit/chainlink-feeds v0.1.2-0.20250227211209-7cd000095135/go.mod h1:NkvE4iQgiT7dMCP6U3xPELHhWhN5Xr6rHC0axRebyMU= -github.com/smartcontractkit/chainlink-framework/chains v0.0.0-20250227163723-3c71fefea680 h1:Es/V5imh4at3NdHDWlbDMjljd24TrJQCy/+8xAVajl0= -github.com/smartcontractkit/chainlink-framework/chains v0.0.0-20250227163723-3c71fefea680/go.mod h1:tHem58EihQh63kR2LlAOKDAs9Vbghf1dJKZRGy6LG8g= +github.com/smartcontractkit/chainlink-framework/chains v0.0.0-20250311143712-d83af6d2a580 h1:Ctff6yL9mnsFEyefj0LwqLAUvN5flxyGJiZ5pKZpqAA= +github.com/smartcontractkit/chainlink-framework/chains v0.0.0-20250311143712-d83af6d2a580/go.mod h1:tHem58EihQh63kR2LlAOKDAs9Vbghf1dJKZRGy6LG8g= github.com/smartcontractkit/chainlink-framework/multinode v0.0.0-20250211162441-3d6cea220efb h1:LWijSyJ2lhppkFLN19EGsLHZXQ5wen2DEk1cyR0tV+o= github.com/smartcontractkit/chainlink-framework/multinode v0.0.0-20250211162441-3d6cea220efb/go.mod h1:4JqpgFy01LaqG1yM2iFTzwX3ZgcAvW9WdstBZQgPHzU= -github.com/smartcontractkit/chainlink-integrations/evm v0.0.0-20250304212534-9eff2fa32bea h1:qcbJAI8cfLezQiWi1OS87jiLFqqzdTaHbp4zNfNGiSU= -github.com/smartcontractkit/chainlink-integrations/evm v0.0.0-20250304212534-9eff2fa32bea/go.mod h1:SnIqxMeK33uC2og+sgMftKauW5dCioMBG5XzxA8tx6o= +github.com/smartcontractkit/chainlink-integrations/evm v0.0.0-20250311123343-5a841c234992 h1:JozqMfkum2Sbsj+LXi3ZpyCw6T6QTpNbQCm4Mjcb5f4= +github.com/smartcontractkit/chainlink-integrations/evm v0.0.0-20250311123343-5a841c234992/go.mod h1:Lx4JdHoPK1m5rV5iE7+4rGipwpAqa3qWkWrixKX2IXo= github.com/smartcontractkit/chainlink-protos/job-distributor v0.9.0 h1:hfMRj2ny6oNHd8w1rhJHdoX3YkoWJtCkBK6wTlCE4+c= github.com/smartcontractkit/chainlink-protos/job-distributor v0.9.0/go.mod h1:/dVVLXrsp+V0AbcYGJo3XMzKg3CkELsweA/TTopCsKE= github.com/smartcontractkit/chainlink-protos/orchestrator v0.5.0 h1:xRgu/kMkxcY4LeDKMBhaXU4khgya7v2wyb4Sa5Nzb+Y= @@ -1158,8 +1158,8 @@ github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20241009055228- github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20241009055228-33d0c0bf38de/go.mod h1:Sl2MF/Fp3fgJIVzhdGhmZZX2BlnM0oUUyBP4s4xYb6o= github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20241009055228-33d0c0bf38de h1:66VQxXx3lvTaAZrMBkIcdH9VEjujUEvmBQdnyOJnkOc= github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20241009055228-33d0c0bf38de/go.mod h1:NSc7hgOQbXG3DAwkOdWnZzLTZENXSwDJ7Va1nBp0YU0= -github.com/smartcontractkit/wsrpc v0.8.3 h1:9tDf7Ut61g36RJIyxV9iI73SqoOMasKPfURV9oMLrPg= -github.com/smartcontractkit/wsrpc v0.8.3/go.mod h1:2u/wfnhl5R4RlSXseN4n6HHIWk8w1Am3AT6gWftQbNg= +github.com/smartcontractkit/wsrpc v0.8.5-0.20250310183704-ea183816e1d1 h1:yfukbG7KzP3FGe3WOV4GHowHqnRW1Pg7fDz2vBucS10= +github.com/smartcontractkit/wsrpc v0.8.5-0.20250310183704-ea183816e1d1/go.mod h1:m3pdp17i4bD50XgktkzWetcV5yaLsi7Gunbv4ZgN6qg= github.com/smarty/assertions v1.15.0/go.mod h1:yABtdzeQs6l1brC900WlRNwj6ZR55d7B+E8C6HtKdec= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= diff --git a/core/services/blockhashstore/batch_bhs.go b/core/services/blockhashstore/batch_bhs.go index d54dca44ae3..f6bcd8fb2c9 100644 --- a/core/services/blockhashstore/batch_bhs.go +++ b/core/services/blockhashstore/batch_bhs.go @@ -10,11 +10,8 @@ import ( "github.com/pkg/errors" txmgrcommon "github.com/smartcontractkit/chainlink-framework/chains/txmgr" - "github.com/smartcontractkit/chainlink-integrations/evm/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/batch_blockhash_store" - "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore" ) type batchBHSConfig interface { @@ -26,17 +23,12 @@ type BatchBlockhashStore struct { txm txmgr.TxManager abi *abi.ABI batchbhs batch_blockhash_store.BatchBlockhashStoreInterface - lggr logger.Logger } func NewBatchBHS( config batchBHSConfig, - fromAddresses []types.EIP55Address, txm txmgr.TxManager, batchbhs batch_blockhash_store.BatchBlockhashStoreInterface, - chainID *big.Int, - gethks keystore.Eth, - lggr logger.Logger, ) (*BatchBlockhashStore, error) { abi, err := batch_blockhash_store.BatchBlockhashStoreMetaData.GetAbi() if err != nil { @@ -47,7 +39,6 @@ func NewBatchBHS( txm: txm, abi: abi, batchbhs: batchbhs, - lggr: lggr, }, nil } diff --git a/core/services/blockhashstore/bhs.go b/core/services/blockhashstore/bhs.go index 772ca62bba3..ca2930bc9f8 100644 --- a/core/services/blockhashstore/bhs.go +++ b/core/services/blockhashstore/bhs.go @@ -15,11 +15,11 @@ import ( "github.com/pkg/errors" txmgrcommon "github.com/smartcontractkit/chainlink-framework/chains/txmgr" + evmkeystore "github.com/smartcontractkit/chainlink-integrations/evm/keys" "github.com/smartcontractkit/chainlink-integrations/evm/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/blockhash_store" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/trusted_blockhash_store" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore" ) var _ BHS = &BulletproofBHS{} @@ -44,8 +44,7 @@ type BulletproofBHS struct { trustedAbi *abi.ABI bhs blockhash_store.BlockhashStoreInterface trustedBHS *trusted_blockhash_store.TrustedBlockhashStore - chainID *big.Int - gethks keystore.Eth + gethks evmkeystore.RoundRobin } // NewBulletproofBHS creates a new instance with the given transaction manager and blockhash store. @@ -56,8 +55,7 @@ func NewBulletproofBHS( txm txmgr.TxManager, bhs blockhash_store.BlockhashStoreInterface, trustedBHS *trusted_blockhash_store.TrustedBlockhashStore, - chainID *big.Int, - gethks keystore.Eth, + gethks evmkeystore.RoundRobin, ) (*BulletproofBHS, error) { bhsABI, err := blockhash_store.BlockhashStoreMetaData.GetAbi() if err != nil { @@ -79,7 +77,6 @@ func NewBulletproofBHS( trustedAbi: trustedBHSAbi, bhs: bhs, trustedBHS: trustedBHS, - chainID: chainID, gethks: gethks, }, nil } @@ -91,7 +88,7 @@ func (c *BulletproofBHS) Store(ctx context.Context, blockNum uint64) error { return errors.Wrap(err, "packing args") } - fromAddress, err := c.gethks.GetRoundRobinAddress(ctx, c.chainID, SendingKeys(c.fromAddresses)...) + fromAddress, err := c.gethks.GetNextAddress(ctx, SendingKeys(c.fromAddresses)...) if err != nil { return errors.Wrap(err, "getting next from address") } @@ -132,7 +129,7 @@ func (c *BulletproofBHS) StoreTrusted( } // Create a transaction from the given batch and send it to the TXM. - fromAddress, err := c.gethks.GetRoundRobinAddress(ctx, c.chainID, SendingKeys(c.fromAddresses)...) + fromAddress, err := c.gethks.GetNextAddress(ctx, SendingKeys(c.fromAddresses)...) if err != nil { return errors.Wrap(err, "getting next from address") } @@ -186,7 +183,7 @@ func (c *BulletproofBHS) StoreEarliest(ctx context.Context) error { return errors.Wrap(err, "packing args") } - fromAddress, err := c.gethks.GetRoundRobinAddress(ctx, c.chainID, c.sendingKeys()...) + fromAddress, err := c.gethks.GetNextAddress(ctx, c.sendingKeys()...) if err != nil { return errors.Wrap(err, "getting next from address") } diff --git a/core/services/blockhashstore/bhs_test.go b/core/services/blockhashstore/bhs_test.go index 7e91cfad895..9359c0b6f7e 100644 --- a/core/services/blockhashstore/bhs_test.go +++ b/core/services/blockhashstore/bhs_test.go @@ -8,6 +8,8 @@ import ( "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink-integrations/evm/client/clienttest" + "github.com/smartcontractkit/chainlink-integrations/evm/keys" + "github.com/smartcontractkit/chainlink-integrations/evm/keys/keystest" "github.com/smartcontractkit/chainlink-integrations/evm/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" txmmocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr/mocks" @@ -17,10 +19,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" - "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/blockhashstore" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore" - "github.com/smartcontractkit/chainlink/v2/core/utils" ) func TestStoreRotatesFromAddresses(t *testing.T) { @@ -35,20 +34,17 @@ func TestStoreRotatesFromAddresses(t *testing.T) { DatabaseConfig: cfg.Database(), FeatureConfig: cfg.Feature(), ListenerConfig: cfg.Database().Listener(), - DB: db, KeyStore: kst.Eth(), + DB: db, Client: ethClient, }) chain, err := legacyChains.Get(cltest.FixtureChainID.String()) require.NoError(t, err) - lggr := logger.TestLogger(t) - ks := keystore.New(db, utils.FastScryptParams, lggr) - require.NoError(t, ks.Unlock(ctx, "blah")) - k1, err := ks.Eth().Create(ctx, &cltest.FixtureChainID) - require.NoError(t, err) - k2, err := ks.Eth().Create(ctx, &cltest.FixtureChainID) - require.NoError(t, err) - fromAddresses := []types.EIP55Address{k1.EIP55Address, k2.EIP55Address} + coreKS := keystest.NewMemoryChainStore() + ks := keys.NewStore(coreKS) + addr1 := coreKS.MustCreate(t) + addr2 := coreKS.MustCreate(t) + fromAddresses := []types.EIP55Address{types.EIP55AddressFromAddress(addr1), types.EIP55AddressFromAddress(addr2)} txm := new(txmmocks.MockEvmTxManager) bhsAddress := common.HexToAddress("0x31Ca8bf590360B3198749f852D5c516c642846F6") @@ -61,17 +57,16 @@ func TestStoreRotatesFromAddresses(t *testing.T) { txm, store, nil, - &cltest.FixtureChainID, - ks.Eth(), + ks, ) require.NoError(t, err) txm.On("CreateTransaction", mock.Anything, mock.MatchedBy(func(tx txmgr.TxRequest) bool { - return tx.FromAddress.String() == k1.Address.String() + return tx.FromAddress.String() == addr1.String() })).Once().Return(txmgr.Tx{}, nil) txm.On("CreateTransaction", mock.Anything, mock.MatchedBy(func(tx txmgr.TxRequest) bool { - return tx.FromAddress.String() == k2.Address.String() + return tx.FromAddress.String() == addr2.String() })).Once().Return(txmgr.Tx{}, nil) // store 2 blocks diff --git a/core/services/blockhashstore/delegate.go b/core/services/blockhashstore/delegate.go index 17247b8bfec..695bc7b3bc2 100644 --- a/core/services/blockhashstore/delegate.go +++ b/core/services/blockhashstore/delegate.go @@ -10,6 +10,7 @@ import ( "github.com/pkg/errors" "github.com/smartcontractkit/chainlink-common/pkg/services" + "github.com/smartcontractkit/chainlink-integrations/evm/keys" "github.com/smartcontractkit/chainlink-integrations/evm/types" "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" "github.com/smartcontractkit/chainlink/v2/core/config" @@ -70,24 +71,27 @@ func (d *Delegate) ServicesForSpec(ctx context.Context, jb job.Job) ([]job.Servi } d.logger.Debugw("Creating services for job spec", "job", string(marshalledJob)) - chain, err := d.legacyChains.Get(jb.BlockhashStoreSpec.EVMChainID.String()) + cid := jb.BlockhashStoreSpec.EVMChainID.ToInt() + chain, err := d.legacyChains.Get(cid.String()) if err != nil { return nil, fmt.Errorf( - "getting chain ID %d: %w", jb.BlockhashStoreSpec.EVMChainID.ToInt(), err) + "getting chain ID %s: %w", cid, err) } if !d.cfg.Feature().LogPoller() { return nil, errors.New("log poller must be enabled to run blockhashstore") } - keys, err := d.ks.EnabledKeysForChain(ctx, chain.ID()) + ks := keys.NewChainStore(keystore.NewEthSigner(d.ks, cid), cid) + + enabled, err := ks.EnabledAddresses(ctx) if err != nil { return nil, errors.Wrap(err, "getting sending keys") } - if len(keys) == 0 { + if len(enabled) == 0 { return nil, fmt.Errorf("missing sending keys for chain ID: %v", chain.ID()) } - fromAddresses := []types.EIP55Address{keys[0].EIP55Address} + fromAddresses := []types.EIP55Address{types.EIP55AddressFromAddress(enabled[0])} if jb.BlockhashStoreSpec.FromAddresses != nil { fromAddresses = jb.BlockhashStoreSpec.FromAddresses } @@ -161,8 +165,7 @@ func (d *Delegate) ServicesForSpec(ctx context.Context, jb job.Job) ([]job.Servi chain.TxManager(), bhs, trustedBHS, - chain.ID(), - d.ks, + ks, ) if err != nil { return nil, errors.Wrap(err, "building bulletproof bhs") diff --git a/core/services/blockheaderfeeder/block_header_feeder.go b/core/services/blockheaderfeeder/block_header_feeder.go index 915e187f6b7..4737ccf485c 100644 --- a/core/services/blockheaderfeeder/block_header_feeder.go +++ b/core/services/blockheaderfeeder/block_header_feeder.go @@ -12,10 +12,10 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/pkg/errors" + evmkeystore "github.com/smartcontractkit/chainlink-integrations/evm/keys" "github.com/smartcontractkit/chainlink-integrations/evm/types" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/blockhashstore" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore" ) var ( @@ -45,11 +45,10 @@ func NewBlockHeaderFeeder( waitBlocks int, lookbackBlocks int, latestBlock func(ctx context.Context) (uint64, error), - gethks keystore.Eth, + gethks evmkeystore.RoundRobin, getBlockhashesBatchSize uint16, storeBlockhashesBatchSize uint16, fromAddresses []types.EIP55Address, - chainID *big.Int, ) *BlockHeaderFeeder { return &BlockHeaderFeeder{ lggr: logger, @@ -66,7 +65,6 @@ func NewBlockHeaderFeeder( blockHeaderProvider: blockHeaderProvider, gethks: gethks, fromAddresses: fromAddresses, - chainID: chainID, } } @@ -85,9 +83,8 @@ type BlockHeaderFeeder struct { lastRunBlock uint64 getBlockhashesBatchSize uint16 storeBlockhashesBatchSize uint16 - gethks keystore.Eth + gethks evmkeystore.RoundRobin fromAddresses []types.EIP55Address - chainID *big.Int } // Run the feeder. @@ -148,7 +145,7 @@ func (f *BlockHeaderFeeder) Run(ctx context.Context) error { } // use 1 sending key for all batches because ordering matters for StoreVerifyHeader - fromAddress, err := f.gethks.GetRoundRobinAddress(ctx, f.chainID, blockhashstore.SendingKeys(f.fromAddresses)...) + fromAddress, err := f.gethks.GetNextAddress(ctx, blockhashstore.SendingKeys(f.fromAddresses)...) if err != nil { return errors.Wrap(err, "getting round robin address") } diff --git a/core/services/blockheaderfeeder/block_header_feeder_test.go b/core/services/blockheaderfeeder/block_header_feeder_test.go index ccecccbd51d..0bf32a8cc51 100644 --- a/core/services/blockheaderfeeder/block_header_feeder_test.go +++ b/core/services/blockheaderfeeder/block_header_feeder_test.go @@ -6,14 +6,13 @@ import ( "testing" "github.com/ethereum/go-ethereum/common" - "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" + "github.com/smartcontractkit/chainlink-integrations/evm/keys/keystest" "github.com/smartcontractkit/chainlink-integrations/evm/types" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/blockhashstore" - keystoremocks "github.com/smartcontractkit/chainlink/v2/core/services/keystore/mocks" ) type testCase struct { @@ -201,8 +200,7 @@ func (test testCase) testFeeder(t *testing.T) { blockHeaderProvider := &blockhashstore.TestBlockHeaderProvider{} fromAddress := "0x469aA2CD13e037DC5236320783dCfd0e641c0559" fromAddresses := []types.EIP55Address{types.EIP55Address(fromAddress)} - ks := keystoremocks.NewEth(t) - ks.On("GetRoundRobinAddress", mock.Anything, testutils.FixtureChainID, mock.Anything).Maybe().Return(common.HexToAddress(fromAddress), nil) + ks := keystest.Addresses{common.HexToAddress(fromAddress)} feeder := NewBlockHeaderFeeder( lggr, @@ -219,7 +217,6 @@ func (test testCase) testFeeder(t *testing.T) { test.getBatchSize, test.storeBatchSize, fromAddresses, - testutils.FixtureChainID, ) err := feeder.Run(testutils.Context(t)) @@ -245,8 +242,7 @@ func TestFeeder_CachesStoredBlocks(t *testing.T) { blockHeaderProvider := &blockhashstore.TestBlockHeaderProvider{} fromAddress := "0x469aA2CD13e037DC5236320783dCfd0e641c0559" fromAddresses := []types.EIP55Address{types.EIP55Address(fromAddress)} - ks := keystoremocks.NewEth(t) - ks.On("GetRoundRobinAddress", mock.Anything, testutils.FixtureChainID, mock.Anything).Maybe().Return(common.HexToAddress(fromAddress), nil) + ks := keystest.Addresses{common.HexToAddress(fromAddress)} feeder := NewBlockHeaderFeeder( logger.TestLogger(t), @@ -263,7 +259,6 @@ func TestFeeder_CachesStoredBlocks(t *testing.T) { 1, 1, fromAddresses, - testutils.FixtureChainID, ) // Should store block 74. block 75 was already stored from above diff --git a/core/services/blockheaderfeeder/delegate.go b/core/services/blockheaderfeeder/delegate.go index 046941aa154..0c729aae05c 100644 --- a/core/services/blockheaderfeeder/delegate.go +++ b/core/services/blockheaderfeeder/delegate.go @@ -4,12 +4,15 @@ import ( "context" "encoding/json" "fmt" + "slices" "time" + "github.com/ethereum/go-ethereum/common" "github.com/pkg/errors" "go.uber.org/multierr" "github.com/smartcontractkit/chainlink-common/pkg/services" + "github.com/smartcontractkit/chainlink-integrations/evm/keys" "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" "github.com/smartcontractkit/chainlink/v2/core/config" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/batch_blockhash_store" @@ -67,10 +70,11 @@ func (d *Delegate) ServicesForSpec(ctx context.Context, jb job.Job) ([]job.Servi } d.logger.Debugw("Creating services for job spec", "job", string(marshalledJob)) - chain, err := d.legacyChains.Get(jb.BlockHeaderFeederSpec.EVMChainID.String()) + cid := jb.BlockHeaderFeederSpec.EVMChainID.ToInt() + chain, err := d.legacyChains.Get(cid.String()) if err != nil { return nil, fmt.Errorf( - "getting chain ID %d: %w", jb.BlockHeaderFeederSpec.EVMChainID.ToInt(), err) + "getting chain ID %s: %w", cid, err) } if !d.cfg.Feature().LogPoller() { @@ -83,14 +87,15 @@ func (d *Delegate) ServicesForSpec(ctx context.Context, jb job.Job) ([]job.Servi chain.Config().EVM().FinalityDepth(), jb.BlockHeaderFeederSpec.LookbackBlocks) } - keys, err := d.ks.EnabledKeysForChain(ctx, chain.ID()) + ks := keys.NewChainStore(keystore.NewEthSigner(d.ks, cid), cid) + enabled, err := ks.EnabledAddresses(ctx) if err != nil { return nil, errors.Wrap(err, "getting sending keys") } - if len(keys) == 0 { + if len(enabled) == 0 { return nil, fmt.Errorf("missing sending keys for chain ID: %v", chain.ID()) } - if err = CheckFromAddressesExist(ctx, jb, d.ks); err != nil { + if err = CheckFromAddressesExist(jb, enabled); err != nil { return nil, err } fromAddresses := jb.BlockHeaderFeederSpec.FromAddresses @@ -149,19 +154,23 @@ func (d *Delegate) ServicesForSpec(ctx context.Context, jb job.Job) ([]job.Servi coordinators = append(coordinators, coord) } - bpBHS, err := blockhashstore.NewBulletproofBHS(chain.Config().EVM().GasEstimator(), d.cfg.Database(), fromAddresses, chain.TxManager(), bhs, nil, chain.ID(), d.ks) + bpBHS, err := blockhashstore.NewBulletproofBHS( + chain.Config().EVM().GasEstimator(), + d.cfg.Database(), + fromAddresses, + chain.TxManager(), + bhs, + nil, + ks, + ) if err != nil { return nil, errors.Wrap(err, "building bulletproof bhs") } batchBHS, err := blockhashstore.NewBatchBHS( chain.Config().EVM().GasEstimator(), - fromAddresses, chain.TxManager(), batchBlockhashStore, - chain.ID(), - d.ks, - d.logger, ) if err != nil { return nil, errors.Wrap(err, "building batchBHS") @@ -191,11 +200,10 @@ func (d *Delegate) ServicesForSpec(ctx context.Context, jb job.Job) ([]job.Servi } return uint64(head.Number), nil }, - d.ks, + ks, jb.BlockHeaderFeederSpec.GetBlockhashesBatchSize, jb.BlockHeaderFeederSpec.StoreBlockhashesBatchSize, fromAddresses, - chain.ID(), ) services := []job.ServiceCtx{&service{ @@ -280,10 +288,11 @@ func (s *service) runFeeder(ctx context.Context) { // CheckFromAddressesExist returns an error if and only if one of the addresses // in the BlockHeaderFeeder spec's fromAddresses field does not exist in the keystore. -func CheckFromAddressesExist(ctx context.Context, jb job.Job, gethks keystore.Eth) (err error) { +func CheckFromAddressesExist(jb job.Job, enabled []common.Address) (err error) { for _, a := range jb.BlockHeaderFeederSpec.FromAddresses { - _, err2 := gethks.Get(ctx, a.Hex()) - err = multierr.Append(err, err2) + if !slices.Contains(enabled, a.Address()) { + err = multierr.Append(err, fmt.Errorf("address not enabled: %s", a.Hex())) + } } return } diff --git a/core/services/chainlink/application.go b/core/services/chainlink/application.go index 801c66ca7c5..4a6e4ee440a 100644 --- a/core/services/chainlink/application.go +++ b/core/services/chainlink/application.go @@ -15,6 +15,7 @@ import ( "github.com/grafana/pyroscope-go" "github.com/jonboulle/clockwork" "github.com/pkg/errors" + "github.com/prometheus/client_golang/prometheus" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/trace" @@ -30,9 +31,11 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/utils" "github.com/smartcontractkit/chainlink-common/pkg/utils/jsonserializable" "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox" + "github.com/smartcontractkit/chainlink-integrations/evm/keys" "github.com/smartcontractkit/chainlink-integrations/evm/logpoller" evmtypes "github.com/smartcontractkit/chainlink-integrations/evm/types" evmutils "github.com/smartcontractkit/chainlink-integrations/evm/utils" + "github.com/smartcontractkit/chainlink/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/build" "github.com/smartcontractkit/chainlink/v2/core/capabilities" @@ -42,6 +45,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/capabilities/remote" remotetypes "github.com/smartcontractkit/chainlink/v2/core/capabilities/remote/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" + "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" "github.com/smartcontractkit/chainlink/v2/core/config" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/logger/audit" @@ -180,25 +184,24 @@ type ApplicationOpts struct { // CREOpts is the options for the CRE services CREOpts - Config GeneralConfig - Logger logger.Logger - MailMon *mailbox.Monitor - DS sqlutil.DataSource - KeyStore keystore.Master - RelayerChainInteroperators *CoreRelayerChainInteroperators - AuditLogger audit.AuditLogger - CloseLogger func() error - ExternalInitiatorManager webhook.ExternalInitiatorManager - Version string - RestrictedHTTPClient *http.Client - UnrestrictedHTTPClient *http.Client - SecretGenerator SecretGenerator - LoopRegistry *plugins.LoopRegistry - GRPCOpts loop.GRPCOpts - MercuryPool wsrpc.Pool - RetirementReportCache llo.RetirementReportCache - LLOTransmissionReaper services.ServiceCtx - NewOracleFactoryFn standardcapabilities.NewOracleFactoryFn + Config GeneralConfig + Logger logger.Logger + Registerer prometheus.Registerer + DS sqlutil.DataSource + KeyStore keystore.Master + AuditLogger audit.AuditLogger + CloseLogger func() error + ExternalInitiatorManager webhook.ExternalInitiatorManager + Version string + RestrictedHTTPClient *http.Client + UnrestrictedHTTPClient *http.Client + SecretGenerator SecretGenerator + GRPCOpts loop.GRPCOpts + MercuryPool wsrpc.Pool + RetirementReportCache llo.RetirementReportCache + LLOTransmissionReaper services.ServiceCtx + NewOracleFactoryFn standardcapabilities.NewOracleFactoryFn + EVMFactoryConfigFn func(*EVMFactoryConfig) } type Heartbeat struct { @@ -260,7 +263,7 @@ func (h *Heartbeat) getBeat() time.Duration { // the logger at the same directory and returns the Application to // be used by the node. // TODO: Inject more dependencies here to save booting up useless stuff in tests -func NewApplication(opts ApplicationOpts) (Application, error) { +func NewApplication(ctx context.Context, opts ApplicationOpts) (Application, error) { var srvcs []services.ServiceCtx heartbeat := NewHeartbeat(opts.Logger) @@ -268,29 +271,85 @@ func NewApplication(opts ApplicationOpts) (Application, error) { auditLogger := opts.AuditLogger cfg := opts.Config - relayerChainInterops := opts.RelayerChainInteroperators - mailMon := opts.MailMon externalInitiatorManager := opts.ExternalInitiatorManager globalLogger := logger.Sugared(opts.Logger) keyStore := opts.KeyStore restrictedHTTPClient := opts.RestrictedHTTPClient unrestrictedHTTPClient := opts.UnrestrictedHTTPClient + mailMon := mailbox.NewMonitor(cfg.AppID().String(), globalLogger.Named("Mailbox")) + if opts.CapabilitiesRegistry == nil { // for tests only, in prod Registry should always be set at this point opts.CapabilitiesRegistry = capabilities.NewRegistry(globalLogger) } - creCfg := creServiceConfig{ - DS: opts.DS, - CREOpts: opts.CREOpts, - capabilityCfg: cfg.Capabilities(), - workflowsCfg: cfg.Workflows(), - logger: globalLogger, - relayerChainInterops: relayerChainInterops, - keystore: keyStore, + csaKeystore := &keystore.CSASigner{CSA: keyStore.CSA()} + beholderAuthHeaders, csaPubKeyHex, err := keystore.BuildBeholderAuth(ctx, keyStore.CSA()) + if err != nil { + return nil, fmt.Errorf("failed to build Beholder auth: %w", err) + } + loopRegistry := plugins.NewLoopRegistry(globalLogger, cfg.Database(), cfg.Tracing(), cfg.Telemetry(), beholderAuthHeaders, csaPubKeyHex) + + relayerFactory := RelayerFactory{ + Logger: opts.Logger, + Registerer: opts.Registerer, + LoopRegistry: loopRegistry, + GRPCOpts: opts.GRPCOpts, + MercuryPool: opts.MercuryPool, + CapabilitiesRegistry: opts.CapabilitiesRegistry, + HTTPClient: opts.UnrestrictedHTTPClient, + RetirementReportCache: opts.RetirementReportCache, + } + + evmFactoryCfg := EVMFactoryConfig{ + ChainOpts: legacyevm.ChainOpts{ + ChainConfigs: cfg.EVMConfigs(), + DatabaseConfig: cfg.Database(), + ListenerConfig: cfg.Database().Listener(), + FeatureConfig: cfg.Feature(), + MailMon: mailMon, + DS: opts.DS, + }, + EthKeystore: keyStore.Eth(), + CSAKeystore: csaKeystore, + MercuryConfig: cfg.Mercury(), + } + + if opts.EVMFactoryConfigFn != nil { + opts.EVMFactoryConfigFn(&evmFactoryCfg) + } + + // evm always enabled for backward compatibility + // TODO BCF-2510 this needs to change in order to clear the path for EVM extraction + initOps := []CoreRelayerChainInitFunc{InitDummy(relayerFactory), InitEVM(relayerFactory, evmFactoryCfg)} + + if cfg.CosmosEnabled() { + initOps = append(initOps, InitCosmos(relayerFactory, keyStore.Cosmos(), cfg.CosmosConfigs())) + } + if cfg.SolanaEnabled() { + solanaCfg := SolanaFactoryConfig{ + TOMLConfigs: cfg.SolanaConfigs(), + DS: opts.DS, + } + initOps = append(initOps, InitSolana(relayerFactory, keyStore.Solana(), solanaCfg)) + } + if cfg.StarkNetEnabled() { + initOps = append(initOps, InitStarknet(relayerFactory, keyStore.StarkNet(), cfg.StarknetConfigs())) + } + if cfg.AptosEnabled() { + initOps = append(initOps, InitAptos(relayerFactory, keyStore.Aptos(), cfg.AptosConfigs())) + } + if cfg.TronEnabled() { + initOps = append(initOps, InitTron(relayerFactory, keyStore.Tron(), cfg.TronConfigs())) + } + + relayChainInterops, err := NewCoreRelayerChainInteroperators(initOps...) + if err != nil { + return nil, err } - creServices, err := newCREServices(creCfg) + + creServices, err := newCREServices(ctx, globalLogger, opts.DS, keyStore, cfg.Capabilities(), cfg.Workflows(), relayChainInterops, opts.CREOpts) if err != nil { return nil, fmt.Errorf("failed to initilize CRE: %w", err) } @@ -299,12 +358,7 @@ func NewApplication(opts ApplicationOpts) (Application, error) { // as OCR2 job implementations, in the case of Median today. // We will have a non-nil registry here in LOOP relayers are being used, otherwise // we need to initialize in case we serve OCR2 LOOPs - loopRegistry := opts.LoopRegistry if loopRegistry == nil { - beholderAuthHeaders, csaPubKeyHex, err := keystore.BuildBeholderAuth(keyStore) - if err != nil { - return nil, fmt.Errorf("could not build Beholder auth: %w", err) - } loopRegistry = plugins.NewLoopRegistry(globalLogger, opts.Config.Database(), opts.Config.Tracing(), opts.Config.Telemetry(), beholderAuthHeaders, csaPubKeyHex) } @@ -333,7 +387,7 @@ func NewApplication(opts ApplicationOpts) (Application, error) { globalLogger.Info("Nurse service (automatic pprof profiling) is disabled") } - telemetryManager := telemetry.NewManager(cfg.TelemetryIngress(), keyStore.CSA(), globalLogger) + telemetryManager := telemetry.NewManager(cfg.TelemetryIngress(), csaKeystore, globalLogger) srvcs = append(srvcs, telemetryManager) backupCfg := cfg.Database().Backup() @@ -363,13 +417,13 @@ func NewApplication(opts ApplicationOpts) (Application, error) { // EVM chains are used all over the place. This will need to change for fully EVM extraction // TODO: BCF-2510, BCF-2511 - legacyEVMChains := relayerChainInterops.LegacyEVMChains() + legacyEVMChains := relayChainInterops.LegacyEVMChains() if legacyEVMChains == nil { return nil, fmt.Errorf("no evm chains found") } srvcs = append(srvcs, mailMon) - srvcs = append(srvcs, relayerChainInterops.Services()...) + srvcs = append(srvcs, relayChainInterops.Services()...) // Initialize Local Users ORM and Authentication Provider specified in config // BasicAdminUsersORM is initialized and required regardless of separate Authentication Provider @@ -427,7 +481,7 @@ func NewApplication(opts ApplicationOpts) (Application, error) { srvcs = append(srvcs, pipelineORM) - loopRegistrarConfig := plugins.NewRegistrarConfig(opts.GRPCOpts, opts.LoopRegistry.Register, opts.LoopRegistry.Unregister) + loopRegistrarConfig := plugins.NewRegistrarConfig(opts.GRPCOpts, loopRegistry.Register, loopRegistry.Unregister) var ( delegates = map[job.Type]job.Delegate{ @@ -530,7 +584,7 @@ func NewApplication(opts ApplicationOpts) (Application, error) { loopRegistrarConfig, telemetryManager, pipelineRunner, - opts.RelayerChainInteroperators, + relayChainInterops, creServices.gatewayConnectorWrapper, keyStore, peerWrapper, @@ -542,7 +596,8 @@ func NewApplication(opts ApplicationOpts) (Application, error) { delegates[job.OffchainReporting] = ocr.NewDelegate( opts.DS, jobORM, - keyStore, + keyStore.Eth(), + keyStore.OCR(), pipelineRunner, peerWrapper, telemetryManager, @@ -574,7 +629,7 @@ func NewApplication(opts ApplicationOpts) (Application, error) { Lggr: globalLogger, Ks: keyStore.OCR2(), EthKs: keyStore.Eth(), - Relayers: opts.RelayerChainInteroperators, + Relayers: relayChainInterops, MailMon: mailMon, CapabilitiesRegistry: opts.CapabilitiesRegistry, RetirementReportCache: opts.RetirementReportCache, @@ -588,13 +643,13 @@ func NewApplication(opts ApplicationOpts) (Application, error) { globalLogger, cfg.OCR2(), cfg.Insecure(), - opts.RelayerChainInteroperators, + relayChainInterops, ) delegates[job.CCIP] = ccip.NewDelegate( globalLogger, loopRegistrarConfig, pipelineRunner, - relayerChainInterops, + relayChainInterops, opts.KeyStore, opts.DS, peerWrapper, @@ -657,7 +712,7 @@ func NewApplication(opts ApplicationOpts) (Application, error) { } return &ChainlinkApplication{ - relayers: opts.RelayerChainInteroperators, + relayers: relayChainInterops, jobORM: jobORM, jobSpawner: jobSpawner, pipelineRunner: pipelineRunner, @@ -733,16 +788,16 @@ type CREServices struct { srvs []services.ServiceCtx } -func newCREServices(cscfg creServiceConfig) (*CREServices, error) { - var ( - capCfg = cscfg.capabilityCfg - wCfg = cscfg.workflowsCfg - globalLogger = cscfg.logger - keyStore = cscfg.keystore - relayerChainInterops = cscfg.relayerChainInterops - opts = cscfg.CREOpts - ds = cscfg.DS - ) +func newCREServices( + ctx context.Context, + globalLogger logger.Logger, + ds sqlutil.DataSource, + keyStore creKeystore, + capCfg config.Capabilities, + wCfg config.Workflows, + relayerChainInterops *CoreRelayerChainInteroperators, + opts CREOpts, +) (*CREServices, error) { var srvcs []services.ServiceCtx workflowRateLimiter, err := ratelimiter.NewRateLimiter(ratelimiter.Config{ GlobalRPS: capCfg.RateLimit().GlobalRPS(), @@ -765,9 +820,13 @@ func newCREServices(cscfg creServiceConfig) (*CREServices, error) { var gatewayConnectorWrapper *gatewayconnector.ServiceWrapper if capCfg.GatewayConnector().DonID() != "" { globalLogger.Debugw("Creating GatewayConnector wrapper", "donID", capCfg.GatewayConnector().DonID()) + chainID, ok := new(big.Int).SetString(capCfg.GatewayConnector().ChainIDForNodeKey(), 0) + if !ok { + return nil, fmt.Errorf("failed to parse gateway connector chain ID as integer: %s", capCfg.GatewayConnector().ChainIDForNodeKey()) + } gatewayConnectorWrapper = gatewayconnector.NewGatewayConnectorServiceWrapper( capCfg.GatewayConnector(), - keyStore.Eth(), + keys.NewStore(keystore.NewEthSigner(keyStore.Eth(), chainID)), clockwork.NewRealClock(), globalLogger) srvcs = append(srvcs, gatewayConnectorWrapper) @@ -844,18 +903,10 @@ func newCREServices(cscfg creServiceConfig) (*CREServices, error) { fetcherFunc = opts.FetcherFunc } - err = keyStore.Workflow().EnsureKey(context.Background()) - if err != nil { - return nil, fmt.Errorf("failed to ensure workflow key: %w", err) - } - - keys, err := keyStore.Workflow().GetAll() + key, err := keystore.GetDefault(ctx, keyStore.Workflow()) if err != nil { return nil, fmt.Errorf("failed to get all workflow keys: %w", err) } - if len(keys) != 1 { - return nil, fmt.Errorf("expected 1 key, got %d", len(keys)) - } eventHandler := syncer.NewEventHandler( lggr, @@ -865,7 +916,7 @@ func newCREServices(cscfg creServiceConfig) (*CREServices, error) { opts.CapabilitiesRegistry, custmsg.NewLabeler(), clockwork.NewRealClock(), - keys[0], + key, workflowRateLimiter, workflowLimits, syncer.WithMaxArtifactSize( diff --git a/core/services/chainlink/relayer_chain_interoperators.go b/core/services/chainlink/relayer_chain_interoperators.go index 73283f5d8a3..a7e6d2121a6 100644 --- a/core/services/chainlink/relayer_chain_interoperators.go +++ b/core/services/chainlink/relayer_chain_interoperators.go @@ -107,7 +107,7 @@ func NewCoreRelayerChainInteroperators(initFuncs ...CoreRelayerChainInitFunc) (* type CoreRelayerChainInitFunc func(op *CoreRelayerChainInteroperators) error // InitDummy instantiates a dummy relayer -func InitDummy(ctx context.Context, factory RelayerFactory) CoreRelayerChainInitFunc { +func InitDummy(factory RelayerFactory) CoreRelayerChainInitFunc { return func(op *CoreRelayerChainInteroperators) error { op.dummyFactory = &factory return nil @@ -115,9 +115,9 @@ func InitDummy(ctx context.Context, factory RelayerFactory) CoreRelayerChainInit } // InitEVM is a option for instantiating evm relayers -func InitEVM(ctx context.Context, factory RelayerFactory, config EVMFactoryConfig) CoreRelayerChainInitFunc { +func InitEVM(factory RelayerFactory, config EVMFactoryConfig) CoreRelayerChainInitFunc { return func(op *CoreRelayerChainInteroperators) (err error) { - adapters, err2 := factory.NewEVM(ctx, config) + adapters, err2 := factory.NewEVM(config) if err2 != nil { return fmt.Errorf("failed to setup EVM relayer: %w", err2) } @@ -135,9 +135,10 @@ func InitEVM(ctx context.Context, factory RelayerFactory, config EVMFactoryConfi } // InitCosmos is a option for instantiating Cosmos relayers -func InitCosmos(ctx context.Context, factory RelayerFactory, ks keystore.Cosmos, chainCfgs RawConfigs) CoreRelayerChainInitFunc { +func InitCosmos(factory RelayerFactory, ks keystore.Cosmos, chainCfgs RawConfigs) CoreRelayerChainInitFunc { return func(op *CoreRelayerChainInteroperators) (err error) { - relayers, err := factory.NewCosmos(ks, chainCfgs) + loopKs := &keystore.CosmosLoopSigner{Cosmos: ks} + relayers, err := factory.NewCosmos(loopKs, chainCfgs) if err != nil { return fmt.Errorf("failed to setup Cosmos relayer: %w", err) } @@ -151,9 +152,10 @@ func InitCosmos(ctx context.Context, factory RelayerFactory, ks keystore.Cosmos, } // InitSolana is a option for instantiating Solana relayers -func InitSolana(ctx context.Context, factory RelayerFactory, config SolanaFactoryConfig) CoreRelayerChainInitFunc { +func InitSolana(factory RelayerFactory, ks keystore.Solana, config SolanaFactoryConfig) CoreRelayerChainInitFunc { return func(op *CoreRelayerChainInteroperators) error { - solRelayers, err := factory.NewSolana(config) + loopKs := &keystore.SolanaLooppSigner{Solana: ks} + solRelayers, err := factory.NewSolana(loopKs, config) if err != nil { return fmt.Errorf("failed to setup Solana relayer: %w", err) } @@ -168,9 +170,10 @@ func InitSolana(ctx context.Context, factory RelayerFactory, config SolanaFactor } // InitStarknet is a option for instantiating Starknet relayers -func InitStarknet(ctx context.Context, factory RelayerFactory, ks keystore.StarkNet, chainCfgs RawConfigs) CoreRelayerChainInitFunc { +func InitStarknet(factory RelayerFactory, ks keystore.StarkNet, chainCfgs RawConfigs) CoreRelayerChainInitFunc { return func(op *CoreRelayerChainInteroperators) (err error) { - starkRelayers, err := factory.NewStarkNet(ks, chainCfgs) + loopKs := &keystore.StarknetLooppSigner{StarkNet: ks} + starkRelayers, err := factory.NewStarkNet(loopKs, chainCfgs) if err != nil { return fmt.Errorf("failed to setup StarkNet relayer: %w", err) } @@ -185,9 +188,10 @@ func InitStarknet(ctx context.Context, factory RelayerFactory, ks keystore.Stark } // InitAptos is a option for instantiating Aptos relayers -func InitAptos(ctx context.Context, factory RelayerFactory, ks keystore.Aptos, chainCfgs RawConfigs) CoreRelayerChainInitFunc { +func InitAptos(factory RelayerFactory, ks keystore.Aptos, chainCfgs RawConfigs) CoreRelayerChainInitFunc { return func(op *CoreRelayerChainInteroperators) (err error) { - relayers, err := factory.NewAptos(ks, chainCfgs) + loopKs := &keystore.AptosLooppSigner{Aptos: ks} + relayers, err := factory.NewAptos(loopKs, chainCfgs) if err != nil { return fmt.Errorf("failed to setup aptos relayer: %w", err) } @@ -202,9 +206,10 @@ func InitAptos(ctx context.Context, factory RelayerFactory, ks keystore.Aptos, c } // InitTron is a option for instantiating Tron relayers -func InitTron(ctx context.Context, factory RelayerFactory, ks keystore.Tron, chainCfgs RawConfigs) CoreRelayerChainInitFunc { +func InitTron(factory RelayerFactory, ks keystore.Tron, chainCfgs RawConfigs) CoreRelayerChainInitFunc { return func(op *CoreRelayerChainInteroperators) error { - tronRelayers, err := factory.NewTron(ks, chainCfgs) + loopKs := &keystore.TronLOOPSigner{Tron: ks} + tronRelayers, err := factory.NewTron(loopKs, chainCfgs) if err != nil { return fmt.Errorf("failed to setup Tron relayer: %w", err) } diff --git a/core/services/chainlink/relayer_chain_interoperators_test.go b/core/services/chainlink/relayer_chain_interoperators_test.go index fbd4301b576..c7791ec68a3 100644 --- a/core/services/chainlink/relayer_chain_interoperators_test.go +++ b/core/services/chainlink/relayer_chain_interoperators_test.go @@ -12,11 +12,13 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/loop" "github.com/smartcontractkit/chainlink-common/pkg/types" "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox" + "github.com/smartcontractkit/chainlink/v2/core/services/keystore" solcfg "github.com/smartcontractkit/chainlink-solana/pkg/solana/config" "github.com/smartcontractkit/chainlink-integrations/evm/config/toml" ubig "github.com/smartcontractkit/chainlink-integrations/evm/utils/big" + "github.com/smartcontractkit/chainlink/v2/core/capabilities" "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" @@ -132,7 +134,7 @@ func TestCoreRelayerChainInteroperators(t *testing.T) { {name: "2 evm chains with 3 nodes", initFuncs: []chainlink.CoreRelayerChainInitFunc{ - chainlink.InitEVM(testctx, factory, chainlink.EVMFactoryConfig{ + chainlink.InitEVM(factory, chainlink.EVMFactoryConfig{ ChainOpts: legacyevm.ChainOpts{ ChainConfigs: cfg.EVMConfigs(), DatabaseConfig: cfg.Database(), @@ -141,7 +143,8 @@ func TestCoreRelayerChainInteroperators(t *testing.T) { MailMon: &mailbox.Monitor{}, DS: db, }, - CSAETHKeystore: keyStore, + EthKeystore: keyStore.Eth(), + CSAKeystore: &keystore.CSASigner{CSA: keyStore.CSA()}, }), }, expectedEVMChainCnt: 2, @@ -154,10 +157,8 @@ func TestCoreRelayerChainInteroperators(t *testing.T) { }, {name: "2 solana chain with 2 node", - initFuncs: []chainlink.CoreRelayerChainInitFunc{ - chainlink.InitSolana(testctx, factory, chainlink.SolanaFactoryConfig{ - Keystore: keyStore.Solana(), + chainlink.InitSolana(factory, keyStore.Solana(), chainlink.SolanaFactoryConfig{ TOMLConfigs: cfg.SolanaConfigs()}), }, expectedSolanaChainCnt: 2, @@ -170,11 +171,9 @@ func TestCoreRelayerChainInteroperators(t *testing.T) { }, {name: "all chains", - - initFuncs: []chainlink.CoreRelayerChainInitFunc{chainlink.InitSolana(testctx, factory, chainlink.SolanaFactoryConfig{ - Keystore: keyStore.Solana(), + initFuncs: []chainlink.CoreRelayerChainInitFunc{chainlink.InitSolana(factory, keyStore.Solana(), chainlink.SolanaFactoryConfig{ TOMLConfigs: cfg.SolanaConfigs()}), - chainlink.InitEVM(testctx, factory, chainlink.EVMFactoryConfig{ + chainlink.InitEVM(factory, chainlink.EVMFactoryConfig{ ChainOpts: legacyevm.ChainOpts{ ChainConfigs: cfg.EVMConfigs(), DatabaseConfig: cfg.Database(), @@ -184,10 +183,11 @@ func TestCoreRelayerChainInteroperators(t *testing.T) { MailMon: &mailbox.Monitor{}, DS: db, }, - CSAETHKeystore: keyStore, + EthKeystore: keyStore.Eth(), + CSAKeystore: &keystore.CSASigner{CSA: keyStore.CSA()}, }), - chainlink.InitStarknet(testctx, factory, keyStore.StarkNet(), cfg.StarknetConfigs()), - chainlink.InitCosmos(testctx, factory, keyStore.Cosmos(), cfg.CosmosConfigs()), + chainlink.InitStarknet(factory, keyStore.StarkNet(), cfg.StarknetConfigs()), + chainlink.InitCosmos(factory, keyStore.Cosmos(), cfg.CosmosConfigs()), }, expectedEVMChainCnt: 2, expectedEVMNodeCnt: 3, diff --git a/core/services/chainlink/relayer_factory.go b/core/services/chainlink/relayer_factory.go index 21275831f17..49f13e1fec7 100644 --- a/core/services/chainlink/relayer_factory.go +++ b/core/services/chainlink/relayer_factory.go @@ -2,7 +2,6 @@ package chainlink import ( "cmp" - "context" "errors" "fmt" "net/http" @@ -16,6 +15,7 @@ import ( coretypes "github.com/smartcontractkit/chainlink-common/pkg/types/core" "github.com/smartcontractkit/chainlink-solana/pkg/solana" solcfg "github.com/smartcontractkit/chainlink-solana/pkg/solana/config" + "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" coreconfig "github.com/smartcontractkit/chainlink/v2/core/config" "github.com/smartcontractkit/chainlink/v2/core/config/env" @@ -50,25 +50,17 @@ func (r *RelayerFactory) NewDummy(config DummyFactoryConfig) (loop.Relayer, erro type EVMFactoryConfig struct { legacyevm.ChainOpts - evmrelay.CSAETHKeystore + EthKeystore keystore.Eth + CSAKeystore coretypes.Keystore MercuryConfig coreconfig.Mercury } -func (r *RelayerFactory) NewEVM(ctx context.Context, config EVMFactoryConfig) (map[types.RelayID]evmrelay.LOOPRelayAdapter, error) { +func (r *RelayerFactory) NewEVM(config EVMFactoryConfig) (map[types.RelayID]evmrelay.LOOPRelayAdapter, error) { // TODO impl EVM loop. For now always 'fallback' to an adapter and embedded chain - relayers := make(map[types.RelayID]evmrelay.LOOPRelayAdapter) - lggr := r.Logger.Named("EVM") - // override some common opts with the factory values. this seems weird... maybe other signatures should change, or this should take a different type... - ccOpts := legacyevm.ChainRelayOpts{ - Logger: lggr, - KeyStore: config.CSAETHKeystore.Eth(), - ChainOpts: config.ChainOpts, - } - - legacyChains, err := evmrelay.NewLegacyChains(ctx, ccOpts) + legacyChains, err := evmrelay.NewLegacyChains(lggr, config.EthKeystore, config.ChainOpts) if err != nil { return nil, err } @@ -77,16 +69,17 @@ func (r *RelayerFactory) NewEVM(ctx context.Context, config EVMFactoryConfig) (m chain := chain relayerOpts := evmrelay.RelayerOpts{ - DS: ccOpts.DS, + DS: config.DS, Registerer: r.Registerer, - CSAETHKeystore: config.CSAETHKeystore, + EVMKeystore: keystore.NewEthSigner(config.EthKeystore, chain.ID()), + CSAKeystore: config.CSAKeystore, MercuryPool: r.MercuryPool, MercuryConfig: config.MercuryConfig, CapabilitiesRegistry: r.CapabilitiesRegistry, HTTPClient: r.HTTPClient, RetirementReportCache: r.RetirementReportCache, } - relayer, err2 := evmrelay.NewRelayer(ctx, lggr.Named(relayID.ChainID), chain, relayerOpts) + relayer, err2 := evmrelay.NewRelayer(lggr.Named(relayID.ChainID), chain, relayerOpts) if err2 != nil { err = errors.Join(err, err2) continue @@ -100,18 +93,14 @@ func (r *RelayerFactory) NewEVM(ctx context.Context, config EVMFactoryConfig) (m } type SolanaFactoryConfig struct { - Keystore keystore.Solana solcfg.TOMLConfigs DS sqlutil.DataSource } -func (r *RelayerFactory) NewSolana(config SolanaFactoryConfig) (map[types.RelayID]loop.Relayer, error) { - chainCfgs, ds, ks := config.TOMLConfigs, config.DS, config.Keystore +func (r *RelayerFactory) NewSolana(ks coretypes.Keystore, config SolanaFactoryConfig) (map[types.RelayID]loop.Relayer, error) { + chainCfgs, ds := config.TOMLConfigs, config.DS solanaRelayers := make(map[types.RelayID]loop.Relayer) - var ( - solLggr = r.Logger.Named("Solana") - signer = &keystore.SolanaSigner{Solana: ks} - ) + var solLggr = r.Logger.Named("Solana") unique := make(map[string]struct{}) // create one relayer per chain id @@ -152,12 +141,12 @@ func (r *RelayerFactory) NewSolana(config SolanaFactoryConfig) (map[types.RelayI return nil, fmt.Errorf("failed to create Solana LOOP command: %w", err) } - solanaRelayers[relayID] = loop.NewRelayerService(lggr, r.GRPCOpts, solCmdFn, string(cfgTOML), signer, r.CapabilitiesRegistry) + solanaRelayers[relayID] = loop.NewRelayerService(lggr, r.GRPCOpts, solCmdFn, string(cfgTOML), ks, r.CapabilitiesRegistry) } else { // fallback to embedded chain opts := solana.ChainOpts{ Logger: lggr, - KeyStore: signer, + KeyStore: ks, DS: ds, } @@ -171,9 +160,8 @@ func (r *RelayerFactory) NewSolana(config SolanaFactoryConfig) (map[types.RelayI return solanaRelayers, nil } -func (r *RelayerFactory) NewStarkNet(ks keystore.StarkNet, chainCfgs RawConfigs) (map[types.RelayID]loop.Relayer, error) { - loopKs := &keystore.StarknetLooppSigner{StarkNet: ks} - return r.NewLOOPRelayer("StarkNet", relay.NetworkStarkNet, env.StarknetPlugin, loopKs, chainCfgs) +func (r *RelayerFactory) NewStarkNet(ks coretypes.Keystore, chainCfgs RawConfigs) (map[types.RelayID]loop.Relayer, error) { + return r.NewLOOPRelayer("StarkNet", relay.NetworkStarkNet, env.StarknetPlugin, ks, chainCfgs) } type CosmosFactoryConfig struct { @@ -196,14 +184,12 @@ func (c CosmosFactoryConfig) Validate() error { return err } -func (r *RelayerFactory) NewCosmos(ks keystore.Cosmos, chainCfgs RawConfigs) (map[types.RelayID]loop.Relayer, error) { - loopKs := &keystore.CosmosLoopKeystore{Cosmos: ks} - return r.NewLOOPRelayer("Cosmos", relay.NetworkCosmos, env.CosmosPlugin, loopKs, chainCfgs) +func (r *RelayerFactory) NewCosmos(ks coretypes.Keystore, chainCfgs RawConfigs) (map[types.RelayID]loop.Relayer, error) { + return r.NewLOOPRelayer("Cosmos", relay.NetworkCosmos, env.CosmosPlugin, ks, chainCfgs) } -func (r *RelayerFactory) NewAptos(ks keystore.Aptos, chainCfgs RawConfigs) (map[types.RelayID]loop.Relayer, error) { - loopKs := &keystore.AptosLooppSigner{Aptos: ks} - return r.NewLOOPRelayer("Aptos", relay.NetworkAptos, env.AptosPlugin, loopKs, chainCfgs) +func (r *RelayerFactory) NewAptos(ks coretypes.Keystore, chainCfgs RawConfigs) (map[types.RelayID]loop.Relayer, error) { + return r.NewLOOPRelayer("Aptos", relay.NetworkAptos, env.AptosPlugin, ks, chainCfgs) } func (r *RelayerFactory) NewLOOPRelayer(name string, network string, plugin env.Plugin, ks coretypes.Keystore, chainCfgs RawConfigs) (map[types.RelayID]loop.Relayer, error) { @@ -252,7 +238,6 @@ func (r *RelayerFactory) NewLOOPRelayer(name string, network string, plugin env. return relayers, nil } -func (r *RelayerFactory) NewTron(ks keystore.Tron, chainCfgs RawConfigs) (map[types.RelayID]loop.Relayer, error) { - loopKs := &keystore.TronLOOPKeystore{Tron: ks} - return r.NewLOOPRelayer("Tron", relay.NetworkTron, env.TronPlugin, loopKs, chainCfgs) +func (r *RelayerFactory) NewTron(ks coretypes.Keystore, chainCfgs RawConfigs) (map[types.RelayID]loop.Relayer, error) { + return r.NewLOOPRelayer("Tron", relay.NetworkTron, env.TronPlugin, ks, chainCfgs) } diff --git a/core/services/feeds/connection_manager.go b/core/services/feeds/connection_manager.go index df580c51c59..bf6b4fa6f87 100644 --- a/core/services/feeds/connection_manager.go +++ b/core/services/feeds/connection_manager.go @@ -1,7 +1,7 @@ package feeds import ( - "crypto/ed25519" + "crypto" "sync" "github.com/pkg/errors" @@ -11,6 +11,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/services" pb "github.com/smartcontractkit/chainlink-protos/orchestrator/feedsmanager" + "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/recovery" ) @@ -54,8 +55,7 @@ type ConnectOpts struct { // URI is the URI of the feeds manager URI string - // Privkey defines the local CSA private key - Privkey []byte + CSASigner crypto.Signer // Pubkey defines the Feeds Manager Service's public key Pubkey []byte @@ -95,7 +95,7 @@ func (mgr *connectionsManager) Connect(opts ConnectOpts) { mgr.lggr.Infow("Connecting to Feeds Manager...", "feedsManagerID", opts.FeedsManagerID) clientConn, err := wsrpc.DialWithContext(ctx, opts.URI, - wsrpc.WithTransportCreds(opts.Privkey, ed25519.PublicKey(opts.Pubkey)), + wsrpc.WithTransportSigner(opts.CSASigner, opts.Pubkey), wsrpc.WithBlock(), wsrpc.WithLogger(mgr.lggr), ) diff --git a/core/services/feeds/service.go b/core/services/feeds/service.go index b789749a384..ac551ed2c0b 100644 --- a/core/services/feeds/service.go +++ b/core/services/feeds/service.go @@ -21,7 +21,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/services" "github.com/smartcontractkit/chainlink-common/pkg/sqlutil" - + "github.com/smartcontractkit/chainlink-common/pkg/types/core" pb "github.com/smartcontractkit/chainlink-protos/orchestrator/feedsmanager" "github.com/smartcontractkit/chainlink-integrations/evm/types" @@ -41,7 +41,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/standardcapabilities" "github.com/smartcontractkit/chainlink/v2/core/services/streams" "github.com/smartcontractkit/chainlink/v2/core/services/workflows" - "github.com/smartcontractkit/chainlink/v2/core/utils/crypto" + cryptoutils "github.com/smartcontractkit/chainlink/v2/core/utils/crypto" "github.com/smartcontractkit/chainlink/v2/plugins" ) @@ -134,6 +134,7 @@ type service struct { jobORM job.ORM ds sqlutil.DataSource csaKeyStore keystore.CSA + csaSigner *core.Ed25519Signer p2pKeyStore keystore.P2P ocr1KeyStore keystore.OCR ocr2KeyStore keystore.OCR2 @@ -213,7 +214,7 @@ func NewService( type RegisterManagerParams struct { Name string URI string - PublicKey crypto.PublicKey + PublicKey cryptoutils.PublicKey ChainConfigs []ChainConfig } @@ -264,14 +265,9 @@ func (s *service) RegisterManager(ctx context.Context, params RegisterManagerPar return 0, err } - privkey, err := s.getCSAPrivateKey() - if err != nil { - return 0, err - } - // Establish a connection mgr.ID = id - s.connectFeedManager(ctx, mgr, privkey) + s.connectFeedManager(mgr) return id, nil } @@ -336,7 +332,7 @@ func (s *service) SyncNodeInfo(ctx context.Context, id int64) error { cfgMsgs = append(cfgMsgs, cfgMsg) } - workflowKey := s.getWorkflowPublicKey() + workflowKey := s.getWorkflowPublicKey(ctx) resp, err := fmsClient.UpdateNode(ctx, &pb.UpdateNodeRequest{ Version: s.version, @@ -366,7 +362,7 @@ func (s *service) UpdateManager(ctx context.Context, mgr FeedsManager) error { return errors.Wrap(err, "could not update manager") } - if err := s.restartConnection(ctx, mgr); err != nil { + if err := s.restartConnection(mgr); err != nil { s.lggr.Errorf("could not restart FMS connection: %v", err) } @@ -379,7 +375,7 @@ func (s *service) EnableManager(ctx context.Context, id int64) (*FeedsManager, e return nil, errors.Wrap(err, "could not enable manager") } - if err := s.restartConnection(ctx, *mgr); err != nil { + if err := s.restartConnection(*mgr); err != nil { s.lggr.Errorf("could not restart FMS connection: %v", err) } @@ -1172,10 +1168,17 @@ func (s *service) UpdateSpecDefinition(ctx context.Context, id int64, defn strin // Start starts the service. func (s *service) Start(ctx context.Context) error { return s.StartOnce("FeedsService", func() error { - privkey, err := s.getCSAPrivateKey() + key, err := keystore.GetDefault(ctx, s.csaKeyStore) + if err != nil { + return err + } + s.csaSigner, err = core.NewEd25519Signer(key.ID(), keystore.CSASigner{CSA: s.csaKeyStore}.Sign) if err != nil { return err } + if err = s.csaSigner.Start(ctx); err != nil { + return err + } mgrs, err := s.ListManagers(ctx) if err != nil { @@ -1191,12 +1194,12 @@ func (s *service) Start(ctx context.Context) error { s.lggr.Infof("starting connection to %d feeds managers", len(mgrs)) for _, mgr := range mgrs { if mgr.DisabledAt == nil { - s.connectFeedManager(ctx, mgr, privkey) + s.connectFeedManager(mgr) } } } else { if mgrs[0].DisabledAt == nil { - s.connectFeedManager(ctx, mgrs[0], privkey) + s.connectFeedManager(mgrs[0]) } } @@ -1215,17 +1218,16 @@ func (s *service) Close() error { // This blocks until it finishes s.connMgr.Close() - - return nil + return s.csaSigner.Close() }) } // connectFeedManager connects to a feeds manager -func (s *service) connectFeedManager(ctx context.Context, mgr FeedsManager, privkey []byte) { +func (s *service) connectFeedManager(mgr FeedsManager) { s.connMgr.Connect(ConnectOpts{ FeedsManagerID: mgr.ID, URI: mgr.URI, - Privkey: privkey, + CSASigner: s.csaSigner, Pubkey: mgr.PublicKey, Handlers: &RPCHandlers{ feedsManagerID: mgr.ID, @@ -1238,31 +1240,15 @@ func (s *service) connectFeedManager(ctx context.Context, mgr FeedsManager, priv }) } -// getCSAPrivateKey gets the server's CSA private key -func (s *service) getCSAPrivateKey() (privkey []byte, err error) { - // Fetch the server's public key - keys, err := s.csaKeyStore.GetAll() - if err != nil { - return privkey, err - } - if len(keys) < 1 { - return privkey, errors.New("CSA key does not exist") - } - return keys[0].Raw(), nil -} - // getWorkflowPublicKey retrieves the server's Workflow public key. // Since there will be at most one key, it returns the first key found. // If an error occurs or no keys are found, it returns blank. -func (s *service) getWorkflowPublicKey() string { - keys, err := s.workflowKeyStore.GetAll() +func (s *service) getWorkflowPublicKey(ctx context.Context) string { + key, err := keystore.GetDefault(ctx, s.workflowKeyStore) if err != nil { return "" } - if len(keys) < 1 { - return "" - } - return keys[0].PublicKeyString() + return key.PublicKeyString() } // observeJobProposalCounts is a helper method that queries the repository for the count of @@ -1550,20 +1536,14 @@ func (s *service) validateProposeJobArgs(ctx context.Context, args ProposeJobArg return nil } -func (s *service) restartConnection(ctx context.Context, mgr FeedsManager) error { +func (s *service) restartConnection(mgr FeedsManager) error { s.lggr.Infof("Restarting connection") if err := s.connMgr.Disconnect(mgr.ID); err != nil { s.lggr.Info("Feeds Manager not connected, attempting to connect") } - // Establish a new connection - privkey, err := s.getCSAPrivateKey() - if err != nil { - return err - } - - s.connectFeedManager(ctx, mgr, privkey) + s.connectFeedManager(mgr) return nil } diff --git a/core/services/feeds/service_test.go b/core/services/feeds/service_test.go index 0820a3e7e21..fc5ac82e2bb 100644 --- a/core/services/feeds/service_test.go +++ b/core/services/feeds/service_test.go @@ -238,9 +238,9 @@ func setupTestServiceCfg( DatabaseConfig: gcfg.Database(), FeatureConfig: gcfg.Feature(), ListenerConfig: gcfg.Database().Listener(), + KeyStore: ethKeyStore, DB: db, HeadTracker: heads.NullTracker, - KeyStore: ethKeyStore, }) keyStore.On("Eth").Return(ethKeyStore) keyStore.On("CSA").Return(csaKeystore) @@ -303,6 +303,7 @@ func Test_Service_RegisterManager(t *testing.T) { Return(id, nil) svc.orm.On("CreateBatchChainConfig", mock.Anything, params.ChainConfigs, mock.Anything). Return([]int64{}, nil) + svc.csaKeystore.On("EnsureKey", mock.Anything).Return(nil) svc.csaKeystore.On("GetAll").Return([]csakey.KeyV2{key}, nil) // ListManagers runs in a goroutine so it might be called. svc.orm.On("ListManagers", testutils.Context(t)).Return([]feeds.FeedsManager{mgr}, nil).Maybe() @@ -360,6 +361,7 @@ func Test_Service_RegisterManager_MultiFeedsManager(t *testing.T) { Return(id, nil) svc.orm.On("CreateBatchChainConfig", mock.Anything, params.ChainConfigs, mock.Anything). Return([]int64{}, nil) + svc.csaKeystore.On("EnsureKey", mock.Anything).Return(nil) svc.csaKeystore.On("GetAll").Return([]csakey.KeyV2{key}, nil) // ListManagers runs in a goroutine so it might be called. svc.orm.On("ListManagers", ctx).Return([]feeds.FeedsManager{mgr}, nil).Maybe() @@ -514,6 +516,7 @@ func Test_Service_UpdateFeedsManager(t *testing.T) { svc := setupTestService(t) svc.orm.On("UpdateManager", mock.Anything, mgr, mock.Anything).Return(nil) + svc.csaKeystore.On("EnsureKey", mock.Anything).Return(nil) svc.csaKeystore.On("GetAll").Return([]csakey.KeyV2{key}, nil) svc.connMgr.On("Disconnect", mgr.ID).Return(nil) svc.connMgr.On("Connect", mock.IsType(feeds.ConnectOpts{})).Return(nil) @@ -531,6 +534,7 @@ func Test_Service_EnableFeedsManager(t *testing.T) { svc.orm.On("EnableManager", mock.Anything, mgr.ID).Return(&mgr, nil) svc.connMgr.On("IsConnected", mgr.ID).Return(false) + svc.csaKeystore.On("EnsureKey", mock.Anything).Return(nil) svc.csaKeystore.On("GetAll").Return([]csakey.KeyV2{key}, nil) svc.connMgr.On("Disconnect", mgr.ID).Return(nil) svc.connMgr.On("Connect", mock.IsType(feeds.ConnectOpts{})).Return(nil) @@ -643,6 +647,7 @@ func Test_Service_CreateChainConfig(t *testing.T) { workflowKey, err := workflowkey.New() require.NoError(t, err) + svc.workflowKeystore.On("EnsureKey", mock.Anything).Return(nil) svc.workflowKeystore.On("GetAll").Return([]workflowkey.Key{workflowKey}, nil) svc.orm.On("CreateChainConfig", mock.Anything, cfg).Return(int64(1), nil) @@ -714,6 +719,7 @@ func Test_Service_DeleteChainConfig(t *testing.T) { workflowKey, err := workflowkey.New() require.NoError(t, err) + svc.workflowKeystore.On("EnsureKey", mock.Anything).Return(nil) svc.workflowKeystore.On("GetAll").Return([]workflowkey.Key{workflowKey}, nil) svc.orm.On("GetChainConfig", mock.Anything, cfg.ID).Return(&cfg, nil) @@ -811,6 +817,7 @@ func Test_Service_UpdateChainConfig(t *testing.T) { workflowKey, err := workflowkey.New() require.NoError(t, err) + svc.workflowKeystore.On("EnsureKey", mock.Anything).Return(nil) svc.workflowKeystore.On("GetAll").Return([]workflowkey.Key{workflowKey}, nil) svc.orm.On("UpdateChainConfig", mock.Anything, cfg).Return(int64(1), nil) @@ -1817,6 +1824,7 @@ func Test_Service_SyncNodeInfo(t *testing.T) { svc.p2pKeystore.On("Get", p2pKey.PeerID()).Return(p2pKey, nil) svc.ocr1Keystore.On("Get", ocrKey.GetID()).Return(ocrKey, nil) + svc.workflowKeystore.On("EnsureKey", mock.Anything).Return(nil) svc.workflowKeystore.On("GetAll").Return([]workflowkey.Key{workflowKey}, nil) wkID := workflowKey.ID() svc.fmsClient.On("UpdateNode", mock.Anything, &proto.UpdateNodeRequest{ @@ -1921,6 +1929,7 @@ func Test_Service_syncNodeInfoWithRetry(t *testing.T) { { name: "create chain", setup: func(t *testing.T, svc *TestService) { + svc.workflowKeystore.On("EnsureKey", mock.Anything).Return(nil) svc.workflowKeystore.EXPECT().GetAll().Return([]workflowkey.Key{workflowKey}, nil) svc.orm.EXPECT().CreateChainConfig(mock.Anything, cfg).Return(int64(1), nil) svc.orm.EXPECT().GetManager(mock.Anything, mgr.ID).Return(&mgr, nil) @@ -1944,6 +1953,7 @@ func Test_Service_syncNodeInfoWithRetry(t *testing.T) { { name: "update chain", setup: func(t *testing.T, svc *TestService) { + svc.workflowKeystore.On("EnsureKey", mock.Anything).Return(nil) svc.workflowKeystore.EXPECT().GetAll().Return([]workflowkey.Key{workflowKey}, nil) svc.orm.EXPECT().UpdateChainConfig(mock.Anything, cfg).Return(int64(1), nil) svc.orm.EXPECT().GetChainConfig(mock.Anything, cfg.ID).Return(&cfg, nil) @@ -1967,6 +1977,7 @@ func Test_Service_syncNodeInfoWithRetry(t *testing.T) { { name: "delete chain", setup: func(t *testing.T, svc *TestService) { + svc.workflowKeystore.On("EnsureKey", mock.Anything).Return(nil) svc.workflowKeystore.EXPECT().GetAll().Return([]workflowkey.Key{workflowKey}, nil) svc.orm.EXPECT().GetChainConfig(mock.Anything, cfg.ID).Return(&cfg, nil) svc.orm.EXPECT().DeleteChainConfig(mock.Anything, cfg.ID).Return(cfg.ID, nil) @@ -1991,6 +2002,7 @@ func Test_Service_syncNodeInfoWithRetry(t *testing.T) { { name: "more errors than MaxAttempts", setup: func(t *testing.T, svc *TestService) { + svc.workflowKeystore.On("EnsureKey", mock.Anything).Return(nil) svc.workflowKeystore.EXPECT().GetAll().Return([]workflowkey.Key{workflowKey}, nil) svc.orm.EXPECT().CreateChainConfig(mock.Anything, cfg).Return(int64(1), nil) svc.orm.EXPECT().GetManager(mock.Anything, mgr.ID).Return(&mgr, nil) @@ -4878,6 +4890,7 @@ func Test_Service_StartStop(t *testing.T) { { name: "success with a feeds manager connection", beforeFunc: func(svc *TestService) { + svc.csaKeystore.On("EnsureKey", mock.Anything).Return(nil) svc.csaKeystore.On("GetAll").Return([]csakey.KeyV2{key}, nil) svc.orm.On("ListManagers", mock.Anything).Return([]feeds.FeedsManager{mgr}, nil) svc.connMgr.On("IsConnected", mgr.ID).Return(false) @@ -4890,6 +4903,7 @@ func Test_Service_StartStop(t *testing.T) { name: "success with multiple feeds managers connection", enableMultiFeedsManagers: true, beforeFunc: func(svc *TestService) { + svc.csaKeystore.On("EnsureKey", mock.Anything).Return(nil) svc.csaKeystore.On("GetAll").Return([]csakey.KeyV2{key}, nil) svc.orm.On("ListManagers", mock.Anything).Return([]feeds.FeedsManager{mgr, mgr2}, nil) svc.connMgr.On("IsConnected", mgr.ID).Return(false) @@ -4902,6 +4916,7 @@ func Test_Service_StartStop(t *testing.T) { { name: "success with no registered managers", beforeFunc: func(svc *TestService) { + svc.csaKeystore.On("EnsureKey", mock.Anything).Return(nil) svc.csaKeystore.On("GetAll").Return([]csakey.KeyV2{key}, nil) svc.orm.On("ListManagers", mock.Anything).Return([]feeds.FeedsManager{}, nil) svc.connMgr.On("Close") diff --git a/core/services/functions/connector_handler.go b/core/services/functions/connector_handler.go index 75a3dca24f1..0e860e565fa 100644 --- a/core/services/functions/connector_handler.go +++ b/core/services/functions/connector_handler.go @@ -3,15 +3,13 @@ package functions import ( "bytes" "context" - "crypto/ecdsa" "encoding/json" + "errors" "fmt" "strings" "sync" "time" - "go.uber.org/multierr" - ethCommon "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" "github.com/prometheus/client_golang/prometheus" @@ -19,7 +17,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/assets" "github.com/smartcontractkit/chainlink-common/pkg/services" - + "github.com/smartcontractkit/chainlink-integrations/evm/keys" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/gateway/api" "github.com/smartcontractkit/chainlink/v2/core/services/gateway/common" @@ -36,7 +34,8 @@ type functionsConnectorHandler struct { services.StateMachine connector connector.GatewayConnector - signerKey *ecdsa.PrivateKey + signAddr ethCommon.Address + keystore keys.MessageSigner nodeAddress string storage s4.Storage allowlist fallow.OnchainAllowlist @@ -74,8 +73,19 @@ func InternalId(sender []byte, requestId []byte) RequestID { return RequestID(crypto.Keccak256Hash(append(sender, requestId...)).Bytes()) } -func NewFunctionsConnectorHandler(pluginConfig *config.PluginConfig, signerKey *ecdsa.PrivateKey, storage s4.Storage, allowlist fallow.OnchainAllowlist, rateLimiter *hc.RateLimiter, subscriptions fsub.OnchainSubscriptions, listener FunctionsListener, offchainTransmitter OffchainTransmitter, lggr logger.Logger) (*functionsConnectorHandler, error) { - if signerKey == nil || storage == nil || allowlist == nil || rateLimiter == nil || subscriptions == nil || listener == nil || offchainTransmitter == nil { +func NewFunctionsConnectorHandler( + pluginConfig *config.PluginConfig, + signAddr ethCommon.Address, + keystore keys.MessageSigner, + storage s4.Storage, + allowlist fallow.OnchainAllowlist, + rateLimiter *hc.RateLimiter, + subscriptions fsub.OnchainSubscriptions, + listener FunctionsListener, + offchainTransmitter OffchainTransmitter, + lggr logger.Logger, +) (*functionsConnectorHandler, error) { + if signAddr == (ethCommon.Address{}) || keystore == nil || storage == nil || allowlist == nil || rateLimiter == nil || subscriptions == nil || listener == nil || offchainTransmitter == nil { return nil, fmt.Errorf("all dependencies must be non-nil") } allowedHeartbeatInitiators := make(map[string]struct{}) @@ -84,7 +94,8 @@ func NewFunctionsConnectorHandler(pluginConfig *config.PluginConfig, signerKey * } return &functionsConnectorHandler{ nodeAddress: pluginConfig.GatewayConnectorConfig.NodeAddress, - signerKey: signerKey, + signAddr: signAddr, + keystore: keystore, storage: storage, allowlist: allowlist, rateLimiter: rateLimiter, @@ -105,7 +116,9 @@ func (h *functionsConnectorHandler) SetConnector(connector connector.GatewayConn } func (h *functionsConnectorHandler) Sign(data ...[]byte) ([]byte, error) { - return common.SignData(h.signerKey, data...) + ctx, cancel := h.chStop.NewCtx() + defer cancel() + return h.keystore.SignMessage(ctx, h.signAddr, common.Flatten(data...)) } func (h *functionsConnectorHandler) HandleGatewayMessage(ctx context.Context, gatewayId string, msg *api.Message) { @@ -159,8 +172,8 @@ func (h *functionsConnectorHandler) Start(ctx context.Context) error { func (h *functionsConnectorHandler) Close() error { return h.StopOnce("FunctionsConnectorHandler", func() (err error) { close(h.chStop) - err = multierr.Combine(err, h.allowlist.Close()) - err = multierr.Combine(err, h.subscriptions.Close()) + err = errors.Join(err, h.allowlist.Close()) + err = errors.Join(err, h.subscriptions.Close()) h.shutdownWaitGroup.Wait() return }) @@ -351,7 +364,7 @@ func (h *functionsConnectorHandler) sendResponse(ctx context.Context, gatewayId Payload: payloadJson, }, } - if err = msg.Sign(h.signerKey); err != nil { + if err = msg.SignKS(ctx, h.keystore, h.signAddr); err != nil { return err } return h.connector.SendToGateway(ctx, gatewayId, msg) diff --git a/core/services/functions/connector_handler_test.go b/core/services/functions/connector_handler_test.go index a24139da58e..830595a474f 100644 --- a/core/services/functions/connector_handler_test.go +++ b/core/services/functions/connector_handler_test.go @@ -14,6 +14,7 @@ import ( "github.com/onsi/gomega" "github.com/smartcontractkit/chainlink-common/pkg/assets" + "github.com/smartcontractkit/chainlink-integrations/evm/keys/keystest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/functions" @@ -79,15 +80,17 @@ func TestFunctionsConnectorHandler(t *testing.T) { allowlist.On("Close", mock.Anything).Return(nil) subscriptions.On("Start", mock.Anything).Return(nil) subscriptions.On("Close", mock.Anything).Return(nil) + signAddr := crypto.PubkeyToAddress(privateKey.PublicKey) config := &config.PluginConfig{ GatewayConnectorConfig: &gwconnector.ConnectorConfig{ NodeAddress: addr.Hex(), }, MinimumSubscriptionBalance: *assets.NewLinkFromJuels(100), RequestTimeoutSec: 1_000, - AllowedHeartbeatInitiators: []string{crypto.PubkeyToAddress(privateKey.PublicKey).Hex()}, + AllowedHeartbeatInitiators: []string{signAddr.Hex()}, } - handler, err := functions.NewFunctionsConnectorHandler(config, privateKey, storage, allowlist, rateLimiter, subscriptions, listener, offchainTransmitter, logger) + msgSigner := (*keystest.ECDSAMessageSigner)(privateKey) + handler, err := functions.NewFunctionsConnectorHandler(config, signAddr, msgSigner, storage, allowlist, rateLimiter, subscriptions, listener, offchainTransmitter, logger) require.NoError(t, err) handler.SetConnector(connector) diff --git a/core/services/gateway/api/message.go b/core/services/gateway/api/message.go index 86813c26b35..0afc0c05dff 100644 --- a/core/services/gateway/api/message.go +++ b/core/services/gateway/api/message.go @@ -1,14 +1,17 @@ package api import ( + "context" "crypto/ecdsa" "encoding/json" "errors" "strings" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" "github.com/smartcontractkit/chainlink-common/pkg/utils/hex" + "github.com/smartcontractkit/chainlink-integrations/evm/keys" gw_common "github.com/smartcontractkit/chainlink/v2/core/services/gateway/common" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -103,6 +106,20 @@ func (m *Message) Sign(privateKey *ecdsa.PrivateKey) error { return nil } +func (m *Message) SignKS(ctx context.Context, ks keys.MessageSigner, signer common.Address) error { + if m == nil { + return errors.New("nil message") + } + rawData := GetRawMessageBody(&m.Body) + signature, err := ks.SignMessage(ctx, signer, gw_common.Flatten(rawData...)) + if err != nil { + return err + } + m.Signature = utils.StringToHex(string(signature)) + m.Body.Sender = strings.ToLower(signer.Hex()) + return nil +} + func (m *Message) ExtractSigner() (signerAddress []byte, err error) { if m == nil { return nil, errors.New("nil message") diff --git a/core/services/gateway/common/utils.go b/core/services/gateway/common/utils.go index 59c67bdcfa1..a8b870571bb 100644 --- a/core/services/gateway/common/utils.go +++ b/core/services/gateway/common/utils.go @@ -33,6 +33,9 @@ func AlignedBytesToString(data []byte) string { return string(data[:idx]) } +func Flatten(data ...[]byte) []byte { + return flatten(data...) +} func flatten(data ...[]byte) []byte { var result []byte for _, d := range data { diff --git a/core/services/headreporter/prometheus_reporter_test.go b/core/services/headreporter/prometheus_reporter_test.go index 5c8ef15c136..328b3b10afc 100644 --- a/core/services/headreporter/prometheus_reporter_test.go +++ b/core/services/headreporter/prometheus_reporter_test.go @@ -13,6 +13,7 @@ import ( "github.com/smartcontractkit/chainlink-integrations/evm/client/clienttest" "github.com/smartcontractkit/chainlink-integrations/evm/gas" "github.com/smartcontractkit/chainlink-integrations/evm/heads/headstest" + "github.com/smartcontractkit/chainlink-integrations/evm/keys/keystest" "github.com/smartcontractkit/chainlink-integrations/evm/logpoller" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" @@ -121,7 +122,7 @@ func Test_PrometheusReporter(t *testing.T) { func newLegacyChainContainer(t *testing.T, db *sqlx.DB) legacyevm.LegacyChainContainer { config, dbConfig, evmConfig := txmgr.MakeTestConfigs(t) - keyStore := cltest.NewKeyStore(t, db).Eth() + keyStore := &keystest.FakeChainStore{} ethClient := clienttest.NewClientWithDefaultChainID(t) estimator, err := gas.NewEstimator(logger.TestLogger(t), ethClient, config.ChainType(), ethClient.ConfiguredChainID(), evmConfig.GasEstimator(), nil) require.NoError(t, err) diff --git a/core/services/job/job_orm_test.go b/core/services/job/job_orm_test.go index 1084d7d0fab..916004ea015 100644 --- a/core/services/job/job_orm_test.go +++ b/core/services/job/job_orm_test.go @@ -19,11 +19,12 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/types" "github.com/smartcontractkit/chainlink-common/pkg/utils/jsonserializable" pkgworkflows "github.com/smartcontractkit/chainlink-common/pkg/workflows" - "github.com/smartcontractkit/chainlink-integrations/evm/assets" configtoml "github.com/smartcontractkit/chainlink-integrations/evm/config/toml" + "github.com/smartcontractkit/chainlink-integrations/evm/keys" evmtypes "github.com/smartcontractkit/chainlink-integrations/evm/types" "github.com/smartcontractkit/chainlink-integrations/evm/utils/big" + "github.com/smartcontractkit/chainlink/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" @@ -38,7 +39,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/gateway" "github.com/smartcontractkit/chainlink/v2/core/services/job" "github.com/smartcontractkit/chainlink/v2/core/services/keeper" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" "github.com/smartcontractkit/chainlink/v2/core/services/ocr" ocr2validate "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/validate" @@ -1415,8 +1415,8 @@ func Test_FindPipelineRuns(t *testing.T) { DatabaseConfig: config.Database(), FeatureConfig: config.Feature(), ListenerConfig: config.Database().Listener(), - DB: db, KeyStore: keyStore.Eth(), + DB: db, }) orm := NewTestORM(t, db, pipelineORM, bridgesORM, keyStore) @@ -2361,12 +2361,10 @@ func TestORM_CreateJob_KeyLocking(t *testing.T) { `, dtTransmitterAddress.Address.String()) - rm, err := ks.Eth().GetResourceMutex(ctx, transmitterID) - require.NoError(t, err) - require.NoError(t, rm.TryLock(keystore.TXMv1)) - rm, err = ks.Eth().GetResourceMutex(ctx, dtTransmitterAddress.Address) - require.NoError(t, err) - require.NoError(t, rm.TryLock(keystore.TXMv2)) + rm := ks.Eth().GetResourceMutex(ctx, transmitterID) + require.NoError(t, rm.TryLock(keys.TXMv1)) + rm = ks.Eth().GetResourceMutex(ctx, dtTransmitterAddress.Address) + require.NoError(t, rm.TryLock(keys.TXMv2)) jb, err := ocr2validate.ValidatedOracleSpecToml(testutils.Context(t), config.OCR2(), config.Insecure(), baseJobSpec+completeDualTransmissionSpec, nil) require.NoError(t, err) @@ -2377,12 +2375,10 @@ func TestORM_CreateJob_KeyLocking(t *testing.T) { }) t.Run("keys locked but job spec misconfigured", func(t *testing.T) { - rm, err := ks.Eth().GetResourceMutex(ctx, transmitterID) - require.NoError(t, err) - require.NoError(t, rm.TryLock(keystore.TXMv1)) - rm, err = ks.Eth().GetResourceMutex(ctx, dtTransmitterAddress.Address) - require.NoError(t, err) - require.NoError(t, rm.TryLock(keystore.TXMv2)) + rm := ks.Eth().GetResourceMutex(ctx, transmitterID) + require.NoError(t, rm.TryLock(keys.TXMv1)) + rm = ks.Eth().GetResourceMutex(ctx, dtTransmitterAddress.Address) + require.NoError(t, rm.TryLock(keys.TXMv2)) completeDualTransmissionSpec := fmt.Sprintf(` enableDualTransmission=true diff --git a/core/services/job/job_pipeline_orm_integration_test.go b/core/services/job/job_pipeline_orm_integration_test.go index b8abce41850..f95e9a9c48a 100644 --- a/core/services/job/job_pipeline_orm_integration_test.go +++ b/core/services/job/job_pipeline_orm_integration_test.go @@ -162,7 +162,7 @@ func TestPipelineORM_Integration(t *testing.T) { ListenerConfig: config.Database().Listener(), Client: clienttest.NewClientWithDefaultChainID(t), DB: db, - KeyStore: ethKeyStore, + KeyStore: keyStore.Eth(), }) runner := pipeline.NewRunner(orm, btORM, config.JobPipeline(), config.WebServer(), legacyChains, nil, nil, lggr, nil, nil) diff --git a/core/services/job/orm.go b/core/services/job/orm.go index b0605e44466..3c4c3df7f69 100644 --- a/core/services/job/orm.go +++ b/core/services/job/orm.go @@ -22,6 +22,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/sqlutil" "github.com/smartcontractkit/chainlink-common/pkg/types" evmconfig "github.com/smartcontractkit/chainlink-integrations/evm/config" + evmkeystore "github.com/smartcontractkit/chainlink-integrations/evm/keys" evmtypes "github.com/smartcontractkit/chainlink-integrations/evm/types" "github.com/smartcontractkit/chainlink-integrations/evm/utils/big" "github.com/smartcontractkit/chainlink/v2/core/bridges" @@ -348,20 +349,14 @@ func (o *orm) CreateJob(ctx context.Context, jb *Job) error { } // Check if secondary transmitter address is used as primary somewhere else - hasLock, err2 := checkIfKeyHasLock(ctx, tx.keyStore.Eth(), common.HexToAddress(dtTransmitterAddress), keystore.TXMv1) - if err2 != nil { - return err2 - } else if hasLock { + if checkIfKeyHasLock(ctx, tx.keyStore.Eth(), common.HexToAddress(dtTransmitterAddress), evmkeystore.TXMv1) { return errors.Errorf("key %s cannot be a secondary transmitter address because it's used a primary transmitter in another job", dtTransmitterAddress) } } // Check if primary transmitter address is used as secondary somewhere else, don't check for mercury as it uses CSA keys for transmitters if jb.OCR2OracleSpec.PluginType != types.Mercury { - hasLock, err2 := checkIfKeyHasLock(ctx, tx.keyStore.Eth(), common.HexToAddress(jb.OCR2OracleSpec.TransmitterID.String), keystore.TXMv2) - if err2 != nil { - return err2 - } else if hasLock { + if checkIfKeyHasLock(ctx, tx.keyStore.Eth(), common.HexToAddress(jb.OCR2OracleSpec.TransmitterID.String), evmkeystore.TXMv2) { return errors.Errorf("key %s cannot be a (primary) transmitter address because it's used a secondary transmitter address in another job", jb.OCR2OracleSpec.TransmitterID.String) } } @@ -1793,11 +1788,8 @@ func validateDualTransmissionMeta(meta map[string]interface{}) error { return nil } -func checkIfKeyHasLock(ctx context.Context, ks keystore.Eth, address common.Address, usage keystore.ServiceType) (bool, error) { - rm, err := ks.GetResourceMutex(ctx, address) - if err != nil { - return false, err - } +func checkIfKeyHasLock(ctx context.Context, ks keystore.Eth, address common.Address, usage evmkeystore.ServiceType) bool { + rm := ks.GetResourceMutex(ctx, address) return rm.IsLocked(usage) } diff --git a/core/services/job/runner_integration_test.go b/core/services/job/runner_integration_test.go index e84cd8f7aa3..363ba8b5d94 100644 --- a/core/services/job/runner_integration_test.go +++ b/core/services/job/runner_integration_test.go @@ -27,7 +27,6 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" "github.com/smartcontractkit/chainlink-common/pkg/utils/jsonserializable" "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox/mailboxtest" - "github.com/smartcontractkit/chainlink-integrations/evm/types" "github.com/smartcontractkit/chainlink/v2/core/auth" "github.com/smartcontractkit/chainlink/v2/core/bridges" @@ -90,7 +89,7 @@ func TestRunner(t *testing.T) { DatabaseConfig: config.Database(), FeatureConfig: config.Feature(), ListenerConfig: config.Database().Listener(), - KeyStore: ethKeyStore, + KeyStore: keyStore.Eth(), }) c := clhttptest.NewTestLocalOnlyHTTPClient() @@ -472,7 +471,8 @@ answer1 [type=median index=0]; sd := ocr.NewDelegate( db, jobORM, - keyStore, + ethKeyStore, + keyStore.OCR(), nil, pw, monitoringEndpoint, @@ -507,7 +507,8 @@ answer1 [type=median index=0]; sd := ocr.NewDelegate( db, jobORM, - keyStore, + ethKeyStore, + keyStore.OCR(), nil, pw, monitoringEndpoint, @@ -535,7 +536,8 @@ answer1 [type=median index=0]; sd := ocr.NewDelegate( db, jobORM, - keyStore, + ethKeyStore, + keyStore.OCR(), nil, pw, monitoringEndpoint, @@ -597,7 +599,8 @@ answer1 [type=median index=0]; sd := ocr.NewDelegate( db, jobORM, - keyStore, + ethKeyStore, + keyStore.OCR(), nil, pw, monitoringEndpoint, @@ -642,7 +645,8 @@ answer1 [type=median index=0]; sd := ocr.NewDelegate( db, jobORM, - keyStore, + ethKeyStore, + keyStore.OCR(), nil, pw, monitoringEndpoint, diff --git a/core/services/job/spawner_test.go b/core/services/job/spawner_test.go index 32f156eb214..4ee55a3fc1a 100644 --- a/core/services/job/spawner_test.go +++ b/core/services/job/spawner_test.go @@ -17,6 +17,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/types" "github.com/smartcontractkit/chainlink-common/pkg/utils" "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox/mailboxtest" + "github.com/smartcontractkit/chainlink/v2/core/services/keystore" evmtypes "github.com/smartcontractkit/chainlink-integrations/evm/types" "github.com/smartcontractkit/chainlink/v2/core/bridges" @@ -140,7 +141,7 @@ func TestSpawner_CreateJobDeleteJob(t *testing.T) { serviceA1.On("Start", mock.Anything).Return(nil).Once() serviceA2.On("Start", mock.Anything).Return(nil).Once().Run(func(mock.Arguments) { eventuallyA.ItHappened() }) mailMon := servicetest.Run(t, mailboxtest.NewMonitor(t)) - dA := ocr.NewDelegate(nil, orm, nil, nil, nil, monitoringEndpoint, legacyChains, logger.TestLogger(t), config, mailMon) + dA := ocr.NewDelegate(nil, orm, nil, nil, nil, nil, monitoringEndpoint, legacyChains, logger.TestLogger(t), config, mailMon) delegateA := &delegate{jobA.Type, []job.ServiceCtx{serviceA1, serviceA2}, 0, make(chan struct{}), dA} eventuallyB := cltest.NewAwaiter() @@ -148,7 +149,7 @@ func TestSpawner_CreateJobDeleteJob(t *testing.T) { serviceB2 := mocks.NewServiceCtx(t) serviceB1.On("Start", mock.Anything).Return(nil).Once() serviceB2.On("Start", mock.Anything).Return(nil).Once().Run(func(mock.Arguments) { eventuallyB.ItHappened() }) - dB := ocr.NewDelegate(nil, orm, nil, nil, nil, monitoringEndpoint, legacyChains, logger.TestLogger(t), config, mailMon) + dB := ocr.NewDelegate(nil, orm, nil, nil, nil, nil, monitoringEndpoint, legacyChains, logger.TestLogger(t), config, mailMon) delegateB := &delegate{jobB.Type, []job.ServiceCtx{serviceB1, serviceB2}, 0, make(chan struct{}), dB} spawner := job.NewSpawner(orm, config.Database(), noopChecker{}, map[job.Type]job.Delegate{ @@ -200,7 +201,7 @@ func TestSpawner_CreateJobDeleteJob(t *testing.T) { lggr := logger.TestLogger(t) orm := NewTestORM(t, db, pipeline.NewORM(db, lggr, config.JobPipeline().MaxSuccessfulRuns()), bridges.NewORM(db), keyStore) mailMon := servicetest.Run(t, mailboxtest.NewMonitor(t)) - d := ocr.NewDelegate(nil, orm, nil, nil, nil, monitoringEndpoint, legacyChains, logger.TestLogger(t), config, mailMon) + d := ocr.NewDelegate(nil, orm, nil, nil, nil, nil, monitoringEndpoint, legacyChains, logger.TestLogger(t), config, mailMon) delegateA := &delegate{jobA.Type, []job.ServiceCtx{serviceA1, serviceA2}, 0, nil, d} spawner := job.NewSpawner(orm, config.Database(), noopChecker{}, map[job.Type]job.Delegate{ jobA.Type: delegateA, @@ -235,7 +236,7 @@ func TestSpawner_CreateJobDeleteJob(t *testing.T) { lggr := logger.TestLogger(t) orm := NewTestORM(t, db, pipeline.NewORM(db, lggr, config.JobPipeline().MaxSuccessfulRuns()), bridges.NewORM(db), keyStore) mailMon := servicetest.Run(t, mailboxtest.NewMonitor(t)) - d := ocr.NewDelegate(nil, orm, nil, nil, nil, monitoringEndpoint, legacyChains, logger.TestLogger(t), config, mailMon) + d := ocr.NewDelegate(nil, orm, nil, nil, nil, nil, monitoringEndpoint, legacyChains, logger.TestLogger(t), config, mailMon) delegateA := &delegate{jobA.Type, []job.ServiceCtx{serviceA1, serviceA2}, 0, nil, d} spawner := job.NewSpawner(orm, config.Database(), noopChecker{}, map[job.Type]job.Delegate{ jobA.Type: delegateA, @@ -283,15 +284,17 @@ func TestSpawner_CreateJobDeleteJob(t *testing.T) { c.Feature.LogPoller = func(b bool) *bool { return &b }(true) }) lp := &mocklp.LogPoller{} + + csaKeystore := &keystore.CSASigner{CSA: keyStore.CSA()} testopts := evmtest.TestChainOpts{ DB: db, Client: ethClient, ChainConfigs: config.EVMConfigs(), DatabaseConfig: config.Database(), + KeyStore: keyStore.Eth(), FeatureConfig: config.Feature(), ListenerConfig: config.Database().Listener(), LogPoller: lp, - KeyStore: ethKeyStore, } lggr := logger.TestLogger(t) @@ -299,9 +302,10 @@ func TestSpawner_CreateJobDeleteJob(t *testing.T) { assert.Equal(t, legacyChains.Len(), 1) chain := evmtest.MustGetDefaultChain(t, legacyChains) - evmRelayer, err := evmrelayer.NewRelayer(ctx, lggr, chain, evmrelayer.RelayerOpts{ + evmRelayer, err := evmrelayer.NewRelayer(lggr, chain, evmrelayer.RelayerOpts{ DS: db, - CSAETHKeystore: keyStore, + EVMKeystore: keystore.NewEthSigner(keyStore.Eth(), chain.ID()), + CSAKeystore: csaKeystore, CapabilitiesRegistry: capabilities.NewRegistry(lggr), }) assert.NoError(t, err) @@ -318,7 +322,7 @@ func TestSpawner_CreateJobDeleteJob(t *testing.T) { processConfig := plugins.NewRegistrarConfig(loop.GRPCOpts{}, func(name string) (*plugins.RegisteredLoop, error) { return nil, nil }, func(loopId string) {}) ocr2DelegateConfig := ocr2.NewDelegateConfig(config.OCR2(), config.Mercury(), config.Threshold(), config.Insecure(), config.JobPipeline(), processConfig) - d := ocr2.NewDelegate(ocr2.DelegateOpts{JobORM: orm, MonitoringEndpointGen: monitoringEndpoint, LegacyChains: legacyChains, Lggr: lggr, Ks: keyStore.OCR2(), EthKs: ethKeyStore, Relayers: testRelayGetter, MailMon: mailMon, CapabilitiesRegistry: capabilities.NewRegistry(lggr)}, ocr2DelegateConfig) + d := ocr2.NewDelegate(ocr2.DelegateOpts{JobORM: orm, MonitoringEndpointGen: monitoringEndpoint, LegacyChains: legacyChains, Lggr: lggr, Ks: keyStore.OCR2(), EthKs: keyStore.Eth(), Relayers: testRelayGetter, MailMon: mailMon, CapabilitiesRegistry: capabilities.NewRegistry(lggr)}, ocr2DelegateConfig) delegateOCR2 := &delegate{jobOCR2Keeper.Type, []job.ServiceCtx{}, 0, nil, d} spawner := job.NewSpawner(orm, config.Database(), noopChecker{}, map[job.Type]job.Delegate{ diff --git a/core/services/keystore/beholder.go b/core/services/keystore/beholder.go index 40655cf0e82..940881c083c 100644 --- a/core/services/keystore/beholder.go +++ b/core/services/keystore/beholder.go @@ -1,17 +1,17 @@ package keystore import ( + "context" "encoding/hex" "github.com/smartcontractkit/chainlink-common/pkg/beholder" ) -func BuildBeholderAuth(keyStore Master) (authHeaders map[string]string, pubKeyHex string, err error) { - csaKeys, err := keyStore.CSA().GetAll() +func BuildBeholderAuth(ctx context.Context, keyStore CSA) (authHeaders map[string]string, pubKeyHex string, err error) { + csaKey, err := GetDefault(ctx, keyStore) if err != nil { return nil, "", err } - csaKey := csaKeys[0] csaPrivKey := csaKey.Raw().Bytes() authHeaders = beholder.BuildAuthHeaders(csaPrivKey) pubKeyHex = hex.EncodeToString(csaKey.PublicKey) diff --git a/core/services/keystore/cosmos.go b/core/services/keystore/cosmos.go index 43370daab45..59e09d47d21 100644 --- a/core/services/keystore/cosmos.go +++ b/core/services/keystore/cosmos.go @@ -145,15 +145,15 @@ func (ks *cosmos) getByID(id string) (cosmoskey.Key, error) { return key, nil } -// CosmosLoopKeystore implements the [github.com/smartcontractkit/chainlink-common/pkg/loop.Keystore] interface and +// CosmosLoopSigner implements the [github.com/smartcontractkit/chainlink-common/pkg/loop.Keystore] interface and // handles signing for Cosmos messages. -type CosmosLoopKeystore struct { +type CosmosLoopSigner struct { Cosmos } -var _ loop.Keystore = &CosmosLoopKeystore{} +var _ loop.Keystore = &CosmosLoopSigner{} -func (lk *CosmosLoopKeystore) Sign(ctx context.Context, id string, hash []byte) ([]byte, error) { +func (lk *CosmosLoopSigner) Sign(ctx context.Context, id string, hash []byte) ([]byte, error) { k, err := lk.Get(id) if err != nil { return nil, err @@ -166,7 +166,7 @@ func (lk *CosmosLoopKeystore) Sign(ctx context.Context, id string, hash []byte) return k.ToPrivKey().Sign(hash) } -func (lk *CosmosLoopKeystore) Accounts(ctx context.Context) ([]string, error) { +func (lk *CosmosLoopSigner) Accounts(ctx context.Context) ([]string, error) { keys, err := lk.GetAll() if err != nil { return nil, err @@ -174,7 +174,7 @@ func (lk *CosmosLoopKeystore) Accounts(ctx context.Context) ([]string, error) { accounts := []string{} for _, k := range keys { - accounts = append(accounts, k.PublicKeyStr()) + accounts = append(accounts, k.ID()) } return accounts, nil diff --git a/core/services/keystore/csa.go b/core/services/keystore/csa.go index 004ec2bf373..a5af50ad666 100644 --- a/core/services/keystore/csa.go +++ b/core/services/keystore/csa.go @@ -2,17 +2,19 @@ package keystore import ( "context" + "crypto" + "crypto/rand" "fmt" "github.com/pkg/errors" + "github.com/smartcontractkit/chainlink-common/pkg/loop" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/csakey" ) // ErrCSAKeyExists describes the error when the CSA key already exists var ErrCSAKeyExists = errors.New("can only have 1 CSA key") -// type CSAKeystoreInterface interface { type CSA interface { Get(id string) (csakey.KeyV2, error) GetAll() ([]csakey.KeyV2, error) @@ -24,6 +26,35 @@ type CSA interface { EnsureKey(ctx context.Context) error } +var _ loop.Keystore = &CSASigner{} + +type CSASigner struct { + CSA +} + +func (c CSASigner) Accounts(ctx context.Context) (accounts []string, err error) { + keys, err := c.CSA.GetAll() + if err != nil { + return nil, err + } + for _, key := range keys { + accounts = append(accounts, key.ID()) + } + return +} + +func (c CSASigner) Sign(ctx context.Context, account string, data []byte) (signed []byte, err error) { + k, err := c.CSA.Get(account) + if err != nil { + return nil, err + } + // loopp spec requires passing nil hash to check existence of id + if data == nil { + return nil, nil + } + return k.PrivateKey().Sign(rand.Reader, data, crypto.Hash(0)) +} + type csa struct { *keyManager } diff --git a/core/services/keystore/eth.go b/core/services/keystore/eth.go index 8d5e5bf78be..182545dd426 100644 --- a/core/services/keystore/eth.go +++ b/core/services/keystore/eth.go @@ -15,7 +15,9 @@ import ( "github.com/ethereum/go-ethereum/crypto" "github.com/pkg/errors" + "github.com/smartcontractkit/chainlink-common/pkg/loop" "github.com/smartcontractkit/chainlink-common/pkg/sqlutil" + evmkeystore "github.com/smartcontractkit/chainlink-integrations/evm/keys" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -48,38 +50,69 @@ type Eth interface { GetStateForKey(ctx context.Context, key ethkey.KeyV2) (ethkey.State, error) GetStatesForChain(ctx context.Context, chainID *big.Int) ([]ethkey.State, error) EnabledAddressesForChain(ctx context.Context, chainID *big.Int) (addresses []common.Address, err error) - GetResourceMutex(ctx context.Context, address common.Address) (*ResourceMutex, error) + GetResourceMutex(ctx context.Context, address common.Address) *evmkeystore.Mutex XXXTestingOnlySetState(ctx context.Context, keyState ethkey.State) XXXTestingOnlyAdd(ctx context.Context, key ethkey.KeyV2) } +var _ loop.Keystore = &EthSigner{} + +type EthSigner struct { + Eth + chainID *big.Int +} + +func NewEthSigner(eth Eth, chainID *big.Int) *EthSigner { + return &EthSigner{Eth: eth, chainID: chainID} +} + +func (e *EthSigner) Accounts(ctx context.Context) (accounts []string, err error) { + as, err := e.EnabledAddressesForChain(ctx, e.chainID) + if err != nil { + return nil, err + } + for _, a := range as { + accounts = append(accounts, a.String()) + } + return +} + +func (e *EthSigner) Sign(ctx context.Context, account string, data []byte) (signed []byte, err error) { + k, err := e.Get(ctx, account) + if err != nil { + return nil, err + } + // loopp spec requires passing nil hash to check existence of id + if data == nil { + return nil, nil + } + return crypto.Sign(data, k.ToEcdsaPrivKey()) +} + type eth struct { *keyManager keystateORM ds sqlutil.DataSource subscribers [](chan struct{}) subscribersMu *sync.RWMutex - resourceMutex map[common.Address]*ResourceMutex // ResourceMutex is an internal field and ought not be persisted to the database. Its main usage is to verify that the same key is not used for both TXMv1 and TXMv2 (usage in both TXMs will cause nonce drift and will lead to missing transactions). This functionality should be removed after we completely switch to TXMv2 + resourceMutex map[common.Address]*evmkeystore.Mutex // ResourceMutex is an internal field and ought not be persisted to the database. Its main usage is to verify that the same key is not used for both TXMv1 and TXMv2 (usage in both TXMs will cause nonce drift and will lead to missing transactions). This functionality should be removed after we completely switch to TXMv2 } // GetResourceMutex gets the resource mutex associates with the address if no resource mutex is found a new one is created -func (ks *eth) GetResourceMutex(ctx context.Context, address common.Address) (*ResourceMutex, error) { +func (ks *eth) GetResourceMutex(ctx context.Context, address common.Address) *evmkeystore.Mutex { ks.lock.Lock() defer ks.lock.Unlock() - if ks.isLocked() { - return nil, ErrLocked - } if ks.resourceMutex == nil { - ks.resourceMutex = make(map[common.Address]*ResourceMutex) + ks.resourceMutex = make(map[common.Address]*evmkeystore.Mutex) } _, exists := ks.resourceMutex[address] if !exists { - ks.resourceMutex[address] = NewResourceMutex() + ks.resourceMutex[address] = &evmkeystore.Mutex{} } - return ks.resourceMutex[address], nil + return ks.resourceMutex[address] } var _ Eth = ð{} diff --git a/core/services/keystore/keystore.go b/core/services/keystore/keystore.go new file mode 100644 index 00000000000..9a8ee409135 --- /dev/null +++ b/core/services/keystore/keystore.go @@ -0,0 +1,26 @@ +package keystore + +import ( + "context" + "fmt" +) + +type getDefault[K any] interface { + EnsureKey(context.Context) error + GetAll() ([]K, error) +} + +func GetDefault[K any, KS getDefault[K]](ctx context.Context, ks KS) (K, error) { + var zero K + if err := ks.EnsureKey(ctx); err != nil { + return zero, fmt.Errorf("failed to ensure %T key", zero) + } + keys, err := ks.GetAll() + if err != nil { + return zero, err + } + if len(keys) < 1 { + return zero, fmt.Errorf("no %T keys available", zero) + } + return keys[0], nil +} diff --git a/core/services/keystore/mocks/eth.go b/core/services/keystore/mocks/eth.go index c56808f9933..12c0a25fa7d 100644 --- a/core/services/keystore/mocks/eth.go +++ b/core/services/keystore/mocks/eth.go @@ -10,7 +10,7 @@ import ( ethkey "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" - keystore "github.com/smartcontractkit/chainlink/v2/core/services/keystore" + keys "github.com/smartcontractkit/chainlink-integrations/evm/keys" mock "github.com/stretchr/testify/mock" @@ -458,8 +458,8 @@ func (_c *Eth_EnabledKeysForChain_Call) Run(run func(ctx context.Context, chainI return _c } -func (_c *Eth_EnabledKeysForChain_Call) Return(keys []ethkey.KeyV2, err error) *Eth_EnabledKeysForChain_Call { - _c.Call.Return(keys, err) +func (_c *Eth_EnabledKeysForChain_Call) Return(_a0 []ethkey.KeyV2, err error) *Eth_EnabledKeysForChain_Call { + _c.Call.Return(_a0, err) return _c } @@ -705,33 +705,23 @@ func (_c *Eth_GetAll_Call) RunAndReturn(run func(context.Context) ([]ethkey.KeyV } // GetResourceMutex provides a mock function with given fields: ctx, address -func (_m *Eth) GetResourceMutex(ctx context.Context, address common.Address) (*keystore.ResourceMutex, error) { +func (_m *Eth) GetResourceMutex(ctx context.Context, address common.Address) *keys.Mutex { ret := _m.Called(ctx, address) if len(ret) == 0 { panic("no return value specified for GetResourceMutex") } - var r0 *keystore.ResourceMutex - var r1 error - if rf, ok := ret.Get(0).(func(context.Context, common.Address) (*keystore.ResourceMutex, error)); ok { - return rf(ctx, address) - } - if rf, ok := ret.Get(0).(func(context.Context, common.Address) *keystore.ResourceMutex); ok { + var r0 *keys.Mutex + if rf, ok := ret.Get(0).(func(context.Context, common.Address) *keys.Mutex); ok { r0 = rf(ctx, address) } else { if ret.Get(0) != nil { - r0 = ret.Get(0).(*keystore.ResourceMutex) + r0 = ret.Get(0).(*keys.Mutex) } } - if rf, ok := ret.Get(1).(func(context.Context, common.Address) error); ok { - r1 = rf(ctx, address) - } else { - r1 = ret.Error(1) - } - - return r0, r1 + return r0 } // Eth_GetResourceMutex_Call is a *mock.Call that shadows Run/Return methods with type explicit version for method 'GetResourceMutex' @@ -753,12 +743,12 @@ func (_c *Eth_GetResourceMutex_Call) Run(run func(ctx context.Context, address c return _c } -func (_c *Eth_GetResourceMutex_Call) Return(_a0 *keystore.ResourceMutex, _a1 error) *Eth_GetResourceMutex_Call { - _c.Call.Return(_a0, _a1) +func (_c *Eth_GetResourceMutex_Call) Return(_a0 *keys.Mutex) *Eth_GetResourceMutex_Call { + _c.Call.Return(_a0) return _c } -func (_c *Eth_GetResourceMutex_Call) RunAndReturn(run func(context.Context, common.Address) (*keystore.ResourceMutex, error)) *Eth_GetResourceMutex_Call { +func (_c *Eth_GetResourceMutex_Call) RunAndReturn(run func(context.Context, common.Address) *keys.Mutex) *Eth_GetResourceMutex_Call { _c.Call.Return(run) return _c } @@ -1011,9 +1001,9 @@ func (_c *Eth_GetStatesForChain_Call) RunAndReturn(run func(context.Context, *bi return _c } -// GetStatesForKeys provides a mock function with given fields: ctx, keys -func (_m *Eth) GetStatesForKeys(ctx context.Context, keys []ethkey.KeyV2) ([]ethkey.State, error) { - ret := _m.Called(ctx, keys) +// GetStatesForKeys provides a mock function with given fields: ctx, _a1 +func (_m *Eth) GetStatesForKeys(ctx context.Context, _a1 []ethkey.KeyV2) ([]ethkey.State, error) { + ret := _m.Called(ctx, _a1) if len(ret) == 0 { panic("no return value specified for GetStatesForKeys") @@ -1022,10 +1012,10 @@ func (_m *Eth) GetStatesForKeys(ctx context.Context, keys []ethkey.KeyV2) ([]eth var r0 []ethkey.State var r1 error if rf, ok := ret.Get(0).(func(context.Context, []ethkey.KeyV2) ([]ethkey.State, error)); ok { - return rf(ctx, keys) + return rf(ctx, _a1) } if rf, ok := ret.Get(0).(func(context.Context, []ethkey.KeyV2) []ethkey.State); ok { - r0 = rf(ctx, keys) + r0 = rf(ctx, _a1) } else { if ret.Get(0) != nil { r0 = ret.Get(0).([]ethkey.State) @@ -1033,7 +1023,7 @@ func (_m *Eth) GetStatesForKeys(ctx context.Context, keys []ethkey.KeyV2) ([]eth } if rf, ok := ret.Get(1).(func(context.Context, []ethkey.KeyV2) error); ok { - r1 = rf(ctx, keys) + r1 = rf(ctx, _a1) } else { r1 = ret.Error(1) } @@ -1048,12 +1038,12 @@ type Eth_GetStatesForKeys_Call struct { // GetStatesForKeys is a helper method to define mock.On call // - ctx context.Context -// - keys []ethkey.KeyV2 -func (_e *Eth_Expecter) GetStatesForKeys(ctx interface{}, keys interface{}) *Eth_GetStatesForKeys_Call { - return &Eth_GetStatesForKeys_Call{Call: _e.mock.On("GetStatesForKeys", ctx, keys)} +// - _a1 []ethkey.KeyV2 +func (_e *Eth_Expecter) GetStatesForKeys(ctx interface{}, _a1 interface{}) *Eth_GetStatesForKeys_Call { + return &Eth_GetStatesForKeys_Call{Call: _e.mock.On("GetStatesForKeys", ctx, _a1)} } -func (_c *Eth_GetStatesForKeys_Call) Run(run func(ctx context.Context, keys []ethkey.KeyV2)) *Eth_GetStatesForKeys_Call { +func (_c *Eth_GetStatesForKeys_Call) Run(run func(ctx context.Context, _a1 []ethkey.KeyV2)) *Eth_GetStatesForKeys_Call { _c.Call.Run(func(args mock.Arguments) { run(args[0].(context.Context), args[1].([]ethkey.KeyV2)) }) diff --git a/core/services/keystore/models.go b/core/services/keystore/models.go index 55a1c847816..1ebc7480997 100644 --- a/core/services/keystore/models.go +++ b/core/services/keystore/models.go @@ -4,7 +4,6 @@ import ( "encoding/json" "fmt" "math/big" - "sync" "time" gethkeystore "github.com/ethereum/go-ethereum/accounts/keystore" @@ -424,70 +423,3 @@ func (rawKeys rawKeyRing) keys() (*keyRing, error) { func adulteratedPassword(password string) string { return "master-password-" + password } - -type ResourceMutex struct { - mu sync.Mutex - serviceType ServiceType - count int // Tracks active users per service type -} -type ServiceType int - -const ( - TXMv1 ServiceType = iota - TXMv2 -) - -// TryLock attempts to lock the resource for the specified service type. -// It returns an error if the resource is locked by a different service type. -func (rm *ResourceMutex) TryLock(serviceType ServiceType) error { - rm.mu.Lock() - defer rm.mu.Unlock() - - if rm.count == 0 { - rm.serviceType = serviceType - } - - // Check if other service types are using the resource - if rm.serviceType != serviceType && rm.count > 0 { - return errors.New("resource is locked by another service type") - } - - // Increment active count for the current service type - rm.count++ - return nil -} - -// Unlock releases the lock for the service type -func (rm *ResourceMutex) Unlock(serviceType ServiceType) error { - rm.mu.Lock() - defer rm.mu.Unlock() - - // Check if the service type has an active lock - if rm.count == 0 { - return errors.New("no active lock") - } - - if rm.serviceType != serviceType { - return errors.New("no active lock for this service type") - } - - // Decrement active count for the service type - rm.count-- - return nil -} - -// IsLocked checks if the resource is locked by a specific service type. -func (rm *ResourceMutex) IsLocked(serviceType ServiceType) (bool, error) { - rm.mu.Lock() - defer rm.mu.Unlock() - - if rm.count == 0 || rm.serviceType != serviceType { - return false, nil - } - - return true, nil -} - -func NewResourceMutex() *ResourceMutex { - return &ResourceMutex{} -} diff --git a/core/services/keystore/models_test.go b/core/services/keystore/models_test.go index e4a2058b569..a66e29865d1 100644 --- a/core/services/keystore/models_test.go +++ b/core/services/keystore/models_test.go @@ -161,77 +161,3 @@ func TestKeyRing_Encrypt_Decrypt(t *testing.T) { require.Error(t, err) }) } - -func TestResourceMutex_LockUnlock(t *testing.T) { - rm := &ResourceMutex{} - - err := rm.TryLock(TXMv1) - require.NoError(t, err) - - err = rm.Unlock(TXMv1) - require.NoError(t, err) -} - -func TestResourceMutex_LockByDifferentServiceType(t *testing.T) { - rm := &ResourceMutex{} - - err := rm.TryLock(TXMv1) - require.NoError(t, err) - - err = rm.TryLock(TXMv2) - require.Error(t, err) - require.Equal(t, "resource is locked by another service type", err.Error()) -} - -func TestResourceMutex_UnlockWithoutLock(t *testing.T) { - rm := &ResourceMutex{} - - err := rm.Unlock(TXMv1) - require.Error(t, err) - require.Equal(t, "no active lock", err.Error()) - - require.NoError(t, rm.TryLock(TXMv1)) - err = rm.Unlock(TXMv2) - require.Error(t, err) - require.Equal(t, "no active lock for this service type", err.Error()) -} - -func TestResourceMutex_MultipleLocks(t *testing.T) { - rm := &ResourceMutex{} - - err := rm.TryLock(TXMv1) - require.NoError(t, err) - - err = rm.TryLock(TXMv1) - require.NoError(t, err) - - err = rm.Unlock(TXMv1) - require.NoError(t, err) - - err = rm.Unlock(TXMv1) - require.NoError(t, err) -} - -func TestIsLocked_WhenResourceIsLockedByServiceType(t *testing.T) { - rm := &ResourceMutex{serviceType: TXMv1, count: 1} - - locked, err := rm.IsLocked(TXMv1) - require.NoError(t, err) - require.True(t, locked) -} - -func TestIsLocked_WhenResourceIsNotLockedByServiceType(t *testing.T) { - rm := &ResourceMutex{} - - locked, err := rm.IsLocked(TXMv1) - require.NoError(t, err) - require.False(t, locked) -} - -func TestIsLocked_WhenResourceIsLockedByDifferentServiceType(t *testing.T) { - rm := &ResourceMutex{serviceType: TXMv2, count: 1} - - locked, err := rm.IsLocked(TXMv1) - require.NoError(t, err) - require.False(t, locked) -} diff --git a/core/services/keystore/solana.go b/core/services/keystore/solana.go index 5391ef6d2e7..829f2a84ad0 100644 --- a/core/services/keystore/solana.go +++ b/core/services/keystore/solana.go @@ -22,20 +22,20 @@ type Solana interface { Sign(ctx context.Context, id string, msg []byte) (signature []byte, err error) } -// SolanaSigner adapts Solana to [loop.Keystore]. -type SolanaSigner struct { +// SolanaLooppSigner adapts Solana to [core.Keystore]. +type SolanaLooppSigner struct { Solana } -var _ loop.Keystore = &SolanaSigner{} +var _ loop.Keystore = &SolanaLooppSigner{} -func (s *SolanaSigner) Accounts(ctx context.Context) (accounts []string, err error) { +func (s *SolanaLooppSigner) Accounts(ctx context.Context) (accounts []string, err error) { ks, err := s.GetAll() if err != nil { return nil, err } for _, k := range ks { - accounts = append(accounts, k.PublicKeyStr()) + accounts = append(accounts, k.ID()) } return } diff --git a/core/services/keystore/starknet.go b/core/services/keystore/starknet.go index 1aa213b86e9..b78be446a10 100644 --- a/core/services/keystore/starknet.go +++ b/core/services/keystore/starknet.go @@ -189,7 +189,14 @@ func (lk *StarknetLooppSigner) Sign(ctx context.Context, id string, hash []byte) return sig.Bytes() } -// TODO what is this supposed to return for starknet? func (lk *StarknetLooppSigner) Accounts(ctx context.Context) ([]string, error) { - return nil, fmt.Errorf("unimplemented") + ks, err := lk.GetAll() + if err != nil { + return nil, err + } + as := make([]string, 0, len(ks)) + for _, k := range ks { + as = append(as, k.ID()) + } + return as, nil } diff --git a/core/services/keystore/tron.go b/core/services/keystore/tron.go index d5302d572b0..5fd5d041bbd 100644 --- a/core/services/keystore/tron.go +++ b/core/services/keystore/tron.go @@ -164,15 +164,15 @@ func (ks *tron) Sign(_ context.Context, id string, msg []byte) (signature []byte return k.Sign(msg) } -// TronLOOPKeystore implements the [github.com/smartcontractkit/chainlink-common/pkg/loop.Keystore] interface and +// TronLOOPSigner implements the [github.com/smartcontractkit/chainlink-common/pkg/loop.Keystore] interface and // handles signing for Tron messages. -type TronLOOPKeystore struct { +type TronLOOPSigner struct { Tron } -var _ loop.Keystore = &TronLOOPKeystore{} +var _ loop.Keystore = &TronLOOPSigner{} -func (lk *TronLOOPKeystore) Accounts(ctx context.Context) ([]string, error) { +func (lk *TronLOOPSigner) Accounts(ctx context.Context) ([]string, error) { keys, err := lk.GetAll() if err != nil { return nil, err @@ -180,7 +180,7 @@ func (lk *TronLOOPKeystore) Accounts(ctx context.Context) ([]string, error) { accounts := []string{} for _, k := range keys { - accounts = append(accounts, k.PublicKeyStr()) + accounts = append(accounts, k.ID()) } return accounts, nil diff --git a/core/services/llo/grpc/client.go b/core/services/llo/grpc/client.go index d1fb6af129b..7236bedaa29 100644 --- a/core/services/llo/grpc/client.go +++ b/core/services/llo/grpc/client.go @@ -2,6 +2,7 @@ package grpc import ( "context" + "crypto" "crypto/ed25519" "encoding/hex" "errors" @@ -31,7 +32,7 @@ type client struct { services.Service eng *services.Engine - clientPrivKey ed25519.PrivateKey + clientSigner crypto.Signer clientPubKeyHex string serverPubKey ed25519.PublicKey serverURL string @@ -41,10 +42,10 @@ type client struct { } type ClientOpts struct { - Logger logger.Logger - ClientPrivKey ed25519.PrivateKey - ServerPubKey ed25519.PublicKey - ServerURL string + Logger logger.Logger + ClientSigner crypto.Signer + ServerPubKey ed25519.PublicKey + ServerURL string } func NewClient(opts ClientOpts) Client { @@ -53,8 +54,8 @@ func NewClient(opts ClientOpts) Client { func newClient(opts ClientOpts) Client { c := &client{ - clientPrivKey: opts.ClientPrivKey, - clientPubKeyHex: hex.EncodeToString(opts.ClientPrivKey.Public().(ed25519.PublicKey)), + clientSigner: opts.ClientSigner, + clientPubKeyHex: hex.EncodeToString(opts.ClientSigner.Public().(ed25519.PublicKey)), serverPubKey: opts.ServerPubKey, serverURL: opts.ServerURL, } @@ -67,7 +68,7 @@ func newClient(opts ClientOpts) Client { } func (c *client) start(context.Context) error { - cMtls, err := mtls.NewTransportCredentials(c.clientPrivKey, []ed25519.PublicKey{c.serverPubKey}) + cMtls, err := mtls.NewTransportSigner(c.clientSigner, []ed25519.PublicKey{c.serverPubKey}) if err != nil { return fmt.Errorf("failed to create client mTLS credentials: %w", err) } diff --git a/core/services/llo/grpc/client_test.go b/core/services/llo/grpc/client_test.go index a7fa8a55145..7c8ed279fd2 100644 --- a/core/services/llo/grpc/client_test.go +++ b/core/services/llo/grpc/client_test.go @@ -27,10 +27,10 @@ func Test_Client(t *testing.T) { t.Run("Transmit errors if not started", func(t *testing.T) { c := NewClient(ClientOpts{ - Logger: logger.TestLogger(t), - ClientPrivKey: clientPrivKey, - ServerPubKey: serverPrivKey.Public().(ed25519.PublicKey), - ServerURL: "example.com", + Logger: logger.TestLogger(t), + ClientSigner: clientPrivKey, + ServerPubKey: serverPrivKey.Public().(ed25519.PublicKey), + ServerURL: "example.com", }) resp, err := c.Transmit(tests.Context(t), &rpc.TransmitRequest{}) @@ -43,10 +43,10 @@ func Test_Client(t *testing.T) { serverURL := srv.start(t, []ed25519.PublicKey{clientPrivKey.Public().(ed25519.PublicKey)}) c := NewClient(ClientOpts{ - Logger: logger.TestLogger(t), - ClientPrivKey: clientPrivKey, - ServerPubKey: serverPrivKey.Public().(ed25519.PublicKey), - ServerURL: serverURL, + Logger: logger.TestLogger(t), + ClientSigner: clientPrivKey, + ServerPubKey: serverPrivKey.Public().(ed25519.PublicKey), + ServerURL: serverURL, }) servicetest.Run(t, c) diff --git a/core/services/llo/mercurytransmitter/transmitter.go b/core/services/llo/mercurytransmitter/transmitter.go index 654768e97ed..c751485920d 100644 --- a/core/services/llo/mercurytransmitter/transmitter.go +++ b/core/services/llo/mercurytransmitter/transmitter.go @@ -2,7 +2,6 @@ package mercurytransmitter import ( "context" - "crypto/ed25519" "crypto/sha256" "encoding/binary" "errors" @@ -18,14 +17,14 @@ import ( "github.com/smartcontractkit/libocr/offchainreporting2plus/types" ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - "github.com/smartcontractkit/chainlink/v2/core/config" - "github.com/smartcontractkit/chainlink/v2/core/services/llo/grpc" - commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/services" coretypes "github.com/smartcontractkit/chainlink-common/pkg/types/core" llotypes "github.com/smartcontractkit/chainlink-common/pkg/types/llo" + + "github.com/smartcontractkit/chainlink/v2/core/config" + "github.com/smartcontractkit/chainlink/v2/core/services/llo/grpc" ) const ( @@ -131,7 +130,7 @@ type Opts struct { VerboseLogging bool Cfg Config Clients map[string]grpc.Client - FromAccount ed25519.PublicKey + FromAccount string DonID uint32 ORM ORM CapabilitiesRegistry coretypes.CapabilitiesRegistry @@ -156,7 +155,7 @@ func newTransmitter(opts Opts) *transmitter { opts.ORM, servers, opts.DonID, - fmt.Sprintf("%x", opts.FromAccount), + opts.FromAccount, make(services.StopChan), &sync.WaitGroup{}, } diff --git a/core/services/llo/mercurytransmitter/transmitter_test.go b/core/services/llo/mercurytransmitter/transmitter_test.go index 3769a4f247b..0d45ffacff6 100644 --- a/core/services/llo/mercurytransmitter/transmitter_test.go +++ b/core/services/llo/mercurytransmitter/transmitter_test.go @@ -3,6 +3,7 @@ package mercurytransmitter import ( "context" "crypto/ed25519" + "encoding/hex" "sync" "testing" "time" @@ -72,7 +73,7 @@ func Test_Transmitter_Transmit(t *testing.T) { Lggr: lggr, Cfg: mockCfg{}, Clients: clients, - FromAccount: ed25519.PublicKey{}, + FromAccount: hex.EncodeToString(ed25519.PublicKey{}), DonID: donID, ORM: orm, }) @@ -100,7 +101,7 @@ func Test_Transmitter_Transmit(t *testing.T) { Lggr: lggr, Cfg: mockCfg{}, Clients: clients, - FromAccount: ed25519.PublicKey{}, + FromAccount: hex.EncodeToString(ed25519.PublicKey{}), DonID: donID, ORM: orm, }) diff --git a/core/services/ocr/delegate.go b/core/services/ocr/delegate.go index 2c3851f2095..a9e22a09ba3 100644 --- a/core/services/ocr/delegate.go +++ b/core/services/ocr/delegate.go @@ -16,8 +16,8 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/sqlutil" "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox" - txmgrcommon "github.com/smartcontractkit/chainlink-framework/chains/txmgr" + "github.com/smartcontractkit/chainlink-integrations/evm/keys" "github.com/smartcontractkit/chainlink-integrations/evm/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" @@ -35,7 +35,8 @@ import ( type Delegate struct { ds sqlutil.DataSource jobORM job.ORM - keyStore keystore.Master + ethKeyStore keystore.Eth + ocrKeyStore keystore.OCR pipelineRunner pipeline.Runner peerWrapper *ocrcommon.SingletonPeerWrapper monitoringEndpointGen telemetry.MonitoringEndpointGenerator @@ -52,7 +53,8 @@ const ConfigOverriderPollInterval = 30 * time.Second func NewDelegate( ds sqlutil.DataSource, jobORM job.ORM, - keyStore keystore.Master, + ethKeyStore keystore.Eth, + ocrKeyStore keystore.OCR, pipelineRunner pipeline.Runner, peerWrapper *ocrcommon.SingletonPeerWrapper, monitoringEndpointGen telemetry.MonitoringEndpointGenerator, @@ -64,7 +66,8 @@ func NewDelegate( return &Delegate{ ds: ds, jobORM: jobORM, - keyStore: keyStore, + ethKeyStore: ethKeyStore, + ocrKeyStore: ocrKeyStore, pipelineRunner: pipelineRunner, peerWrapper: peerWrapper, monitoringEndpointGen: monitoringEndpointGen, @@ -186,7 +189,7 @@ func (d *Delegate) ServicesForSpec(ctx context.Context, jb job.Job) (services [] return nil, errors.New("Need at least one v2 bootstrap peer defined") } - ocrkey, err := d.keyStore.OCR().Get(concreteSpec.EncryptedOCRKeyBundleID.String()) + ocrkey, err := d.ocrKeyStore.Get(concreteSpec.EncryptedOCRKeyBundleID.String()) if err != nil { return nil, err } @@ -224,6 +227,9 @@ func (d *Delegate) ServicesForSpec(ctx context.Context, jb job.Job) (services [] } } + cid := chain.ID() + ks := keys.NewChainStore(keystore.NewEthSigner(d.ethKeyStore, cid), cid) + transmitter, err := ocrcommon.NewTransmitter( chain.TxManager(), []common.Address{concreteSpec.TransmitterAddress.Address()}, @@ -231,8 +237,7 @@ func (d *Delegate) ServicesForSpec(ctx context.Context, jb job.Job) (services [] effectiveTransmitterAddress, strategy, checker, - chain.ID(), - d.keyStore.Eth(), + ks, ) if err != nil { return nil, errors.Wrap(err, "failed to create transmitter") diff --git a/core/services/ocr2/delegate.go b/core/services/ocr2/delegate.go index e2e119651c1..988d15a7eac 100644 --- a/core/services/ocr2/delegate.go +++ b/core/services/ocr2/delegate.go @@ -40,6 +40,7 @@ import ( llotypes "github.com/smartcontractkit/chainlink-common/pkg/types/llo" "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox" datastreamsllo "github.com/smartcontractkit/chainlink-data-streams/llo" + "github.com/smartcontractkit/chainlink-integrations/evm/keys" "github.com/smartcontractkit/chainlink/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" @@ -1350,7 +1351,9 @@ func (d *Delegate) newServicesOCR2Keepers20( return nil, fmt.Errorf("keepers2.0 services: failed to get chain (%s): %w", rid.ChainID, err2) } - keeperProvider, rgstry, encoder, logProvider, err2 := ocr2keeper.EVMDependencies20(ctx, jb, d.ds, lggr, chain, d.ethKs) + cid := chain.ID() + ks := keys.NewChainStore(keystore.NewEthSigner(d.ethKs, cid), cid) + keeperProvider, rgstry, encoder, logProvider, err2 := ocr2keeper.EVMDependencies20(ctx, jb, d.ds, lggr, chain, ks) if err2 != nil { return nil, errors.Wrap(err2, "could not build dependencies for ocr2 keepers") } @@ -1477,6 +1480,8 @@ func (d *Delegate) newServicesOCR2Functions( if err != nil { return nil, fmt.Errorf("functions services: failed to get chain %s: %w", rid.ChainID, err) } + cid := chain.ID() + ks := keys.NewChainStore(keystore.NewEthSigner(d.ethKs, cid), cid) createPluginProvider := func(pluginType functionsRelay.FunctionsPluginType, relayerName string) (evmrelaytypes.FunctionsProvider, error) { return evmrelay.NewFunctionsProvider( ctx, @@ -1493,7 +1498,7 @@ func (d *Delegate) newServicesOCR2Functions( PluginConfig: spec.PluginConfig.Bytes(), }, lggr.Named(relayerName), - d.ethKs, + ks, pluginType, ) } @@ -1592,7 +1597,7 @@ func (d *Delegate) newServicesOCR2Functions( Logger: lggr, MailMon: d.mailMon, URLsMonEndpoint: d.monitoringEndpointGen.GenMonitoringEndpoint(rid.Network, rid.ChainID, spec.ContractID, synchronization.FunctionsRequests), - EthKeystore: d.ethKs, + EthKeystore: ks, ThresholdKeyShare: thresholdKeyShare, LogPollerWrapper: functionsProvider.LogPollerWrapper(), } diff --git a/core/services/ocr2/plugins/ccip/testhelpers/integration/chainlink.go b/core/services/ocr2/plugins/ccip/testhelpers/integration/chainlink.go index 3a0e2e4bbb9..5748304b819 100644 --- a/core/services/ocr2/plugins/ccip/testhelpers/integration/chainlink.go +++ b/core/services/ocr2/plugins/ccip/testhelpers/integration/chainlink.go @@ -33,9 +33,7 @@ import ( types4 "github.com/smartcontractkit/libocr/offchainreporting2plus/types" "github.com/smartcontractkit/chainlink-common/pkg/config" - "github.com/smartcontractkit/chainlink-common/pkg/loop" cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccip" - "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox" "github.com/smartcontractkit/chainlink-common/pkg/utils/tests" pb "github.com/smartcontractkit/chainlink-protos/orchestrator/feedsmanager" @@ -45,8 +43,6 @@ import ( "github.com/smartcontractkit/chainlink-integrations/evm/utils" evmUtils "github.com/smartcontractkit/chainlink-integrations/evm/utils/big" - evmcapabilities "github.com/smartcontractkit/chainlink/v2/core/capabilities" - "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" configv2 "github.com/smartcontractkit/chainlink/v2/core/config/toml" price_registry_1_2_0 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/v1_2_0/price_registry" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/v1_5_0/commit_store" @@ -75,7 +71,6 @@ import ( clutils "github.com/smartcontractkit/chainlink/v2/core/utils" "github.com/smartcontractkit/chainlink/v2/core/utils/crypto" "github.com/smartcontractkit/chainlink/v2/core/utils/testutils/heavyweight" - "github.com/smartcontractkit/chainlink/v2/plugins" ) const ( @@ -438,18 +433,12 @@ func setupNodeCCIP( csaKeyStore.On("GetAll").Return([]csakey.KeyV2{key}, nil) keyStore := NewKsa(db, lggr, csaKeyStore) - simEthKeyStore := testhelpers.EthKeyStoreSim{ - ETHKS: keyStore.Eth(), - CSAKS: keyStore.CSA(), - } - mailMon := mailbox.NewMonitor("CCIP", lggr.Named("Mailbox")) - evmOpts := chainlink.EVMFactoryConfig{ - ChainOpts: legacyevm.ChainOpts{ - ChainConfigs: config.EVMConfigs(), - DatabaseConfig: config.Database(), - ListenerConfig: config.Database().Listener(), - FeatureConfig: config.Feature(), - GenEthClient: func(chainID *big.Int) client.Client { + app, err := chainlink.NewApplication(ctx, chainlink.ApplicationOpts{ + Config: config, + DS: db, + KeyStore: keyStore, + EVMFactoryConfigFn: func(fc *chainlink.EVMFactoryConfig) { + fc.GenEthClient = func(chainID *big.Int) client.Client { if chainID.String() == sourceChainID.String() { return sourceClient } else if chainID.String() == destChainID.String() { @@ -457,46 +446,14 @@ func setupNodeCCIP( } t.Fatalf("invalid chain ID %v", chainID.String()) return nil - }, - MailMon: mailMon, - DS: db, + } }, - CSAETHKeystore: simEthKeyStore, - } - beholderAuthHeaders, csaPubKeyHex, err := keystore.BuildBeholderAuth(keyStore) - require.NoError(t, err) - - loopRegistry := plugins.NewLoopRegistry(lggr.Named("LoopRegistry"), config.Database(), config.Tracing(), config.Telemetry(), beholderAuthHeaders, csaPubKeyHex) - relayerFactory := chainlink.RelayerFactory{ - Logger: lggr, - LoopRegistry: loopRegistry, - GRPCOpts: loop.GRPCOpts{}, - CapabilitiesRegistry: evmcapabilities.NewRegistry(logger.TestLogger(t)), - } - testCtx := testutils.Context(t) - // evm alway enabled for backward compatibility - initOps := []chainlink.CoreRelayerChainInitFunc{ - chainlink.InitEVM(testCtx, relayerFactory, evmOpts), - } - - relayChainInterops, err := chainlink.NewCoreRelayerChainInteroperators(initOps...) - if err != nil { - t.Fatal(err) - } - - app, err := chainlink.NewApplication(chainlink.ApplicationOpts{ - Config: config, - DS: db, - KeyStore: keyStore, - RelayerChainInteroperators: relayChainInterops, - Logger: lggr, - ExternalInitiatorManager: nil, - CloseLogger: lggr.Sync, - UnrestrictedHTTPClient: &http.Client{}, - RestrictedHTTPClient: &http.Client{}, - AuditLogger: audit.NoopLogger, - MailMon: mailMon, - LoopRegistry: plugins.NewLoopRegistry(lggr, config.Database(), config.Tracing(), config.Telemetry(), beholderAuthHeaders, csaPubKeyHex), + Logger: lggr, + ExternalInitiatorManager: nil, + CloseLogger: lggr.Sync, + UnrestrictedHTTPClient: &http.Client{}, + RestrictedHTTPClient: &http.Client{}, + AuditLogger: audit.NoopLogger, }) require.NoError(t, err) require.NoError(t, app.GetKeyStore().Unlock(ctx, "password")) @@ -508,6 +465,7 @@ func setupNodeCCIP( require.Len(t, p2pIDs, 1) peerID := p2pIDs[0].PeerID() + testCtx := testutils.Context(t) _, err = app.GetKeyStore().Eth().Create(testCtx, destChainID) require.NoError(t, err) sendingKeys, err := app.GetKeyStore().Eth().EnabledKeysForChain(testCtx, destChainID) diff --git a/core/services/ocr2/plugins/ccip/testhelpers/testhelpers_1_4_0/chainlink.go b/core/services/ocr2/plugins/ccip/testhelpers/testhelpers_1_4_0/chainlink.go index 49f55667ec5..c33a1091e6e 100644 --- a/core/services/ocr2/plugins/ccip/testhelpers/testhelpers_1_4_0/chainlink.go +++ b/core/services/ocr2/plugins/ccip/testhelpers/testhelpers_1_4_0/chainlink.go @@ -33,10 +33,7 @@ import ( types4 "github.com/smartcontractkit/libocr/offchainreporting2plus/types" "github.com/smartcontractkit/chainlink-common/pkg/config" - "github.com/smartcontractkit/chainlink-common/pkg/loop" cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccip" - "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox" - pb "github.com/smartcontractkit/chainlink-protos/orchestrator/feedsmanager" "github.com/smartcontractkit/chainlink-integrations/evm/client" @@ -46,7 +43,6 @@ import ( evmUtils "github.com/smartcontractkit/chainlink-integrations/evm/utils/big" evmcapabilities "github.com/smartcontractkit/chainlink/v2/core/capabilities" - "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" configv2 "github.com/smartcontractkit/chainlink/v2/core/config/toml" commit_store_1_2_0 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/v1_2_0/commit_store" evm_2_evm_offramp_1_2_0 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/v1_2_0/evm_2_evm_offramp" @@ -66,7 +62,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/abihelpers" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/internal/ccipdata/v1_2_0" - "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/testhelpers" integrationtesthelpers "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/testhelpers/integration" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/validate" "github.com/smartcontractkit/chainlink/v2/core/services/ocrbootstrap" @@ -74,7 +69,6 @@ import ( clutils "github.com/smartcontractkit/chainlink/v2/core/utils" "github.com/smartcontractkit/chainlink/v2/core/utils/crypto" "github.com/smartcontractkit/chainlink/v2/core/utils/testutils/heavyweight" - "github.com/smartcontractkit/chainlink/v2/plugins" ) const ( @@ -437,19 +431,16 @@ func setupNodeCCIP( require.NoError(t, err) csaKeyStore.On("GetAll").Return([]csakey.KeyV2{key}, nil) keyStore := NewKsa(db, lggr, csaKeyStore) - - simEthKeyStore := testhelpers.EthKeyStoreSim{ - ETHKS: keyStore.Eth(), - CSAKS: keyStore.CSA(), - } - mailMon := mailbox.NewMonitor("CCIP", lggr.Named("Mailbox")) - evmOpts := chainlink.EVMFactoryConfig{ - ChainOpts: legacyevm.ChainOpts{ - ChainConfigs: config.EVMConfigs(), - DatabaseConfig: config.Database(), - ListenerConfig: config.Database().Listener(), - FeatureConfig: config.Feature(), - GenEthClient: func(chainID *big.Int) client.Client { + ctx := testutils.Context(t) + app, err := chainlink.NewApplication(ctx, chainlink.ApplicationOpts{ + CREOpts: chainlink.CREOpts{ + CapabilitiesRegistry: evmcapabilities.NewRegistry(lggr), + }, + Config: config, + DS: db, + KeyStore: keyStore, + EVMFactoryConfigFn: func(fc *chainlink.EVMFactoryConfig) { + fc.GenEthClient = func(chainID *big.Int) client.Client { if chainID.String() == sourceChainID.String() { return sourceClient } else if chainID.String() == destChainID.String() { @@ -457,45 +448,16 @@ func setupNodeCCIP( } t.Fatalf("invalid chain ID %v", chainID.String()) return nil - }, - MailMon: mailMon, - DS: db, + } }, - CSAETHKeystore: simEthKeyStore, - } - loopRegistry := plugins.NewLoopRegistry(lggr.Named("LoopRegistry"), config.Database(), config.Tracing(), config.Telemetry(), nil, "") - relayerFactory := chainlink.RelayerFactory{ - Logger: lggr, - LoopRegistry: loopRegistry, - GRPCOpts: loop.GRPCOpts{}, - CapabilitiesRegistry: evmcapabilities.NewRegistry(lggr), - } - testCtx := testutils.Context(t) - // evm alway enabled for backward compatibility - initOps := []chainlink.CoreRelayerChainInitFunc{ - chainlink.InitEVM(testCtx, relayerFactory, evmOpts), - } - - relayChainInterops, err := chainlink.NewCoreRelayerChainInteroperators(initOps...) - if err != nil { - t.Fatal(err) - } - - app, err := chainlink.NewApplication(chainlink.ApplicationOpts{ - Config: config, - DS: db, - KeyStore: keyStore, - RelayerChainInteroperators: relayChainInterops, - Logger: lggr, - ExternalInitiatorManager: nil, - CloseLogger: lggr.Sync, - UnrestrictedHTTPClient: &http.Client{}, - RestrictedHTTPClient: &http.Client{}, - AuditLogger: audit.NoopLogger, - MailMon: mailMon, - LoopRegistry: plugins.NewLoopRegistry(lggr, config.Database(), config.Tracing(), config.Telemetry(), nil, ""), + Logger: lggr, + ExternalInitiatorManager: nil, + CloseLogger: lggr.Sync, + UnrestrictedHTTPClient: &http.Client{}, + RestrictedHTTPClient: &http.Client{}, + AuditLogger: audit.NoopLogger, }) - ctx := testutils.Context(t) + require.NoError(t, err) require.NoError(t, app.GetKeyStore().Unlock(ctx, "password")) _, err = app.GetKeyStore().P2P().Create(ctx) @@ -506,6 +468,7 @@ func setupNodeCCIP( require.Len(t, p2pIDs, 1) peerID := p2pIDs[0].PeerID() + testCtx := testutils.Context(t) _, err = app.GetKeyStore().Eth().Create(testCtx, destChainID) require.NoError(t, err) sendingKeys, err := app.GetKeyStore().Eth().EnabledKeysForChain(testCtx, destChainID) diff --git a/core/services/ocr2/plugins/ccip/transmitter/transmitter.go b/core/services/ocr2/plugins/ccip/transmitter/transmitter.go index a2b7109629f..0d78d8ae758 100644 --- a/core/services/ocr2/plugins/ccip/transmitter/transmitter.go +++ b/core/services/ocr2/plugins/ccip/transmitter/transmitter.go @@ -10,6 +10,7 @@ import ( commontypes "github.com/smartcontractkit/chainlink-common/pkg/types" "github.com/smartcontractkit/chainlink-framework/chains/txmgr/types" + "github.com/smartcontractkit/chainlink-integrations/evm/keys" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/statuschecker" ) @@ -39,7 +40,7 @@ type transmitter struct { strategy types.TxStrategy checker txmgr.TransmitCheckerSpec chainID *big.Int - keystore roundRobinKeystore + keystore keys.RoundRobin statuschecker statuschecker.CCIPTransactionStatusChecker // Used for CCIP's idempotency key generation } @@ -52,7 +53,7 @@ func NewTransmitter( strategy types.TxStrategy, checker txmgr.TransmitCheckerSpec, chainID *big.Int, - keystore roundRobinKeystore, + keystore keys.RoundRobin, ) (Transmitter, error) { // Ensure that a keystore is provided. if keystore == nil { @@ -79,7 +80,7 @@ func NewTransmitterWithStatusChecker( strategy types.TxStrategy, checker txmgr.TransmitCheckerSpec, chainID *big.Int, - keystore roundRobinKeystore, + keystore keys.RoundRobin, ) (Transmitter, error) { t, err := NewTransmitter(txm, fromAddresses, gasLimit, effectiveTransmitterAddress, strategy, checker, chainID, keystore) @@ -97,7 +98,7 @@ func NewTransmitterWithStatusChecker( } func (t *transmitter) CreateEthTransaction(ctx context.Context, toAddress common.Address, payload []byte, txMeta *txmgr.TxMeta) error { - roundRobinFromAddress, err := t.keystore.GetRoundRobinAddress(ctx, t.chainID, t.fromAddresses...) + roundRobinFromAddress, err := t.keystore.GetNextAddress(ctx, t.fromAddresses...) if err != nil { return fmt.Errorf("skipped OCR transmission, error getting round-robin address: %w", err) } diff --git a/core/services/ocr2/plugins/ccip/transmitter/transmitter_test.go b/core/services/ocr2/plugins/ccip/transmitter/transmitter_test.go index c8dba44b4b0..decfdcc0526 100644 --- a/core/services/ocr2/plugins/ccip/transmitter/transmitter_test.go +++ b/core/services/ocr2/plugins/ccip/transmitter/transmitter_test.go @@ -11,7 +11,8 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/sqlutil" "github.com/smartcontractkit/chainlink-common/pkg/types" - + "github.com/smartcontractkit/chainlink-integrations/evm/keys" + "github.com/smartcontractkit/chainlink-integrations/evm/keys/keystest" ubig "github.com/smartcontractkit/chainlink-integrations/evm/utils/big" commontxmmocks "github.com/smartcontractkit/chainlink/v2/common/txmgr/types/mocks" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" @@ -37,13 +38,10 @@ func newMockTxStrategy(t *testing.T) *commontxmmocks.TxStrategy { func Test_DefaultTransmitter_CreateEthTransaction(t *testing.T) { t.Parallel() - db := pgtest.NewSqlxDB(t) - ethKeyStore := NewKeyStore(t, db).Eth() - - _, fromAddress := MustInsertRandomKey(t, ethKeyStore) + fromAddress := MustGenerateRandomKey(t).Address + ethKeyStore := keystest.Addresses{fromAddress} gasLimit := uint64(1000) - chainID := big.NewInt(0) effectiveTransmitterAddress := fromAddress toAddress := testutils.NewAddress() payload := []byte{1, 2, 3} @@ -57,7 +55,6 @@ func Test_DefaultTransmitter_CreateEthTransaction(t *testing.T) { effectiveTransmitterAddress, strategy, txmgr.TransmitCheckerSpec{}, - chainID, ethKeyStore, ) require.NoError(t, err) @@ -77,14 +74,12 @@ func Test_DefaultTransmitter_CreateEthTransaction(t *testing.T) { func Test_DefaultTransmitter_Forwarding_Enabled_CreateEthTransaction(t *testing.T) { t.Parallel() - db := pgtest.NewSqlxDB(t) - ethKeyStore := NewKeyStore(t, db).Eth() - - _, fromAddress := MustInsertRandomKey(t, ethKeyStore) - _, fromAddress2 := MustInsertRandomKey(t, ethKeyStore) + memKeys := keystest.NewMemoryChainStore() + fromAddress := memKeys.MustCreate(t) + fromAddress2 := memKeys.MustCreate(t) + ethKeyStore := keys.NewStore(memKeys) gasLimit := uint64(1000) - chainID := big.NewInt(0) effectiveTransmitterAddress := common.Address{} toAddress := testutils.NewAddress() payload := []byte{1, 2, 3} @@ -98,7 +93,6 @@ func Test_DefaultTransmitter_Forwarding_Enabled_CreateEthTransaction(t *testing. effectiveTransmitterAddress, strategy, txmgr.TransmitCheckerSpec{}, - chainID, ethKeyStore, ) require.NoError(t, err) @@ -128,13 +122,9 @@ func Test_DefaultTransmitter_Forwarding_Enabled_CreateEthTransaction(t *testing. func Test_DefaultTransmitter_Forwarding_Enabled_CreateEthTransaction_Round_Robin_Error(t *testing.T) { t.Parallel() - db := pgtest.NewSqlxDB(t) - ethKeyStore := NewKeyStore(t, db).Eth() - fromAddress := common.Address{} gasLimit := uint64(1000) - chainID := big.NewInt(0) effectiveTransmitterAddress := common.Address{} toAddress := testutils.NewAddress() payload := []byte{1, 2, 3} @@ -148,8 +138,7 @@ func Test_DefaultTransmitter_Forwarding_Enabled_CreateEthTransaction_Round_Robin effectiveTransmitterAddress, strategy, txmgr.TransmitCheckerSpec{}, - chainID, - ethKeyStore, + keystest.Addresses{}, ) require.NoError(t, err) require.Error(t, transmitter.CreateEthTransaction(testutils.Context(t), toAddress, payload, nil)) @@ -165,7 +154,6 @@ func Test_DefaultTransmitter_Forwarding_Enabled_CreateEthTransaction_No_Keystore _, fromAddress2 := MustInsertRandomKey(t, ethKeyStore) gasLimit := uint64(1000) - chainID := big.NewInt(0) effectiveTransmitterAddress := common.Address{} txm := txmmocks.NewMockEvmTxManager(t) strategy := newMockTxStrategy(t) @@ -177,7 +165,6 @@ func Test_DefaultTransmitter_Forwarding_Enabled_CreateEthTransaction_No_Keystore effectiveTransmitterAddress, strategy, txmgr.TransmitCheckerSpec{}, - chainID, nil, ) require.Error(t, err) @@ -186,10 +173,9 @@ func Test_DefaultTransmitter_Forwarding_Enabled_CreateEthTransaction_No_Keystore func Test_Transmitter_With_StatusChecker_CreateEthTransaction(t *testing.T) { t.Parallel() - db := pgtest.NewSqlxDB(t) - ethKeyStore := NewKeyStore(t, db).Eth() - - _, fromAddress := MustInsertRandomKey(t, ethKeyStore) + randomKey := MustGenerateRandomKey(t) + fromAddress := randomKey.Address + ethKeyStore := keystest.Addresses{fromAddress} gasLimit := uint64(1000) chainID := big.NewInt(0) diff --git a/core/services/ocr2/plugins/functions/plugin.go b/core/services/ocr2/plugins/functions/plugin.go index b36d3e37dbc..65af724bfe7 100644 --- a/core/services/ocr2/plugins/functions/plugin.go +++ b/core/services/ocr2/plugins/functions/plugin.go @@ -3,8 +3,6 @@ package functions import ( "context" "encoding/json" - "math/big" - "slices" "time" "github.com/ethereum/go-ethereum/common" @@ -16,6 +14,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/sqlutil" "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox" + "github.com/smartcontractkit/chainlink-integrations/evm/keys" "github.com/smartcontractkit/chainlink/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" @@ -27,8 +26,6 @@ import ( gwAllowlist "github.com/smartcontractkit/chainlink/v2/core/services/gateway/handlers/functions/allowlist" gwSubscriptions "github.com/smartcontractkit/chainlink/v2/core/services/gateway/handlers/functions/subscriptions" "github.com/smartcontractkit/chainlink/v2/core/services/job" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/functions/config" s4_plugin "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/s4" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/threshold" @@ -46,7 +43,7 @@ type FunctionsServicesConfig struct { Logger logger.Logger MailMon *mailbox.Monitor URLsMonEndpoint commontypes.MonitoringEndpoint - EthKeystore keystore.Eth + EthKeystore keys.Store ThresholdKeyShare []byte LogPollerWrapper evmrelayTypes.LogPollerWrapper } @@ -175,7 +172,7 @@ func NewFunctionsServices(ctx context.Context, functionsOracleArgs, thresholdOra return nil, errors.Wrap(err, "failed to create a OnchainSubscriptions") } connectorLogger := conf.Logger.Named("GatewayConnector").With("jobName", conf.Job.PipelineSpec.JobName) - connector, handler, err2 := NewConnector(ctx, &pluginConfig, conf.EthKeystore, conf.Chain.ID(), s4Storage, allowlist, rateLimiter, subscriptions, functionsListener, offchainTransmitter, connectorLogger) + connector, handler, err2 := NewConnector(ctx, &pluginConfig, conf.EthKeystore, s4Storage, allowlist, rateLimiter, subscriptions, functionsListener, offchainTransmitter, connectorLogger) if err2 != nil { return nil, errors.Wrap(err, "failed to create a GatewayConnector") } @@ -203,22 +200,19 @@ func NewFunctionsServices(ctx context.Context, functionsOracleArgs, thresholdOra return allServices, nil } -func NewConnector(ctx context.Context, pluginConfig *config.PluginConfig, ethKeystore keystore.Eth, chainID *big.Int, s4Storage s4.Storage, allowlist gwAllowlist.OnchainAllowlist, rateLimiter *hc.RateLimiter, subscriptions gwSubscriptions.OnchainSubscriptions, listener functions.FunctionsListener, offchainTransmitter functions.OffchainTransmitter, lggr logger.Logger) (connector.GatewayConnector, connector.GatewayConnectorHandler, error) { - enabledKeys, err := ethKeystore.EnabledKeysForChain(ctx, chainID) +type Keystore interface { + keys.AddressChecker + keys.MessageSigner +} + +func NewConnector(ctx context.Context, pluginConfig *config.PluginConfig, ethKeystore Keystore, s4Storage s4.Storage, allowlist gwAllowlist.OnchainAllowlist, rateLimiter *hc.RateLimiter, subscriptions gwSubscriptions.OnchainSubscriptions, listener functions.FunctionsListener, offchainTransmitter functions.OffchainTransmitter, lggr logger.Logger) (connector.GatewayConnector, connector.GatewayConnectorHandler, error) { + configuredNodeAddress := common.HexToAddress(pluginConfig.GatewayConnectorConfig.NodeAddress) + err := ethKeystore.CheckEnabled(ctx, configuredNodeAddress) if err != nil { return nil, nil, err } - configuredNodeAddress := common.HexToAddress(pluginConfig.GatewayConnectorConfig.NodeAddress) - idx := slices.IndexFunc(enabledKeys, func(key ethkey.KeyV2) bool { return key.Address == configuredNodeAddress }) - if idx == -1 { - return nil, nil, errors.New("key for configured node address not found") - } - signerKey := enabledKeys[idx].ToEcdsaPrivKey() - if enabledKeys[idx].ID() != pluginConfig.GatewayConnectorConfig.NodeAddress { - return nil, nil, errors.New("node address mismatch") - } - handler, err := functions.NewFunctionsConnectorHandler(pluginConfig, signerKey, s4Storage, allowlist, rateLimiter, subscriptions, listener, offchainTransmitter, lggr) + handler, err := functions.NewFunctionsConnectorHandler(pluginConfig, configuredNodeAddress, ethKeystore, s4Storage, allowlist, rateLimiter, subscriptions, listener, offchainTransmitter, lggr) if err != nil { return nil, nil, err } diff --git a/core/services/ocr2/plugins/functions/plugin_test.go b/core/services/ocr2/plugins/functions/plugin_test.go index b3a120894d0..d7881d5e775 100644 --- a/core/services/ocr2/plugins/functions/plugin_test.go +++ b/core/services/ocr2/plugins/functions/plugin_test.go @@ -1,13 +1,12 @@ package functions_test import ( - "math/big" "testing" "github.com/ethereum/go-ethereum/common" - "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" + "github.com/smartcontractkit/chainlink-integrations/evm/keys/keystest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/logger" sfmocks "github.com/smartcontractkit/chainlink/v2/core/services/functions/mocks" @@ -16,7 +15,6 @@ import ( gfaMocks "github.com/smartcontractkit/chainlink/v2/core/services/gateway/handlers/functions/allowlist/mocks" gfsMocks "github.com/smartcontractkit/chainlink/v2/core/services/gateway/handlers/functions/subscriptions/mocks" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ethkey" - ksmocks "github.com/smartcontractkit/chainlink/v2/core/services/keystore/mocks" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/functions" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/functions/config" s4mocks "github.com/smartcontractkit/chainlink/v2/core/services/s4/mocks" @@ -34,8 +32,7 @@ func TestNewConnector_Success(t *testing.T) { NodeAddress: keyV2.Address.String(), DonId: "my_don", } - chainID := big.NewInt(80001) - ethKeystore := ksmocks.NewEth(t) + s4Storage := s4mocks.NewStorage(t) allowlist := gfaMocks.NewOnchainAllowlist(t) subscriptions := gfsMocks.NewOnchainSubscriptions(t) @@ -43,11 +40,13 @@ func TestNewConnector_Success(t *testing.T) { require.NoError(t, err) listener := sfmocks.NewFunctionsListener(t) offchainTransmitter := sfmocks.NewOffchainTransmitter(t) - ethKeystore.On("EnabledKeysForChain", mock.Anything, mock.Anything).Return([]ethkey.KeyV2{keyV2}, nil) config := &config.PluginConfig{ GatewayConnectorConfig: gwcCfg, } - _, _, err = functions.NewConnector(ctx, config, ethKeystore, chainID, s4Storage, allowlist, rateLimiter, subscriptions, listener, offchainTransmitter, logger.TestLogger(t)) + ks := &keystest.FakeChainStore{ + Addresses: keystest.Addresses{keyV2.Address}, + } + _, _, err = functions.NewConnector(ctx, config, ks, s4Storage, allowlist, rateLimiter, subscriptions, listener, offchainTransmitter, logger.TestLogger(t)) require.NoError(t, err) } @@ -65,8 +64,6 @@ func TestNewConnector_NoKeyForConfiguredAddress(t *testing.T) { NodeAddress: addresses[0], DonId: "my_don", } - chainID := big.NewInt(80001) - ethKeystore := ksmocks.NewEth(t) s4Storage := s4mocks.NewStorage(t) allowlist := gfaMocks.NewOnchainAllowlist(t) subscriptions := gfsMocks.NewOnchainSubscriptions(t) @@ -74,10 +71,12 @@ func TestNewConnector_NoKeyForConfiguredAddress(t *testing.T) { require.NoError(t, err) listener := sfmocks.NewFunctionsListener(t) offchainTransmitter := sfmocks.NewOffchainTransmitter(t) - ethKeystore.On("EnabledKeysForChain", mock.Anything, mock.Anything).Return([]ethkey.KeyV2{{Address: common.HexToAddress(addresses[1])}}, nil) config := &config.PluginConfig{ GatewayConnectorConfig: gwcCfg, } - _, _, err = functions.NewConnector(ctx, config, ethKeystore, chainID, s4Storage, allowlist, rateLimiter, subscriptions, listener, offchainTransmitter, logger.TestLogger(t)) + ks := &keystest.FakeChainStore{ + Addresses: keystest.Addresses{common.HexToAddress(addresses[1])}, + } + _, _, err = functions.NewConnector(ctx, config, ks, s4Storage, allowlist, rateLimiter, subscriptions, listener, offchainTransmitter, logger.TestLogger(t)) require.Error(t, err) } diff --git a/core/services/ocr2/plugins/ocr2keeper/util.go b/core/services/ocr2/plugins/ocr2keeper/util.go index c5e21ee7c97..dc62b12c555 100644 --- a/core/services/ocr2/plugins/ocr2keeper/util.go +++ b/core/services/ocr2/plugins/ocr2keeper/util.go @@ -13,12 +13,11 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/sqlutil" "github.com/smartcontractkit/chainlink-common/pkg/types" ocr2keepers21 "github.com/smartcontractkit/chainlink-common/pkg/types/automation" - + "github.com/smartcontractkit/chainlink-integrations/evm/keys" evmtypes "github.com/smartcontractkit/chainlink-integrations/evm/types" "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/job" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore" evmregistry20 "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v20" evmregistry21 "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21" evmregistry21transmit "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/transmit" @@ -37,7 +36,7 @@ type Encoder21 interface { ocr2keepers21.Encoder } -func EVMProvider(ctx context.Context, ds sqlutil.DataSource, chain legacyevm.Chain, lggr logger.Logger, spec job.Job, ethKeystore keystore.Eth) (evmrelay.OCR2KeeperProvider, error) { +func EVMProvider(ctx context.Context, ds sqlutil.DataSource, chain legacyevm.Chain, lggr logger.Logger, spec job.Job, ethKeystore keys.Store) (evmrelay.OCR2KeeperProvider, error) { oSpec := spec.OCR2OracleSpec ocr2keeperRelayer := evmrelay.NewOCR2KeeperRelayer(ds, chain, lggr.Named("OCR2KeeperRelayer"), ethKeystore) @@ -66,7 +65,7 @@ func EVMDependencies20( ds sqlutil.DataSource, lggr logger.Logger, chain legacyevm.Chain, - ethKeystore keystore.Eth, + ethKeystore keys.Store, ) (evmrelay.OCR2KeeperProvider, *evmregistry20.EvmRegistry, Encoder20, *evmregistry20.LogProvider, error) { var err error diff --git a/core/services/ocrcommon/dual_transmitter.go b/core/services/ocrcommon/dual_transmitter.go index 868c1d65b35..e4e55c609d6 100644 --- a/core/services/ocrcommon/dual_transmitter.go +++ b/core/services/ocrcommon/dual_transmitter.go @@ -2,7 +2,6 @@ package ocrcommon import ( "context" - "math/big" "net/url" "slices" @@ -10,6 +9,7 @@ import ( "github.com/pkg/errors" "github.com/smartcontractkit/chainlink-framework/chains/txmgr/types" + "github.com/smartcontractkit/chainlink-integrations/evm/keys" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/forwarders" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" ) @@ -21,8 +21,7 @@ type ocr2FeedsDualTransmission struct { primaryEffectiveTransmitterAddress common.Address strategy types.TxStrategy checker txmgr.TransmitCheckerSpec - chainID *big.Int - keystore roundRobinKeystore + keystore keys.RoundRobin ocr2Aggregator common.Address txManagerOCR2 @@ -52,7 +51,7 @@ func (t *ocr2FeedsDualTransmission) forwarderAddress(ctx context.Context, eoa, o } func (t *ocr2FeedsDualTransmission) CreateEthTransaction(ctx context.Context, toAddress common.Address, payload []byte, txMeta *txmgr.TxMeta) error { - roundRobinFromAddress, err := t.keystore.GetRoundRobinAddress(ctx, t.chainID, t.primaryFromAddresses...) + roundRobinFromAddress, err := t.keystore.GetNextAddress(ctx, t.primaryFromAddresses...) if err != nil { return errors.Wrap(err, "skipped OCR transmission, error getting round-robin address") } @@ -107,7 +106,7 @@ func (t *ocr2FeedsDualTransmission) CreateSecondaryEthTransaction(ctx context.Co } func (t *ocr2FeedsDualTransmission) FromAddress(ctx context.Context) common.Address { - roundRobinFromAddress, err := t.keystore.GetRoundRobinAddress(ctx, t.chainID, t.primaryFromAddresses...) + roundRobinFromAddress, err := t.keystore.GetNextAddress(ctx, t.primaryFromAddresses...) if err != nil { return t.primaryEffectiveTransmitterAddress } diff --git a/core/services/ocrcommon/transmitter.go b/core/services/ocrcommon/transmitter.go index 1052e7b38ad..d26c1609db4 100644 --- a/core/services/ocrcommon/transmitter.go +++ b/core/services/ocrcommon/transmitter.go @@ -2,21 +2,22 @@ package ocrcommon import ( "context" - "math/big" + "errors" + "fmt" "slices" "github.com/ethereum/go-ethereum/common" - "github.com/pkg/errors" "github.com/smartcontractkit/chainlink-framework/chains/txmgr/types" + "github.com/smartcontractkit/chainlink-integrations/evm/keys" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/forwarders" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore" evmtypes "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/types" ) -type roundRobinKeystore interface { - GetRoundRobinAddress(ctx context.Context, chainID *big.Int, addresses ...common.Address) (address common.Address, err error) +type RoundRobinKeyLocker interface { + keys.RoundRobin + keys.Locker } type txManager interface { @@ -38,8 +39,7 @@ type transmitter struct { effectiveTransmitterAddress common.Address strategy types.TxStrategy checker txmgr.TransmitCheckerSpec - chainID *big.Int - keystore roundRobinKeystore + keystore keys.RoundRobin } // NewTransmitter creates a new eth transmitter @@ -50,8 +50,7 @@ func NewTransmitter( effectiveTransmitterAddress common.Address, strategy types.TxStrategy, checker txmgr.TransmitCheckerSpec, - chainID *big.Int, - keystore roundRobinKeystore, + keystore keys.RoundRobin, ) (Transmitter, error) { // Ensure that a keystore is provided. if keystore == nil { @@ -65,7 +64,6 @@ func NewTransmitter( effectiveTransmitterAddress: effectiveTransmitterAddress, strategy: strategy, checker: checker, - chainID: chainID, keystore: keystore, }, nil } @@ -84,7 +82,6 @@ type ocr2FeedsTransmitter struct { // NewOCR2FeedsTransmitter creates a new eth transmitter that handles OCR2 Feeds specific logic surrounding forwarders. // ocr2FeedsTransmitter validates forwarders before every transmission, enabling smooth onchain config changes without job restarts. func NewOCR2FeedsTransmitter( - ctx context.Context, txm txManagerOCR2, fromAddresses []common.Address, ocr2Aggregator common.Address, @@ -92,8 +89,7 @@ func NewOCR2FeedsTransmitter( effectiveTransmitterAddress common.Address, strategy types.TxStrategy, checker txmgr.TransmitCheckerSpec, - chainID *big.Int, - ks keystore.Eth, + ks RoundRobinKeyLocker, dualTransmissionConfig *evmtypes.DualTransmissionConfig, ) (Transmitter, error) { // Ensure that a keystore is provided. @@ -101,17 +97,13 @@ func NewOCR2FeedsTransmitter( return nil, errors.New("nil keystore provided to transmitter") } - if hasLock, err := keyHasLock(ctx, ks, effectiveTransmitterAddress, keystore.TXMv2); err != nil { - return nil, err - } else if hasLock { - return nil, errors.Errorf("key %s is used as a secondary transmitter in another job. primary and secondary transmitters cannot be mixed", effectiveTransmitterAddress.String()) + if keyHasLock(ks, effectiveTransmitterAddress, keys.TXMv2) { + return nil, fmt.Errorf("key %s is used as a secondary transmitter in another job. primary and secondary transmitters cannot be mixed", effectiveTransmitterAddress.String()) } if dualTransmissionConfig != nil { - if hasLock, err := keyHasLock(ctx, ks, dualTransmissionConfig.TransmitterAddress, keystore.TXMv1); err != nil { - return nil, err - } else if hasLock { - return nil, errors.Errorf("key %s is used as a primary transmitter in another job. primary and secondary transmitters cannot be mixed", effectiveTransmitterAddress.String()) + if keyHasLock(ks, dualTransmissionConfig.TransmitterAddress, keys.TXMv1) { + return nil, fmt.Errorf("key %s is used as a primary transmitter in another job. primary and secondary transmitters cannot be mixed", effectiveTransmitterAddress.String()) } return &ocr2FeedsDualTransmission{ ocr2Aggregator: ocr2Aggregator, @@ -122,7 +114,6 @@ func NewOCR2FeedsTransmitter( primaryEffectiveTransmitterAddress: effectiveTransmitterAddress, strategy: strategy, checker: checker, - chainID: chainID, keystore: ks, secondaryContractAddress: dualTransmissionConfig.ContractAddress, secondaryFromAddress: dualTransmissionConfig.TransmitterAddress, @@ -139,16 +130,15 @@ func NewOCR2FeedsTransmitter( effectiveTransmitterAddress: effectiveTransmitterAddress, strategy: strategy, checker: checker, - chainID: chainID, keystore: ks, }, }, nil } func (t *transmitter) CreateEthTransaction(ctx context.Context, toAddress common.Address, payload []byte, txMeta *txmgr.TxMeta) error { - roundRobinFromAddress, err := t.keystore.GetRoundRobinAddress(ctx, t.chainID, t.fromAddresses...) + roundRobinFromAddress, err := t.keystore.GetNextAddress(ctx, t.fromAddresses...) if err != nil { - return errors.Wrap(err, "skipped OCR transmission, error getting round-robin address") + return fmt.Errorf("skipped OCR transmission, error getting round-robin address: %w", err) } _, err = t.txm.CreateTransaction(ctx, txmgr.TxRequest{ @@ -161,7 +151,10 @@ func (t *transmitter) CreateEthTransaction(ctx context.Context, toAddress common Checker: t.checker, Meta: txMeta, }) - return errors.Wrap(err, "skipped OCR transmission") + if err != nil { + return fmt.Errorf("skipped OCR transmission: %w", err) + } + return nil } func (t *transmitter) CreateSecondaryEthTransaction(ctx context.Context, bytes []byte, meta *txmgr.TxMeta) error { @@ -185,9 +178,9 @@ func (t *transmitter) forwarderAddress() common.Address { } func (t *ocr2FeedsTransmitter) CreateEthTransaction(ctx context.Context, toAddress common.Address, payload []byte, txMeta *txmgr.TxMeta) error { - roundRobinFromAddress, err := t.keystore.GetRoundRobinAddress(ctx, t.chainID, t.fromAddresses...) + roundRobinFromAddress, err := t.keystore.GetNextAddress(ctx, t.fromAddresses...) if err != nil { - return errors.Wrap(err, "skipped OCR transmission, error getting round-robin address") + return fmt.Errorf("skipped OCR transmission, error getting round-robin address: %w", err) } forwarderAddress, err := t.forwarderAddress(ctx, roundRobinFromAddress, toAddress) @@ -206,12 +199,15 @@ func (t *ocr2FeedsTransmitter) CreateEthTransaction(ctx context.Context, toAddre Meta: txMeta, }) - return errors.Wrap(err, "skipped OCR transmission") + if err != nil { + return fmt.Errorf("skipped OCR transmission: %w", err) + } + return nil } // FromAddress for ocr2FeedsTransmitter returns valid forwarder or effectiveTransmitterAddress if forwarders are not set. func (t *ocr2FeedsTransmitter) FromAddress(ctx context.Context) common.Address { - roundRobinFromAddress, err := t.keystore.GetRoundRobinAddress(ctx, t.chainID, t.fromAddresses...) + roundRobinFromAddress, err := t.keystore.GetNextAddress(ctx, t.fromAddresses...) if err != nil { return t.effectiveTransmitterAddress } @@ -250,11 +246,6 @@ func (t *ocr2FeedsTransmitter) CreateSecondaryEthTransaction(ctx context.Context return errors.New("trying to send a secondary transmission on a non dual transmitter") } -func keyHasLock(ctx context.Context, ks keystore.Eth, address common.Address, service keystore.ServiceType) (bool, error) { - rm, err := ks.GetResourceMutex(ctx, address) - if err != nil { - return false, err - } - - return rm.IsLocked(service) +func keyHasLock(ks keys.Locker, address common.Address, service keys.ServiceType) bool { + return ks.GetMutex(address).IsLocked(service) } diff --git a/core/services/ocrcommon/transmitter_test.go b/core/services/ocrcommon/transmitter_test.go index 481a716ef5d..ab3e1f99130 100644 --- a/core/services/ocrcommon/transmitter_test.go +++ b/core/services/ocrcommon/transmitter_test.go @@ -1,7 +1,6 @@ package ocrcommon_test import ( - "math/big" "testing" "github.com/ethereum/go-ethereum/common" @@ -9,14 +8,13 @@ import ( "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" - "github.com/smartcontractkit/chainlink-common/pkg/utils/tests" + "github.com/smartcontractkit/chainlink-integrations/evm/keys" + "github.com/smartcontractkit/chainlink-integrations/evm/keys/keystest" "github.com/smartcontractkit/chainlink-integrations/evm/utils" commontxmmocks "github.com/smartcontractkit/chainlink/v2/common/txmgr/types/mocks" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" txmmocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr/mocks" - "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/services/ocrcommon" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/types" ) @@ -28,13 +26,10 @@ func newMockTxStrategy(t *testing.T) *commontxmmocks.TxStrategy { func Test_DefaultTransmitter_CreateEthTransaction(t *testing.T) { t.Parallel() - db := pgtest.NewSqlxDB(t) - ethKeyStore := cltest.NewKeyStore(t, db).Eth() - - _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore) + fromAddress := testutils.NewAddress() + ethKeyStore := keystest.Addresses{fromAddress} gasLimit := uint64(1000) - chainID := big.NewInt(0) effectiveTransmitterAddress := fromAddress toAddress := testutils.NewAddress() payload := []byte{1, 2, 3} @@ -48,7 +43,6 @@ func Test_DefaultTransmitter_CreateEthTransaction(t *testing.T) { effectiveTransmitterAddress, strategy, txmgr.TransmitCheckerSpec{}, - chainID, ethKeyStore, ) require.NoError(t, err) @@ -68,14 +62,12 @@ func Test_DefaultTransmitter_CreateEthTransaction(t *testing.T) { func Test_DefaultTransmitter_Forwarding_Enabled_CreateEthTransaction(t *testing.T) { t.Parallel() - db := pgtest.NewSqlxDB(t) - ethKeyStore := cltest.NewKeyStore(t, db).Eth() - - _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore) - _, fromAddress2 := cltest.MustInsertRandomKey(t, ethKeyStore) + memKeys := keystest.NewMemoryChainStore() + fromAddress := memKeys.MustCreate(t) + fromAddress2 := memKeys.MustCreate(t) + ethKeyStore := keys.NewStore(memKeys) gasLimit := uint64(1000) - chainID := big.NewInt(0) effectiveTransmitterAddress := common.Address{} toAddress := testutils.NewAddress() payload := []byte{1, 2, 3} @@ -89,7 +81,6 @@ func Test_DefaultTransmitter_Forwarding_Enabled_CreateEthTransaction(t *testing. effectiveTransmitterAddress, strategy, txmgr.TransmitCheckerSpec{}, - chainID, ethKeyStore, ) require.NoError(t, err) @@ -119,13 +110,9 @@ func Test_DefaultTransmitter_Forwarding_Enabled_CreateEthTransaction(t *testing. func Test_DefaultTransmitter_Forwarding_Enabled_CreateEthTransaction_Round_Robin_Error(t *testing.T) { t.Parallel() - db := pgtest.NewSqlxDB(t) - ethKeyStore := cltest.NewKeyStore(t, db).Eth() - - fromAddress := common.Address{} + fromAddress := testutils.NewAddress() gasLimit := uint64(1000) - chainID := big.NewInt(0) effectiveTransmitterAddress := common.Address{} toAddress := testutils.NewAddress() payload := []byte{1, 2, 3} @@ -139,8 +126,7 @@ func Test_DefaultTransmitter_Forwarding_Enabled_CreateEthTransaction_Round_Robin effectiveTransmitterAddress, strategy, txmgr.TransmitCheckerSpec{}, - chainID, - ethKeyStore, + keystest.Addresses{}, ) require.NoError(t, err) require.Error(t, transmitter.CreateEthTransaction(testutils.Context(t), toAddress, payload, nil)) @@ -149,14 +135,10 @@ func Test_DefaultTransmitter_Forwarding_Enabled_CreateEthTransaction_Round_Robin func Test_DefaultTransmitter_Forwarding_Enabled_CreateEthTransaction_No_Keystore_Error(t *testing.T) { t.Parallel() - db := pgtest.NewSqlxDB(t) - ethKeyStore := cltest.NewKeyStore(t, db).Eth() - - _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore) - _, fromAddress2 := cltest.MustInsertRandomKey(t, ethKeyStore) + fromAddress := testutils.NewAddress() + fromAddress2 := testutils.NewAddress() gasLimit := uint64(1000) - chainID := big.NewInt(0) effectiveTransmitterAddress := common.Address{} txm := txmmocks.NewMockEvmTxManager(t) strategy := newMockTxStrategy(t) @@ -168,7 +150,6 @@ func Test_DefaultTransmitter_Forwarding_Enabled_CreateEthTransaction_No_Keystore effectiveTransmitterAddress, strategy, txmgr.TransmitCheckerSpec{}, - chainID, nil, ) require.Error(t, err) @@ -177,18 +158,14 @@ func Test_DefaultTransmitter_Forwarding_Enabled_CreateEthTransaction_No_Keystore func Test_DualTransmitter(t *testing.T) { t.Parallel() - db := pgtest.NewSqlxDB(t) - ethKeyStore := cltest.NewKeyStore(t, db).Eth() - ctx := tests.Context(t) - - _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore) - _, secondaryFromAddress := cltest.MustInsertRandomKey(t, ethKeyStore) + memoryKeystore := keystest.NewMemoryChainStore() + fromAddress := memoryKeystore.MustCreate(t) + secondaryFromAddress := memoryKeystore.MustCreate(t) contractAddress := utils.RandomAddress() secondaryContractAddress := utils.RandomAddress() gasLimit := uint64(1000) - chainID := big.NewInt(0) effectiveTransmitterAddress := fromAddress toAddress := testutils.NewAddress() payload := []byte{1, 2, 3} @@ -205,7 +182,6 @@ func Test_DualTransmitter(t *testing.T) { } transmitter, err := ocrcommon.NewOCR2FeedsTransmitter( - ctx, txm, []common.Address{fromAddress}, contractAddress, @@ -213,8 +189,7 @@ func Test_DualTransmitter(t *testing.T) { effectiveTransmitterAddress, strategy, txmgr.TransmitCheckerSpec{}, - chainID, - ethKeyStore, + keys.NewStore(memoryKeystore), dualTransmissionConfig, ) require.NoError(t, err) diff --git a/core/services/relay/evm/contract_transmitter.go b/core/services/relay/evm/contract_transmitter.go index 40b263370da..da63648b2b1 100644 --- a/core/services/relay/evm/contract_transmitter.go +++ b/core/services/relay/evm/contract_transmitter.go @@ -17,12 +17,12 @@ import ( ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" "github.com/smartcontractkit/chainlink-common/pkg/logger" + evmkeystore "github.com/smartcontractkit/chainlink-integrations/evm/keys" "github.com/smartcontractkit/chainlink-integrations/evm/logpoller" "github.com/smartcontractkit/chainlink-integrations/evm/utils" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" "github.com/smartcontractkit/chainlink/v2/core/services" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore" ) type ContractTransmitter interface { @@ -90,7 +90,7 @@ type contractTransmitter struct { contractReader contractReader lp logpoller.LogPoller lggr logger.Logger - ks keystore.Eth + ks evmkeystore.Locker // Options transmitterOptions *transmitterOps } @@ -107,7 +107,7 @@ func NewOCRContractTransmitter( transmitter Transmitter, lp logpoller.LogPoller, lggr logger.Logger, - ks keystore.Eth, + ks evmkeystore.Locker, opts ...OCRTransmitterOption, ) (*contractTransmitter, error) { transmitted, ok := contractABI.Events["Transmitted"] @@ -254,19 +254,13 @@ func (oc *contractTransmitter) FromAccount(ctx context.Context) (ocrtypes.Accoun func (oc *contractTransmitter) Start(ctx context.Context) error { // Lock the transmitters to TXMv1 - rm, err := oc.ks.GetResourceMutex(ctx, oc.transmitter.FromAddress(ctx)) - if err != nil { - return err - } - return rm.TryLock(keystore.TXMv1) + rm := oc.ks.GetMutex(oc.transmitter.FromAddress(ctx)) + return rm.TryLock(evmkeystore.TXMv1) } func (oc *contractTransmitter) Close() error { // Unlock the transmitters to TXMv1 - rm, err := oc.ks.GetResourceMutex(context.Background(), oc.transmitter.FromAddress(context.Background())) - if err != nil { - return err - } - return rm.Unlock(keystore.TXMv1) + rm := oc.ks.GetMutex(oc.transmitter.FromAddress(context.Background())) + return rm.Unlock(evmkeystore.TXMv1) } // Has no state/lifecycle so it's always healthy and ready diff --git a/core/services/relay/evm/contract_transmitter_test.go b/core/services/relay/evm/contract_transmitter_test.go index 2469e14d8d0..4246a646465 100644 --- a/core/services/relay/evm/contract_transmitter_test.go +++ b/core/services/relay/evm/contract_transmitter_test.go @@ -12,21 +12,21 @@ import ( "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" + "github.com/smartcontractkit/libocr/commontypes" + "github.com/smartcontractkit/libocr/gethwrappers2/ocr2aggregator" + "github.com/smartcontractkit/libocr/offchainreporting2plus/chains/evmutil" + "github.com/smartcontractkit/libocr/offchainreporting2plus/types" + libocr "github.com/smartcontractkit/libocr/offchainreporting2plus/types" + ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" + "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/utils/tests" "github.com/smartcontractkit/chainlink-integrations/evm/client/clienttest" + "github.com/smartcontractkit/chainlink-integrations/evm/keys/keystest" "github.com/smartcontractkit/chainlink-integrations/evm/logpoller" lpmocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller/mocks" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore/mocks" - - "github.com/smartcontractkit/libocr/commontypes" - "github.com/smartcontractkit/libocr/gethwrappers2/ocr2aggregator" - "github.com/smartcontractkit/libocr/offchainreporting2plus/chains/evmutil" - "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - libocr "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" ) var sampleAddress = testutils.NewAddress() @@ -57,7 +57,6 @@ func TestContractTransmitter(t *testing.T) { c := clienttest.NewClient(t) lp := lpmocks.NewLogPoller(t) ctx := testutils.Context(t) - ks := mocks.NewEth(t) // scanLogs = false digestAndEpochDontScanLogs, _ := hex.DecodeString( "0000000000000000000000000000000000000000000000000000000000000000" + // false @@ -69,7 +68,7 @@ func TestContractTransmitter(t *testing.T) { reportToEvmTxMeta := func(b []byte) (*txmgr.TxMeta, error) { return &txmgr.TxMeta{}, nil } - ot, err := NewOCRContractTransmitter(ctx, gethcommon.Address{}, c, contractABI, &mockTransmitter{}, lp, lggr, ks, + ot, err := NewOCRContractTransmitter(ctx, gethcommon.Address{}, c, contractABI, &mockTransmitter{}, lp, lggr, &keystest.FakeChainStore{}, WithReportToEthMetadata(reportToEvmTxMeta)) require.NoError(t, err) digest, epoch, err := ot.LatestConfigDigestAndEpoch(testutils.Context(t)) @@ -163,7 +162,6 @@ func oneSignature() []ocrtypes.AttributedOnchainSignature { } func createContractTransmitter(ctx context.Context, t *testing.T, transmitter Transmitter, ops ...OCRTransmitterOption) *contractTransmitter { - ethKeyStore := mocks.NewEth(t) contractABI, err := abi.JSON(strings.NewReader(ocr2aggregator.OCR2AggregatorMetaData.ABI)) require.NoError(t, err) lp := lpmocks.NewLogPoller(t) @@ -176,7 +174,7 @@ func createContractTransmitter(ctx context.Context, t *testing.T, transmitter Tr transmitter, lp, logger.Test(t), - ethKeyStore, + &keystest.FakeChainStore{}, ops..., ) require.NoError(t, err) diff --git a/core/services/relay/evm/dual_contract_transmitter.go b/core/services/relay/evm/dual_contract_transmitter.go index 4906cd18a81..7c25fe164b8 100644 --- a/core/services/relay/evm/dual_contract_transmitter.go +++ b/core/services/relay/evm/dual_contract_transmitter.go @@ -19,8 +19,8 @@ import ( ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" "github.com/smartcontractkit/chainlink-common/pkg/logger" + "github.com/smartcontractkit/chainlink-integrations/evm/keys" "github.com/smartcontractkit/chainlink-integrations/evm/logpoller" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore" ) // TODO: Remove when new dual transmitter contracts are merged @@ -37,7 +37,7 @@ type dualContractTransmitter struct { contractReader contractReader lp logpoller.LogPoller lggr logger.Logger - ks keystore.Eth + ks keys.Locker // Options transmitterOptions *transmitterOps } @@ -58,7 +58,7 @@ func NewOCRDualContractTransmitter( transmitter Transmitter, lp logpoller.LogPoller, lggr logger.Logger, - ethKeystore keystore.Eth, + ethKeystore keys.Locker, opts ...OCRTransmitterOption, ) (*dualContractTransmitter, error) { transmitted, ok := contractABI.Events["Transmitted"] @@ -195,11 +195,8 @@ func (oc *dualContractTransmitter) unlockTransmitters(ctx context.Context) error func (oc *dualContractTransmitter) unlockPrimary(ctx context.Context) error { primaryAddress := oc.transmitter.FromAddress(ctx) - rmPrimary, err := oc.ks.GetResourceMutex(ctx, primaryAddress) - if err != nil { - return err - } - err = rmPrimary.Unlock(keystore.TXMv1) + rmPrimary := oc.ks.GetMutex(primaryAddress) + err := rmPrimary.Unlock(keys.TXMv1) if err != nil { return err } @@ -212,11 +209,8 @@ func (oc *dualContractTransmitter) unlockSecondary(ctx context.Context) error { if err != nil { return err } - rmSecondary, err := oc.ks.GetResourceMutex(ctx, secondaryAddress) - if err != nil { - return err - } - err = rmSecondary.Unlock(keystore.TXMv2) + rmSecondary := oc.ks.GetMutex(secondaryAddress) + err = rmSecondary.Unlock(keys.TXMv2) if err != nil { return err } @@ -226,11 +220,8 @@ func (oc *dualContractTransmitter) unlockSecondary(ctx context.Context) error { func (oc *dualContractTransmitter) lockPrimary(ctx context.Context) error { primaryAddress := oc.transmitter.FromAddress(ctx) - rmPrimary, err := oc.ks.GetResourceMutex(ctx, primaryAddress) - if err != nil { - return err - } - err = rmPrimary.TryLock(keystore.TXMv1) + rmPrimary := oc.ks.GetMutex(primaryAddress) + err := rmPrimary.TryLock(keys.TXMv1) if err != nil { return err } @@ -243,11 +234,8 @@ func (oc *dualContractTransmitter) lockSecondary(ctx context.Context) error { if err != nil { return err } - rmSecondary, err := oc.ks.GetResourceMutex(ctx, secondaryAddress) - if err != nil { - return err - } - err = rmSecondary.TryLock(keystore.TXMv2) + rmSecondary := oc.ks.GetMutex(secondaryAddress) + err = rmSecondary.TryLock(keys.TXMv2) if err != nil { return err } diff --git a/core/services/relay/evm/dual_contract_transmitter_test.go b/core/services/relay/evm/dual_contract_transmitter_test.go index 0d1a0661fef..ab600b32e75 100644 --- a/core/services/relay/evm/dual_contract_transmitter_test.go +++ b/core/services/relay/evm/dual_contract_transmitter_test.go @@ -12,18 +12,18 @@ import ( "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" + "github.com/smartcontractkit/libocr/gethwrappers2/ocr2aggregator" + "github.com/smartcontractkit/libocr/offchainreporting2plus/chains/evmutil" + "github.com/smartcontractkit/libocr/offchainreporting2plus/types" + "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/utils/tests" "github.com/smartcontractkit/chainlink-integrations/evm/client/clienttest" + "github.com/smartcontractkit/chainlink-integrations/evm/keys/keystest" "github.com/smartcontractkit/chainlink-integrations/evm/logpoller" lpmocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller/mocks" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore/mocks" - - "github.com/smartcontractkit/libocr/gethwrappers2/ocr2aggregator" - "github.com/smartcontractkit/libocr/offchainreporting2plus/chains/evmutil" - "github.com/smartcontractkit/libocr/offchainreporting2plus/types" ) var sampleAddressPrimary = testutils.NewAddress() @@ -54,7 +54,6 @@ func (m *mockDualTransmitter) CreateSecondaryEthTransaction(ctx context.Context, func TestDualContractTransmitter(t *testing.T) { t.Parallel() - keyStore := mocks.NewEth(t) lggr := logger.Test(t) c := clienttest.NewClient(t) lp := lpmocks.NewLogPoller(t) @@ -70,7 +69,7 @@ func TestDualContractTransmitter(t *testing.T) { reportToEvmTxMeta := func(b []byte) (*txmgr.TxMeta, error) { return &txmgr.TxMeta{}, nil } - ot, err := NewOCRDualContractTransmitter(ctx, gethcommon.Address{}, c, contractABI, &mockDualTransmitter{}, lp, lggr, keyStore, WithReportToEthMetadata(reportToEvmTxMeta)) + ot, err := NewOCRDualContractTransmitter(ctx, gethcommon.Address{}, c, contractABI, &mockDualTransmitter{}, lp, lggr, &keystest.FakeChainStore{}, WithReportToEthMetadata(reportToEvmTxMeta)) require.NoError(t, err) digest, epoch, err := ot.LatestConfigDigestAndEpoch(testutils.Context(t)) require.NoError(t, err) @@ -150,7 +149,6 @@ func Test_dualContractTransmitter_Transmit_SignaturesAreTransmitted(t *testing.T } func createDualContractTransmitter(ctx context.Context, t *testing.T, transmitter Transmitter, ops ...OCRTransmitterOption) *dualContractTransmitter { - keyStore := mocks.NewEth(t) contractABI, err := abi.JSON(strings.NewReader(ocr2aggregator.OCR2AggregatorMetaData.ABI)) require.NoError(t, err) lp := lpmocks.NewLogPoller(t) @@ -163,7 +161,7 @@ func createDualContractTransmitter(ctx context.Context, t *testing.T, transmitte transmitter, lp, logger.Test(t), - keyStore, + &keystest.FakeChainStore{}, ops..., ) require.NoError(t, err) diff --git a/core/services/relay/evm/evm.go b/core/services/relay/evm/evm.go index 059157a2ca4..b1bc60b89ed 100644 --- a/core/services/relay/evm/evm.go +++ b/core/services/relay/evm/evm.go @@ -3,7 +3,6 @@ package evm import ( "bytes" "context" - "crypto/ed25519" "crypto/sha256" "encoding/json" "errors" @@ -37,36 +36,26 @@ import ( commontypes "github.com/smartcontractkit/chainlink-common/pkg/types" cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccip" coretypes "github.com/smartcontractkit/chainlink-common/pkg/types/core" - txmgrcommon "github.com/smartcontractkit/chainlink-framework/chains/txmgr" + "github.com/smartcontractkit/chainlink-integrations/evm/keys" evmtypes "github.com/smartcontractkit/chainlink-integrations/evm/types" + coreconfig "github.com/smartcontractkit/chainlink/v2/core/config" + txm "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" - "github.com/smartcontractkit/chainlink/v2/core/config" - coreconfig "github.com/smartcontractkit/chainlink/v2/core/config" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore" "github.com/smartcontractkit/chainlink/v2/core/services/llo" - "github.com/smartcontractkit/chainlink/v2/core/services/llo/bm" - "github.com/smartcontractkit/chainlink/v2/core/services/llo/grpc" - "github.com/smartcontractkit/chainlink/v2/core/services/llo/mercurytransmitter" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/ccipcommit" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/ccipexec" ccipconfig "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/config" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/estimatorconfig" cciptransmitter "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ccip/transmitter" - lloconfig "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/llo/config" mercuryconfig "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/mercury/config" "github.com/smartcontractkit/chainlink/v2/core/services/ocrcommon" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/codec" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/functions" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/interceptors/mantle" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury" - mercuryutils "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/utils" - reportcodecv1 "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/v1/reportcodec" - reportcodecv2 "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/v2/reportcodec" - reportcodecv3 "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/v3/reportcodec" - reportcodecv4 "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/v4/reportcodec" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/wsrpc" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/types" ) @@ -150,25 +139,21 @@ type Relayer struct { ds sqlutil.DataSource chain legacyevm.Chain lggr logger.SugaredLogger - registerer prometheus.Registerer - ks CSAETHKeystore - mercuryPool wsrpc.Pool + csaKeystore coretypes.Keystore + evmKeystore keys.Store codec commontypes.Codec capabilitiesRegistry coretypes.CapabilitiesRegistry // Mercury - mercuryORM mercury.ORM mercuryCfg MercuryConfig + mercuryORM mercury.ORM + mercuryPool wsrpc.Pool triggerCapability *triggers.MercuryTriggerService // LLO/data streams cdcFactory func() (llo.ChannelDefinitionCacheFactory, error) retirementReportCache llo.RetirementReportCache -} - -type CSAETHKeystore interface { - CSA() keystore.CSA - Eth() keystore.Eth + registerer prometheus.Registerer } type MercuryConfig interface { @@ -177,9 +162,10 @@ type MercuryConfig interface { } type RelayerOpts struct { - DS sqlutil.DataSource - Registerer prometheus.Registerer - CSAETHKeystore + DS sqlutil.DataSource + Registerer prometheus.Registerer + CSAKeystore coretypes.Keystore + EVMKeystore coretypes.Keystore MercuryPool wsrpc.Pool RetirementReportCache llo.RetirementReportCache MercuryConfig @@ -192,8 +178,11 @@ func (c RelayerOpts) Validate() error { if c.DS == nil { err = errors.Join(err, errors.New("nil DataSource")) } - if c.CSAETHKeystore == nil { - err = errors.Join(err, errors.New("nil Keystore")) + if c.CSAKeystore == nil { + err = errors.Join(err, errors.New("nil CSAKeystore")) + } + if c.EVMKeystore == nil { + err = errors.Join(err, errors.New("nil EVMKeystore")) } if c.CapabilitiesRegistry == nil { err = errors.Join(err, errors.New("nil CapabilitiesRegistry")) @@ -204,7 +193,7 @@ func (c RelayerOpts) Validate() error { return err } -func NewRelayer(ctx context.Context, lggr logger.Logger, chain legacyevm.Chain, opts RelayerOpts) (*Relayer, error) { +func NewRelayer(lggr logger.Logger, chain legacyevm.Chain, opts RelayerOpts) (*Relayer, error) { err := opts.Validate() if err != nil { return nil, fmt.Errorf("cannot create evm relayer: %w", err) @@ -219,45 +208,42 @@ func NewRelayer(ctx context.Context, lggr logger.Logger, chain legacyevm.Chain, lloORM := llo.NewChainScopedORM(opts.DS, chainSelector) return llo.NewChannelDefinitionCacheFactory(sugared, lloORM, chain.LogPoller(), opts.HTTPClient), nil }) - relayer := &Relayer{ + return &Relayer{ ds: opts.DS, chain: chain, lggr: logger.Sugared(sugared), registerer: opts.Registerer, - ks: opts.CSAETHKeystore, + csaKeystore: opts.CSAKeystore, + evmKeystore: keys.NewChainStore(opts.EVMKeystore, chain.ID()), mercuryPool: opts.MercuryPool, cdcFactory: cdcFactory, retirementReportCache: opts.RetirementReportCache, mercuryORM: mercuryORM, mercuryCfg: opts.MercuryConfig, capabilitiesRegistry: opts.CapabilitiesRegistry, - } + }, nil +} - wCfg := chain.Config().EVM().Workflow() +func (r *Relayer) Name() string { + return r.lggr.Name() +} + +func (r *Relayer) Start(ctx context.Context) error { + wCfg := r.chain.Config().EVM().Workflow() // Initialize write target capability if configuration is defined if wCfg.ForwarderAddress() != nil && wCfg.FromAddress() != nil { if wCfg.GasLimitDefault() == nil { - return nil, fmt.Errorf("unable to instantiate write target as default gas limit is not set") + return fmt.Errorf("unable to instantiate write target as default gas limit is not set") } - - capability, err := NewWriteTarget(ctx, relayer, chain, *wCfg.GasLimitDefault(), lggr) + capability, err := NewWriteTarget(ctx, r, r.chain, *wCfg.GasLimitDefault(), r.lggr) if err != nil { - return nil, fmt.Errorf("failed to initialize write target: %w", err) + return fmt.Errorf("failed to initialize write target: %w", err) } - if err := relayer.capabilitiesRegistry.Add(ctx, capability); err != nil { - return nil, err + if err = r.capabilitiesRegistry.Add(ctx, capability); err != nil { + return fmt.Errorf("failed to register capability: %w", err) } - lggr.Infow("Registered write target", "chain_id", chain.ID()) + r.lggr.Infow("Registered write target", "chain_id", r.chain.ID()) } - - return relayer, nil -} - -func (r *Relayer) Name() string { - return r.lggr.Name() -} - -func (r *Relayer) Start(ctx context.Context) error { return r.chain.Start(ctx) } @@ -340,7 +326,7 @@ func (r *Relayer) NewOCR3CapabilityProvider(ctx context.Context, rargs commontyp return nil, err } - transmitter, err := newOnChainContractTransmitter(ctx, r.lggr, rargs, r.ks.Eth(), configWatcher, configTransmitterOpts{}, OCR2AggregatorTransmissionContractABI) + transmitter, err := newOnChainContractTransmitter(ctx, r.lggr, rargs, r.evmKeystore, configWatcher, configTransmitterOpts{}, OCR2AggregatorTransmissionContractABI) if err != nil { return nil, err } @@ -385,8 +371,7 @@ func (r *Relayer) NewPluginProvider(ctx context.Context, rargs commontypes.Relay if err != nil { return nil, err } - - transmitter, err := newOnChainContractTransmitter(ctx, r.lggr, rargs, r.ks.Eth(), configWatcher, configTransmitterOpts{}, OCR2AggregatorTransmissionContractABI) + transmitter, err := newOnChainContractTransmitter(ctx, r.lggr, rargs, r.evmKeystore, configWatcher, configTransmitterOpts{}, OCR2AggregatorTransmissionContractABI) if err != nil { return nil, err } @@ -437,18 +422,6 @@ func (r *Relayer) NewMercuryProvider(ctx context.Context, rargs commontypes.Rela if !relayConfig.EffectiveTransmitterID.Valid { return nil, pkgerrors.New("EffectiveTransmitterID must be specified") } - privKey, err := r.ks.CSA().Get(relayConfig.EffectiveTransmitterID.String) - if err != nil { - return nil, pkgerrors.Wrap(err, "failed to get CSA key for mercury connection") - } - - clients := make(map[string]wsrpc.Client) - for _, server := range mercuryConfig.GetServers() { - clients[server.URL], err = r.mercuryPool.Checkout(ctx, privKey, server.PubKey, server.URL) - if err != nil { - return nil, err - } - } // initialize trigger capability service lazily if relayConfig.EnableTriggerCapability && r.triggerCapability == nil { @@ -470,44 +443,7 @@ func (r *Relayer) NewMercuryProvider(ctx context.Context, rargs commontypes.Rela } } - reportCodecV1 := reportcodecv1.NewReportCodec(*relayConfig.FeedID, lggr.Named("ReportCodecV1")) - reportCodecV2 := reportcodecv2.NewReportCodec(*relayConfig.FeedID, lggr.Named("ReportCodecV2")) - reportCodecV3 := reportcodecv3.NewReportCodec(*relayConfig.FeedID, lggr.Named("ReportCodecV3")) - reportCodecV4 := reportcodecv4.NewReportCodec(*relayConfig.FeedID, lggr.Named("ReportCodecV4")) - - getCodecForFeed := func(feedID mercuryutils.FeedID) (mercury.TransmitterReportDecoder, error) { - var transmitterCodec mercury.TransmitterReportDecoder - switch feedID.Version() { - case 1: - transmitterCodec = reportCodecV1 - case 2: - transmitterCodec = reportCodecV2 - case 3: - transmitterCodec = reportCodecV3 - case 4: - transmitterCodec = reportCodecV4 - default: - return nil, fmt.Errorf("invalid feed version %d", feedID.Version()) - } - return transmitterCodec, nil - } - - benchmarkPriceDecoder := func(ctx context.Context, feedID mercuryutils.FeedID, report ocrtypes.Report) (*big.Int, error) { - benchmarkPriceCodec, benchmarkPriceErr := getCodecForFeed(feedID) - if benchmarkPriceErr != nil { - return nil, benchmarkPriceErr - } - return benchmarkPriceCodec.BenchmarkPriceFromReport(ctx, report) - } - - transmitterCodec, err := getCodecForFeed(mercuryutils.FeedID(*relayConfig.FeedID)) - if err != nil { - return nil, err - } - - transmitter := mercury.NewTransmitter(lggr, r.mercuryCfg.Transmitter(), clients, privKey.PublicKey, rargs.JobID, *relayConfig.FeedID, r.mercuryORM, transmitterCodec, benchmarkPriceDecoder, r.triggerCapability) - - return NewMercuryProvider(cp, r.codec, NewMercuryChainReader(r.chain.HeadTracker()), transmitter, reportCodecV1, reportCodecV2, reportCodecV3, reportCodecV4, lggr), nil + return NewMercuryProvider(ctx, rargs.JobID, relayConfig, mercuryConfig, r.mercuryCfg.Transmitter(), cp, r.codec, NewMercuryChainReader(r.chain.HeadTracker()), lggr, r.csaKeystore, r.mercuryPool, r.mercuryORM, r.triggerCapability) } func chainToUUID(chainID *big.Int) uuid.UUID { @@ -582,7 +518,7 @@ func (r *Relayer) NewCCIPCommitProvider(ctx context.Context, rargs commontypes.R return nil, err } subjectID := chainToUUID(configWatcher.chain.ID()) - contractTransmitter, err := newOnChainContractTransmitter(ctx, r.lggr, rargs, r.ks.Eth(), configWatcher, configTransmitterOpts{ + contractTransmitter, err := newOnChainContractTransmitter(ctx, r.lggr, rargs, r.evmKeystore, configWatcher, configTransmitterOpts{ subjectID: &subjectID, }, OCR2AggregatorTransmissionContractABI, WithReportToEthMetadata(fn), WithRetention(0)) if err != nil { @@ -666,7 +602,7 @@ func (r *Relayer) NewCCIPExecProvider(ctx context.Context, rargs commontypes.Rel return nil, err } subjectID := chainToUUID(configWatcher.chain.ID()) - contractTransmitter, err := newOnChainContractTransmitter(ctx, r.lggr, rargs, r.ks.Eth(), configWatcher, configTransmitterOpts{ + contractTransmitter, err := newOnChainContractTransmitter(ctx, r.lggr, rargs, r.evmKeystore, configWatcher, configTransmitterOpts{ subjectID: &subjectID, }, OCR2AggregatorTransmissionContractABI, WithReportToEthMetadata(fn), WithRetention(0), WithExcludeSignatures()) if err != nil { @@ -716,88 +652,19 @@ func (r *Relayer) NewLLOProvider(ctx context.Context, rargs commontypes.RelayArg return nil, fmt.Errorf("LLOConfigMode must be specified in relayConfig for LLO jobs (only %q or %q is currently supported)", types.LLOConfigModeMercury, types.LLOConfigModeBlueGreen) } - var lloCfg lloconfig.PluginConfig - if err = json.Unmarshal(pargs.PluginConfig, &lloCfg); err != nil { - return nil, pkgerrors.WithStack(err) - } - if err = lloCfg.Validate(); err != nil { - return nil, err - } - privKey, err := r.ks.CSA().Get(relayConfig.EffectiveTransmitterID.String) - if err != nil { - return nil, pkgerrors.Wrap(err, "failed to get CSA key for mercury connection") - } - - var transmitter LLOTransmitter - if lloCfg.BenchmarkMode { - lggr.Info("Benchmark mode enabled, using dummy transmitter. NOTE: THIS WILL NOT TRANSMIT ANYTHING") - transmitter = bm.NewTransmitter(lggr, fmt.Sprintf("%x", privKey.PublicKey)) - } else { - clients := make(map[string]grpc.Client) - for _, server := range lloCfg.GetServers() { - var client grpc.Client - switch r.mercuryCfg.Transmitter().Protocol() { - case config.MercuryTransmitterProtocolGRPC: - client = grpc.NewClient(grpc.ClientOpts{ - Logger: lggr.Named(fmt.Sprintf("%q", server.URL)).With("serverURL", server.URL), - ClientPrivKey: privKey.PrivateKey(), - ServerPubKey: ed25519.PublicKey(server.PubKey), - ServerURL: server.URL, - }) - case config.MercuryTransmitterProtocolWSRPC: - wsrpcClient, checkoutErr := r.mercuryPool.Checkout(ctx, privKey, server.PubKey, server.URL) - if checkoutErr != nil { - return nil, checkoutErr - } - client = wsrpc.GRPCCompatibilityWrapper{Client: wsrpcClient} - default: - return nil, fmt.Errorf("unsupported protocol %q", r.mercuryCfg.Transmitter().Protocol()) - } - clients[server.URL] = client - } - // FIXME: The transmitter instantiation really ought to be moved out of - // the evm relay into llo package - // https://smartcontract-it.atlassian.net/browse/MERC-6847 - transmitter, err = llo.NewTransmitter(llo.TransmitterOpts{ - Lggr: lggr, - DonID: lloCfg.DonID, - FromAccount: fmt.Sprintf("%x", privKey.PublicKey), // NOTE: This may need to change if we support e.g. multiple tranmsmitters, to be a composite of all keys - VerboseLogging: r.mercuryCfg.VerboseLogging(), - MercuryTransmitterOpts: mercurytransmitter.Opts{ - Lggr: lggr, - VerboseLogging: r.mercuryCfg.VerboseLogging(), - Cfg: r.mercuryCfg.Transmitter(), - Clients: clients, - FromAccount: privKey.PublicKey, - DonID: lloCfg.DonID, - ORM: mercurytransmitter.NewORM(r.ds, relayConfig.LLODONID), - CapabilitiesRegistry: r.capabilitiesRegistry, - }, - Subtransmitters: lloCfg.Transmitters, - RetirementReportCache: r.retirementReportCache, - }) - if err != nil { - return nil, fmt.Errorf("failed to create LLO transmitter: %w", err) - } - } - cdcFactory, err := r.cdcFactory() if err != nil { return nil, err } - cdc, err := cdcFactory.NewCache(lloCfg) - if err != nil { - return nil, err - } configuratorAddress := common.HexToAddress(relayOpts.ContractID) - return NewLLOProvider(ctx, transmitter, lggr, r.retirementReportCache, r.chain, configuratorAddress, cdc, relayConfig, relayOpts) + return NewLLOProvider(ctx, lggr, pargs, r.retirementReportCache, r.chain, configuratorAddress, cdcFactory, relayConfig, relayOpts, r.csaKeystore, r.mercuryCfg, r.retirementReportCache, r.ds, r.mercuryPool, r.capabilitiesRegistry) } func (r *Relayer) NewFunctionsProvider(ctx context.Context, rargs commontypes.RelayArgs, pargs commontypes.PluginArgs) (commontypes.FunctionsProvider, error) { lggr := r.lggr.Named("FunctionsProvider").Named(rargs.ExternalJobID.String()) // TODO(FUN-668): Not ready yet (doesn't implement FunctionsEvents() properly) - return NewFunctionsProvider(ctx, r.chain, rargs, pargs, lggr, r.ks.Eth(), functions.FunctionsPlugin) + return NewFunctionsProvider(ctx, r.chain, rargs, pargs, lggr, r.evmKeystore, functions.FunctionsPlugin) } // NewConfigProvider is called by bootstrap jobs @@ -939,7 +806,7 @@ type configTransmitterOpts struct { } // newOnChainContractTransmitter creates a new contract transmitter. -func newOnChainContractTransmitter(ctx context.Context, lggr logger.Logger, rargs commontypes.RelayArgs, ethKeystore keystore.Eth, configWatcher *configWatcher, opts configTransmitterOpts, transmissionContractABI abi.ABI, ocrTransmitterOpts ...OCRTransmitterOption) (*contractTransmitter, error) { +func newOnChainContractTransmitter(ctx context.Context, lggr logger.Logger, rargs commontypes.RelayArgs, ethKeystore keys.Store, configWatcher *configWatcher, opts configTransmitterOpts, transmissionContractABI abi.ABI, ocrTransmitterOpts ...OCRTransmitterOption) (*contractTransmitter, error) { transmitter, err := generateTransmitterFrom(ctx, rargs, ethKeystore, configWatcher, opts) if err != nil { return nil, err @@ -959,7 +826,7 @@ func newOnChainContractTransmitter(ctx context.Context, lggr logger.Logger, rarg } // newOnChainDualContractTransmitter creates a new dual contract transmitter. -func newOnChainDualContractTransmitter(ctx context.Context, lggr logger.Logger, rargs commontypes.RelayArgs, ethKeystore keystore.Eth, configWatcher *configWatcher, opts configTransmitterOpts, transmissionContractABI abi.ABI, ocrTransmitterOpts ...OCRTransmitterOption) (*dualContractTransmitter, error) { +func newOnChainDualContractTransmitter(ctx context.Context, lggr logger.Logger, rargs commontypes.RelayArgs, ethKeystore keys.Store, configWatcher *configWatcher, opts configTransmitterOpts, transmissionContractABI abi.ABI, ocrTransmitterOpts ...OCRTransmitterOption) (*dualContractTransmitter, error) { transmitter, err := generateTransmitterFrom(ctx, rargs, ethKeystore, configWatcher, opts) if err != nil { return nil, err @@ -978,7 +845,7 @@ func newOnChainDualContractTransmitter(ctx context.Context, lggr logger.Logger, ) } -func NewContractTransmitter(ctx context.Context, lggr logger.Logger, rargs commontypes.RelayArgs, ethKeystore keystore.Eth, configWatcher *configWatcher, opts configTransmitterOpts, transmissionContractABI abi.ABI, dualTransmission bool, ocrTransmitterOpts ...OCRTransmitterOption) (ContractTransmitter, error) { +func NewContractTransmitter(ctx context.Context, lggr logger.Logger, rargs commontypes.RelayArgs, ethKeystore keys.Store, configWatcher *configWatcher, opts configTransmitterOpts, transmissionContractABI abi.ABI, dualTransmission bool, ocrTransmitterOpts ...OCRTransmitterOption) (ContractTransmitter, error) { if dualTransmission { return newOnChainDualContractTransmitter(ctx, lggr, rargs, ethKeystore, configWatcher, opts, transmissionContractABI, ocrTransmitterOpts...) } @@ -986,7 +853,13 @@ func NewContractTransmitter(ctx context.Context, lggr logger.Logger, rargs commo return newOnChainContractTransmitter(ctx, lggr, rargs, ethKeystore, configWatcher, opts, transmissionContractABI, ocrTransmitterOpts...) } -func generateTransmitterFrom(ctx context.Context, rargs commontypes.RelayArgs, ethKeystore keystore.Eth, configWatcher *configWatcher, opts configTransmitterOpts) (Transmitter, error) { +type Keystore interface { + keys.AddressChecker + keys.RoundRobin + keys.Locker +} + +func generateTransmitterFrom(ctx context.Context, rargs commontypes.RelayArgs, ethKeystore Keystore, configWatcher *configWatcher, opts configTransmitterOpts) (Transmitter, error) { var relayConfig types.RelayConfig if err := json.Unmarshal(rargs.RelayConfig, &relayConfig); err != nil { return nil, err @@ -1009,7 +882,7 @@ func generateTransmitterFrom(ctx context.Context, rargs commontypes.RelayArgs, e if sendingKeysLength > 1 && s == effectiveTransmitterAddress.String() { return nil, pkgerrors.New("the transmitter is a local sending key with transaction forwarding enabled") } - if err := ethKeystore.CheckEnabled(ctx, common.HexToAddress(s), configWatcher.chain.Config().EVM().ChainID()); err != nil { + if err := ethKeystore.CheckEnabled(ctx, common.HexToAddress(s)); err != nil { return nil, pkgerrors.Wrap(err, "one of the sending keys given is not enabled") } fromAddresses = append(fromAddresses, common.HexToAddress(s)) @@ -1041,7 +914,6 @@ func generateTransmitterFrom(ctx context.Context, rargs commontypes.RelayArgs, e switch commontypes.OCR2PluginType(rargs.ProviderType) { case commontypes.Median: transmitter, err = ocrcommon.NewOCR2FeedsTransmitter( - ctx, configWatcher.chain.TxManager(), fromAddresses, common.HexToAddress(rargs.ContractID), @@ -1049,7 +921,6 @@ func generateTransmitterFrom(ctx context.Context, rargs commontypes.RelayArgs, e effectiveTransmitterAddress, strategy, checker, - configWatcher.chain.ID(), ethKeystore, relayConfig.DualTransmissionConfig, ) @@ -1072,7 +943,6 @@ func generateTransmitterFrom(ctx context.Context, rargs commontypes.RelayArgs, e effectiveTransmitterAddress, strategy, checker, - configWatcher.chain.ID(), ethKeystore, ) } @@ -1124,7 +994,7 @@ func (r *Relayer) NewMedianProvider(ctx context.Context, rargs commontypes.Relay reportCodec := evmreportcodec.ReportCodec{} - ct, err := NewContractTransmitter(ctx, lggr, rargs, r.ks.Eth(), configWatcher, configTransmitterOpts{}, OCR2AggregatorTransmissionContractABI, relayConfig.EnableDualTransmission) + ct, err := NewContractTransmitter(ctx, lggr, rargs, r.evmKeystore, configWatcher, configTransmitterOpts{}, OCR2AggregatorTransmissionContractABI, relayConfig.EnableDualTransmission) if err != nil { return nil, err } @@ -1172,7 +1042,7 @@ func (r *Relayer) NewMedianProvider(ctx context.Context, rargs commontypes.Relay func (r *Relayer) NewAutomationProvider(ctx context.Context, rargs commontypes.RelayArgs, pargs commontypes.PluginArgs) (commontypes.AutomationProvider, error) { lggr := logger.Sugared(r.lggr).Named("AutomationProvider").Named(rargs.ExternalJobID.String()) - ocr2keeperRelayer := NewOCR2KeeperRelayer(r.ds, r.chain, lggr.Named("OCR2KeeperRelayer"), r.ks.Eth()) + ocr2keeperRelayer := NewOCR2KeeperRelayer(r.ds, r.chain, lggr.Named("OCR2KeeperRelayer"), r.evmKeystore) return ocr2keeperRelayer.NewOCR2KeeperProvider(ctx, rargs, pargs) } diff --git a/core/services/relay/evm/evm_test.go b/core/services/relay/evm/evm_test.go index 39869f79def..ba4d088f3ba 100644 --- a/core/services/relay/evm/evm_test.go +++ b/core/services/relay/evm/evm_test.go @@ -6,15 +6,16 @@ import ( "github.com/stretchr/testify/assert" "github.com/smartcontractkit/chainlink-common/pkg/sqlutil" - coretypes "github.com/smartcontractkit/chainlink-common/pkg/types/core" + "github.com/smartcontractkit/chainlink-common/pkg/types/core" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm" ) func TestRelayerOpts_Validate(t *testing.T) { type fields struct { DS sqlutil.DataSource - CSAETHKeystore evm.CSAETHKeystore - CapabilitiesRegistry coretypes.CapabilitiesRegistry + CSAKeystore core.Keystore + EVMKeystore core.Keystore + CapabilitiesRegistry core.CapabilitiesRegistry } tests := []struct { name string @@ -25,11 +26,13 @@ func TestRelayerOpts_Validate(t *testing.T) { name: "all invalid", fields: fields{ DS: nil, - CSAETHKeystore: nil, + EVMKeystore: nil, + CSAKeystore: nil, CapabilitiesRegistry: nil, }, wantErrContains: `nil DataSource -nil Keystore`, +nil CSAKeystore +nil EVMKeystore`, }, { name: "missing ds, keystore", @@ -37,7 +40,8 @@ nil Keystore`, DS: nil, }, wantErrContains: `nil DataSource -nil Keystore`, +nil CSAKeystore +nil EVMKeystore`, }, { name: "missing ds, keystore, capabilitiesRegistry", @@ -45,7 +49,8 @@ nil Keystore`, DS: nil, }, wantErrContains: `nil DataSource -nil Keystore +nil CSAKeystore +nil EVMKeystore nil CapabilitiesRegistry`, }, } @@ -53,7 +58,8 @@ nil CapabilitiesRegistry`, t.Run(tt.name, func(t *testing.T) { c := evm.RelayerOpts{ DS: tt.fields.DS, - CSAETHKeystore: tt.fields.CSAETHKeystore, + EVMKeystore: tt.fields.EVMKeystore, + CSAKeystore: tt.fields.CSAKeystore, CapabilitiesRegistry: tt.fields.CapabilitiesRegistry, } err := c.Validate() diff --git a/core/services/relay/evm/functions.go b/core/services/relay/evm/functions.go index 976c7ad8a12..f465c95055a 100644 --- a/core/services/relay/evm/functions.go +++ b/core/services/relay/evm/functions.go @@ -13,11 +13,10 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/services" commontypes "github.com/smartcontractkit/chainlink-common/pkg/types" - txmgrcommon "github.com/smartcontractkit/chainlink-framework/chains/txmgr" + "github.com/smartcontractkit/chainlink-integrations/evm/keys" txm "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/functions/config" functionsRelay "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/functions" evmRelayTypes "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/types" @@ -79,7 +78,7 @@ func (p *functionsProvider) Codec() commontypes.Codec { return nil } -func NewFunctionsProvider(ctx context.Context, chain legacyevm.Chain, rargs commontypes.RelayArgs, pargs commontypes.PluginArgs, lggr logger.Logger, ethKeystore keystore.Eth, pluginType functionsRelay.FunctionsPluginType) (evmRelayTypes.FunctionsProvider, error) { +func NewFunctionsProvider(ctx context.Context, chain legacyevm.Chain, rargs commontypes.RelayArgs, pargs commontypes.PluginArgs, lggr logger.Logger, ethKeystore keys.Store, pluginType functionsRelay.FunctionsPluginType) (evmRelayTypes.FunctionsProvider, error) { relayOpts := evmRelayTypes.NewRelayOpts(rargs) relayConfig, err := relayOpts.RelayConfig() if err != nil { @@ -139,7 +138,7 @@ func newFunctionsConfigProvider(ctx context.Context, pluginType functionsRelay.F return newConfigWatcher(lggr, routerContractAddress, offchainConfigDigester, cp, chain, fromBlock, args.New), nil } -func newFunctionsContractTransmitter(ctx context.Context, contractVersion uint32, rargs commontypes.RelayArgs, transmitterID string, configWatcher *configWatcher, ethKeystore keystore.Eth, logPollerWrapper evmRelayTypes.LogPollerWrapper, lggr logger.Logger) (ContractTransmitter, error) { +func newFunctionsContractTransmitter(ctx context.Context, contractVersion uint32, rargs commontypes.RelayArgs, transmitterID string, configWatcher *configWatcher, ethKeystore keys.Store, logPollerWrapper evmRelayTypes.LogPollerWrapper, lggr logger.Logger) (ContractTransmitter, error) { var relayConfig evmRelayTypes.RelayConfig if err := json.Unmarshal(rargs.RelayConfig, &relayConfig); err != nil { return nil, err @@ -162,7 +161,7 @@ func newFunctionsContractTransmitter(ctx context.Context, contractVersion uint32 if sendingKeysLength > 1 && s == effectiveTransmitterAddress.String() { return nil, errors.New("the transmitter is a local sending key with transaction forwarding enabled") } - if err := ethKeystore.CheckEnabled(ctx, common.HexToAddress(s), configWatcher.chain.Config().EVM().ChainID()); err != nil { + if err := ethKeystore.CheckEnabled(ctx, common.HexToAddress(s)); err != nil { return nil, errors.Wrap(err, "one of the sending keys given is not enabled") } fromAddresses = append(fromAddresses, common.HexToAddress(s)) @@ -193,7 +192,6 @@ func newFunctionsContractTransmitter(ctx context.Context, contractVersion uint32 effectiveTransmitterAddress, strategy, checker, - configWatcher.chain.ID(), ethKeystore, ) if err != nil { diff --git a/core/services/relay/evm/functions/contract_transmitter.go b/core/services/relay/evm/functions/contract_transmitter.go index edf192f076c..72879e467ce 100644 --- a/core/services/relay/evm/functions/contract_transmitter.go +++ b/core/services/relay/evm/functions/contract_transmitter.go @@ -18,8 +18,8 @@ import ( ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" "github.com/smartcontractkit/chainlink-common/pkg/logger" - "github.com/smartcontractkit/chainlink-framework/chains/txmgr/types" + "github.com/smartcontractkit/chainlink-integrations/evm/keys" "github.com/smartcontractkit/chainlink-integrations/evm/logpoller" "github.com/smartcontractkit/chainlink-integrations/evm/utils" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" @@ -28,10 +28,6 @@ import ( evmRelayTypes "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/types" ) -type roundRobinKeystore interface { - GetRoundRobinAddress(ctx context.Context, chainID *big.Int, addresses ...common.Address) (address common.Address, err error) -} - type txManager interface { CreateTransaction(ctx context.Context, txRequest txmgr.TxRequest) (tx txmgr.Tx, err error) } @@ -58,8 +54,7 @@ type contractTransmitter struct { effectiveTransmitterAddress common.Address strategy types.TxStrategy checker txmgr.TransmitCheckerSpec - chainID *big.Int - keystore roundRobinKeystore + keystore keys.RoundRobin } var _ FunctionsContractTransmitter = &contractTransmitter{} @@ -81,8 +76,7 @@ func NewFunctionsContractTransmitter( effectiveTransmitterAddress common.Address, strategy types.TxStrategy, checker txmgr.TransmitCheckerSpec, - chainID *big.Int, - keystore roundRobinKeystore, + keystore keys.RoundRobin, ) (*contractTransmitter, error) { // Ensure that a keystore is provided. if keystore == nil { @@ -116,13 +110,12 @@ func NewFunctionsContractTransmitter( effectiveTransmitterAddress: effectiveTransmitterAddress, strategy: strategy, checker: checker, - chainID: chainID, keystore: keystore, }, nil } func (oc *contractTransmitter) createEthTransaction(ctx context.Context, toAddress common.Address, payload []byte) error { - roundRobinFromAddress, err := oc.keystore.GetRoundRobinAddress(ctx, oc.chainID, oc.fromAddresses...) + roundRobinFromAddress, err := oc.keystore.GetNextAddress(ctx, oc.fromAddresses...) if err != nil { return errors.Wrap(err, "skipped OCR transmission, error getting round-robin address") } diff --git a/core/services/relay/evm/functions/contract_transmitter_test.go b/core/services/relay/evm/functions/contract_transmitter_test.go index 4b5b7d9bcf3..dd7eb8f2c4a 100644 --- a/core/services/relay/evm/functions/contract_transmitter_test.go +++ b/core/services/relay/evm/functions/contract_transmitter_test.go @@ -2,28 +2,28 @@ package functions_test import ( "encoding/hex" - "math/big" "strings" "testing" "github.com/ethereum/go-ethereum/accounts/abi" gethcommon "github.com/ethereum/go-ethereum/common" - "github.com/smartcontractkit/libocr/gethwrappers2/ocr2aggregator" - "github.com/smartcontractkit/libocr/offchainreporting2plus/chains/evmutil" - ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" + "github.com/smartcontractkit/libocr/gethwrappers2/ocr2aggregator" + "github.com/smartcontractkit/libocr/offchainreporting2plus/chains/evmutil" + ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" + "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-integrations/evm/client/clienttest" + "github.com/smartcontractkit/chainlink-integrations/evm/keys/keystest" commontxmmocks "github.com/smartcontractkit/chainlink/v2/common/txmgr/types/mocks" lpmocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller/mocks" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" txmmocks "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr/mocks" "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/functions/encoding" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/functions" ) @@ -36,9 +36,6 @@ func TestContractTransmitter_LatestConfigDigestAndEpoch(t *testing.T) { t.Parallel() ctx := testutils.Context(t) - db := pgtest.NewSqlxDB(t) - ethKeyStore := cltest.NewKeyStore(t, db).Eth() - digestStr := "000130da6b9315bd59af6b0a3f5463c0d0a39e92eaa34cbcbdbace7b3bfcc776" lggr := logger.Test(t) c := clienttest.NewClient(t) @@ -52,9 +49,9 @@ func TestContractTransmitter_LatestConfigDigestAndEpoch(t *testing.T) { contractABI, err := abi.JSON(strings.NewReader(ocr2aggregator.OCR2AggregatorABI)) require.NoError(t, err) txm := txmmocks.NewMockEvmTxManager(t) - _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore) + fromAddress := cltest.MustGenerateRandomKey(t).Address + ethKeyStore := keystest.Addresses{fromAddress} gasLimit := uint64(1000) - chainID := big.NewInt(0) effectiveTransmitterAddress := fromAddress strategy := newMockTxStrategy(t) lp.On("RegisterFilter", mock.Anything, mock.Anything).Return(nil) @@ -71,7 +68,6 @@ func TestContractTransmitter_LatestConfigDigestAndEpoch(t *testing.T) { effectiveTransmitterAddress, strategy, txmgr.TransmitCheckerSpec{}, - chainID, ethKeyStore, ) require.NoError(t, err) @@ -87,9 +83,6 @@ func TestContractTransmitter_Transmit_V1(t *testing.T) { t.Parallel() ctx := testutils.Context(t) - db := pgtest.NewSqlxDB(t) - ethKeyStore := cltest.NewKeyStore(t, db).Eth() - contractVersion := uint32(1) configuredDestAddress, coordinatorAddress := testutils.NewAddress(), testutils.NewAddress() lggr := logger.Test(t) @@ -97,9 +90,9 @@ func TestContractTransmitter_Transmit_V1(t *testing.T) { lp := lpmocks.NewLogPoller(t) contractABI, _ := abi.JSON(strings.NewReader(ocr2aggregator.OCR2AggregatorABI)) txm := txmmocks.NewMockEvmTxManager(t) - _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore) + fromAddress := cltest.MustGenerateRandomKey(t).Address + ethKeyStore := keystest.Addresses{fromAddress} gasLimit := uint64(1000) - chainID := big.NewInt(0) effectiveTransmitterAddress := fromAddress strategy := newMockTxStrategy(t) lp.On("RegisterFilter", mock.Anything, mock.Anything).Return(nil) @@ -116,7 +109,6 @@ func TestContractTransmitter_Transmit_V1(t *testing.T) { effectiveTransmitterAddress, strategy, txmgr.TransmitCheckerSpec{}, - chainID, ethKeyStore, ) require.NoError(t, err) @@ -165,9 +157,6 @@ func TestContractTransmitter_Transmit_V1_CoordinatorMismatch(t *testing.T) { t.Parallel() ctx := testutils.Context(t) - db := pgtest.NewSqlxDB(t) - ethKeyStore := cltest.NewKeyStore(t, db).Eth() - contractVersion := uint32(1) configuredDestAddress, coordinatorAddress1, coordinatorAddress2 := testutils.NewAddress(), testutils.NewAddress(), testutils.NewAddress() lggr := logger.Test(t) @@ -175,9 +164,10 @@ func TestContractTransmitter_Transmit_V1_CoordinatorMismatch(t *testing.T) { lp := lpmocks.NewLogPoller(t) contractABI, _ := abi.JSON(strings.NewReader(ocr2aggregator.OCR2AggregatorABI)) txm := txmmocks.NewMockEvmTxManager(t) - _, fromAddress := cltest.MustInsertRandomKey(t, ethKeyStore) + fromAddress := cltest.MustGenerateRandomKey(t).Address + ethKeyStore := keystest.Addresses{fromAddress} gasLimit := uint64(1000) - chainID := big.NewInt(0) + effectiveTransmitterAddress := fromAddress strategy := newMockTxStrategy(t) lp.On("RegisterFilter", mock.Anything, mock.Anything).Return(nil) @@ -194,7 +184,6 @@ func TestContractTransmitter_Transmit_V1_CoordinatorMismatch(t *testing.T) { effectiveTransmitterAddress, strategy, txmgr.TransmitCheckerSpec{}, - chainID, ethKeyStore, ) require.NoError(t, err) diff --git a/core/services/relay/evm/llo_provider.go b/core/services/relay/evm/llo_provider.go index 83e62f75f33..5143959f58c 100644 --- a/core/services/relay/evm/llo_provider.go +++ b/core/services/relay/evm/llo_provider.go @@ -2,24 +2,36 @@ package evm import ( "context" + "crypto/ed25519" + "encoding/json" "errors" "fmt" "math/big" "github.com/ethereum/go-ethereum/common" + pkgerrors "github.com/pkg/errors" + ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/sqlutil" commontypes "github.com/smartcontractkit/chainlink-common/pkg/types" relaytypes "github.com/smartcontractkit/chainlink-common/pkg/types" + coretypes "github.com/smartcontractkit/chainlink-common/pkg/types/core" llotypes "github.com/smartcontractkit/chainlink-common/pkg/types/llo" - "github.com/smartcontractkit/chainlink-integrations/evm/logpoller" "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" - "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/llo" + "github.com/smartcontractkit/chainlink/v2/core/config" + "github.com/smartcontractkit/chainlink/v2/core/services/llo" + "github.com/smartcontractkit/chainlink/v2/core/services/llo/bm" + "github.com/smartcontractkit/chainlink/v2/core/services/llo/grpc" + "github.com/smartcontractkit/chainlink/v2/core/services/llo/mercurytransmitter" + lloconfig "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/llo/config" + evmllo "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/llo" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury" + "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/wsrpc" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/types" ) @@ -39,13 +51,14 @@ type lloProvider struct { services.Service eng *services.Engine - cps []llo.ConfigPollerService + cps []evmllo.ConfigPollerService transmitter LLOTransmitter logger logger.Logger channelDefinitionCache llotypes.ChannelDefinitionCache digester ocrtypes.OffchainConfigDigester - shouldRetireCache llo.ShouldRetireCacheService + shouldRetireCache evmllo.ShouldRetireCacheService + csaSigner *coretypes.Ed25519Signer lp FilterRegisterer runReplay bool @@ -60,14 +73,20 @@ func lloProviderConfiguratorFilterName(addr common.Address, donID uint32) string func NewLLOProvider( ctx context.Context, - transmitter LLOTransmitter, lggr logger.Logger, - cc llo.ConfigCache, + pargs commontypes.PluginArgs, + cc evmllo.ConfigCache, chain legacyevm.Chain, configuratorAddress common.Address, - channelDefinitionCache llotypes.ChannelDefinitionCache, + cdcFactory llo.ChannelDefinitionCacheFactory, relayConfig types.RelayConfig, relayOpts *types.RelayOpts, + csaKeystore coretypes.Keystore, + mercuryCfg MercuryConfig, + retirementReportCache llo.RetirementReportCache, + ds sqlutil.DataSource, + mercuryPool wsrpc.Pool, + capabilitiesRegistry coretypes.CapabilitiesRegistry, ) (relaytypes.LLOProvider, error) { donID := relayConfig.LLODONID lp := chain.LogPoller() @@ -78,7 +97,81 @@ func NewLLOProvider( if err != nil { return nil, err } - src := llo.NewShouldRetireCache(lggr, lp, configuratorAddress, donID) + src := evmllo.NewShouldRetireCache(lggr, lp, configuratorAddress, donID) + + csaPub := relayConfig.EffectiveTransmitterID.String + csaSigner, err := coretypes.NewEd25519Signer(csaPub, csaKeystore.Sign) + if err != nil { + return nil, fmt.Errorf("failed to create ed25519 signer: %w", err) + } + + var lloCfg lloconfig.PluginConfig + if err = json.Unmarshal(pargs.PluginConfig, &lloCfg); err != nil { + return nil, pkgerrors.WithStack(err) + } + if err = lloCfg.Validate(); err != nil { + return nil, err + } + + var transmitter LLOTransmitter + if lloCfg.BenchmarkMode { + lggr.Info("Benchmark mode enabled, using dummy transmitter. NOTE: THIS WILL NOT TRANSMIT ANYTHING") + transmitter = bm.NewTransmitter(lggr, csaPub) + } else { + clients := make(map[string]grpc.Client) + for _, server := range lloCfg.GetServers() { + var client grpc.Client + switch mercuryCfg.Transmitter().Protocol() { + case config.MercuryTransmitterProtocolGRPC: + client = grpc.NewClient(grpc.ClientOpts{ + Logger: logger.Sugared(lggr). + Named(fmt.Sprintf("%q", server.URL)). + With("serverURL", server.URL), + ClientSigner: csaSigner, + ServerPubKey: ed25519.PublicKey(server.PubKey), + ServerURL: server.URL, + }) + case config.MercuryTransmitterProtocolWSRPC: + wsrpcClient, checkoutErr := mercuryPool.Checkout(ctx, csaPub, csaSigner, server.PubKey, server.URL) + if checkoutErr != nil { + return nil, checkoutErr + } + client = wsrpc.GRPCCompatibilityWrapper{Client: wsrpcClient} + default: + return nil, fmt.Errorf("unsupported protocol %q", mercuryCfg.Transmitter().Protocol()) + } + clients[server.URL] = client + } + // FIXME: The transmitter instantiation really ought to be moved out of + // the evm relay into llo package + // https://smartcontract-it.atlassian.net/browse/MERC-6847 + transmitter, err = llo.NewTransmitter(llo.TransmitterOpts{ + Lggr: lggr, + DonID: lloCfg.DonID, + FromAccount: csaPub, // NOTE: This may need to change if we support e.g. multiple tranmsmitters, to be a composite of all keys + VerboseLogging: mercuryCfg.VerboseLogging(), + MercuryTransmitterOpts: mercurytransmitter.Opts{ + Lggr: lggr, + VerboseLogging: mercuryCfg.VerboseLogging(), + Cfg: mercuryCfg.Transmitter(), + Clients: clients, + FromAccount: csaPub, + DonID: lloCfg.DonID, + ORM: mercurytransmitter.NewORM(ds, relayConfig.LLODONID), + CapabilitiesRegistry: capabilitiesRegistry, + }, + Subtransmitters: lloCfg.Transmitters, + RetirementReportCache: retirementReportCache, + }) + if err != nil { + return nil, fmt.Errorf("failed to create LLO transmitter: %w", err) + } + } + + cdc, err := cdcFactory.NewCache(lloCfg) + if err != nil { + return nil, err + } p := &lloProvider{ nil, @@ -86,9 +179,10 @@ func NewLLOProvider( cps, transmitter, logger.Named(lggr, "LLOProvider"), - channelDefinitionCache, + cdc, digester, src, + csaSigner, lp, relayOpts.New, relayConfig.FromBlock, @@ -121,7 +215,7 @@ func (p *lloProvider) start(ctx context.Context) error { } }) } - srvs := []services.StartClose{p.transmitter, p.channelDefinitionCache, p.shouldRetireCache} + srvs := []services.StartClose{p.transmitter, p.channelDefinitionCache, p.shouldRetireCache, p.csaSigner} for _, cp := range p.cps { srvs = append(srvs, cp) } @@ -218,9 +312,9 @@ func (w *mercuryConfigPollerWrapper) close() error { return w.ConfigPoller.Close() } -func newLLOConfigPollers(ctx context.Context, lggr logger.Logger, cc llo.ConfigCache, lp logpoller.LogPoller, chainID *big.Int, configuratorAddress common.Address, relayConfig types.RelayConfig) (cps []llo.ConfigPollerService, configDigester ocrtypes.OffchainConfigDigester, err error) { +func newLLOConfigPollers(ctx context.Context, lggr logger.Logger, cc evmllo.ConfigCache, lp logpoller.LogPoller, chainID *big.Int, configuratorAddress common.Address, relayConfig types.RelayConfig) (cps []evmllo.ConfigPollerService, configDigester ocrtypes.OffchainConfigDigester, err error) { donID := relayConfig.LLODONID - donIDHash := llo.DonIDToBytes32(donID) + donIDHash := evmllo.DonIDToBytes32(donID) switch relayConfig.LLOConfigMode { case types.LLOConfigModeMercury: // NOTE: This uses the old config digest prefix for compatibility with legacy contracts @@ -231,41 +325,41 @@ func newLLOConfigPollers(ctx context.Context, lggr logger.Logger, cc llo.ConfigC lggr, lp, configuratorAddress, - llo.DonIDToBytes32(donID), + evmllo.DonIDToBytes32(donID), ) if err != nil { return nil, nil, err } // don't need to replay in the wrapper since the provider will handle it w := newMercuryConfigPollerWrapper(lggr, mcp, relayConfig.FromBlock, false) - cps = []llo.ConfigPollerService{w} + cps = []evmllo.ConfigPollerService{w} case types.LLOConfigModeBlueGreen: // NOTE: Register filter here because the config poller doesn't do it on its own - err := lp.RegisterFilter(ctx, logpoller.Filter{Name: lloProviderConfiguratorFilterName(configuratorAddress, donID), EventSigs: []common.Hash{llo.ProductionConfigSet, llo.StagingConfigSet, llo.PromoteStagingConfig}, Topic2: []common.Hash{donIDHash}, Addresses: []common.Address{configuratorAddress}}) + err := lp.RegisterFilter(ctx, logpoller.Filter{Name: lloProviderConfiguratorFilterName(configuratorAddress, donID), EventSigs: []common.Hash{evmllo.ProductionConfigSet, evmllo.StagingConfigSet, evmllo.PromoteStagingConfig}, Topic2: []common.Hash{donIDHash}, Addresses: []common.Address{configuratorAddress}}) if err != nil { return nil, nil, fmt.Errorf("failed to register filter: %w", err) } - configDigester = llo.NewOffchainConfigDigester(donIDHash, chainID, configuratorAddress, ocrtypes.ConfigDigestPrefixLLO) - blueCP := llo.NewConfigPoller( + configDigester = evmllo.NewOffchainConfigDigester(donIDHash, chainID, configuratorAddress, ocrtypes.ConfigDigestPrefixLLO) + blueCP := evmllo.NewConfigPoller( lggr, lp, cc, configuratorAddress, donID, - llo.InstanceTypeBlue, + evmllo.InstanceTypeBlue, relayConfig.FromBlock, ) - greenCP := llo.NewConfigPoller( + greenCP := evmllo.NewConfigPoller( lggr, lp, cc, configuratorAddress, donID, - llo.InstanceTypeGreen, + evmllo.InstanceTypeGreen, relayConfig.FromBlock, ) - cps = []llo.ConfigPollerService{blueCP, greenCP} + cps = []evmllo.ConfigPollerService{blueCP, greenCP} } return cps, configDigester, nil } diff --git a/core/services/relay/evm/mercury/helpers_test.go b/core/services/relay/evm/mercury/helpers_test.go index f44594514d7..e316666e850 100644 --- a/core/services/relay/evm/mercury/helpers_test.go +++ b/core/services/relay/evm/mercury/helpers_test.go @@ -7,7 +7,6 @@ import ( "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/eth/ethconfig" @@ -35,10 +34,9 @@ import ( reportcodecv3 "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/v3/reportcodec" ) -var ( - sampleFeedID = [32]uint8{28, 145, 107, 74, 167, 229, 124, 167, 182, 138, 225, 191, 69, 101, 63, 86, 182, 86, 253, 58, 163, 53, 239, 127, 174, 105, 107, 102, 63, 27, 132, 114} - sampleClientPubKey = hexutil.MustDecode("0x724ff6eae9e900270edfff233e16322a70ec06e1a6e62a81ef13921f398f6c93") -) +const sampleClientPubKey = "0x724ff6eae9e900270edfff233e16322a70ec06e1a6e62a81ef13921f398f6c93" + +var sampleFeedID = [32]uint8{28, 145, 107, 74, 167, 229, 124, 167, 182, 138, 225, 191, 69, 101, 63, 86, 182, 86, 253, 58, 163, 53, 239, 127, 174, 105, 107, 102, 63, 27, 132, 114} var sampleReports [][]byte diff --git a/core/services/relay/evm/mercury/transmitter.go b/core/services/relay/evm/mercury/transmitter.go index be500593bf3..0064c33fda7 100644 --- a/core/services/relay/evm/mercury/transmitter.go +++ b/core/services/relay/evm/mercury/transmitter.go @@ -3,7 +3,6 @@ package mercury import ( "bytes" "context" - "crypto/ed25519" "errors" "fmt" "io" @@ -306,7 +305,7 @@ func newServer(lggr logger.Logger, cfg TransmitterConfig, client wsrpc.Client, p } } -func NewTransmitter(lggr logger.Logger, cfg TransmitterConfig, clients map[string]wsrpc.Client, fromAccount ed25519.PublicKey, jobID int32, feedID [32]byte, orm ORM, codec TransmitterReportDecoder, benchmarkPriceDecoder BenchmarkPriceDecoder, triggerCapability *triggers.MercuryTriggerService) *mercuryTransmitter { +func NewTransmitter(lggr logger.Logger, cfg TransmitterConfig, clients map[string]wsrpc.Client, fromAccountHex string, jobID int32, feedID [32]byte, orm ORM, codec TransmitterReportDecoder, benchmarkPriceDecoder BenchmarkPriceDecoder, triggerCapability *triggers.MercuryTriggerService) *mercuryTransmitter { sugared := logger.Sugared(lggr) feedIDHex := fmt.Sprintf("0x%x", feedID[:]) servers := make(map[string]*server, len(clients)) @@ -326,7 +325,7 @@ func NewTransmitter(lggr logger.Logger, cfg TransmitterConfig, clients map[strin triggerCapability, feedID, jobID, - fmt.Sprintf("%x", fromAccount), + fromAccountHex, make(services.StopChan), &sync.WaitGroup{}, } diff --git a/core/services/relay/evm/mercury/wsrpc/client.go b/core/services/relay/evm/mercury/wsrpc/client.go index 69db5508d77..7d37cdac741 100644 --- a/core/services/relay/evm/mercury/wsrpc/client.go +++ b/core/services/relay/evm/mercury/wsrpc/client.go @@ -2,6 +2,7 @@ package wsrpc import ( "context" + "crypto" "fmt" "sync" "sync/atomic" @@ -21,7 +22,6 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/services" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/csakey" "github.com/smartcontractkit/chainlink/v2/core/services/llo/grpc" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/wsrpc/cache" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/wsrpc/pb" @@ -84,7 +84,7 @@ type DialWithContextFunc func(ctxCaller context.Context, target string, opts ... type client struct { services.StateMachine - csaKey csakey.KeyV2 + csaSigner crypto.Signer serverPubKey []byte serverURL string @@ -111,11 +111,11 @@ type client struct { } type ClientOpts struct { - Logger logger.SugaredLogger - ClientPrivKey csakey.KeyV2 - ServerPubKey []byte - ServerURL string - CacheSet cache.CacheSet + Logger logger.SugaredLogger + CSASigner crypto.Signer + ServerPubKey []byte + ServerURL string + CacheSet cache.CacheSet // DialWithContext allows optional dependency injection for testing DialWithContext DialWithContextFunc @@ -132,14 +132,14 @@ func newClient(opts ClientOpts) *client { dialWithContext = opts.DialWithContext } else { // NOTE: Wrap here since wsrpc.DialWithContext returns a concrete *wsrpc.Conn, not an interface - dialWithContext = func(ctxCaller context.Context, target string, opts ...wsrpc.DialOption) (Conn, error) { - conn, err := wsrpc.DialWithContext(ctxCaller, target, opts...) + dialWithContext = func(ctx context.Context, target string, opts ...wsrpc.DialOption) (Conn, error) { + conn, err := wsrpc.DialWithContext(ctx, target, opts...) return conn, err } } return &client{ dialWithContext: dialWithContext, - csaKey: opts.ClientPrivKey, + csaSigner: opts.CSASigner, serverPubKey: opts.ServerPubKey, serverURL: opts.ServerURL, logger: opts.Logger.Named("WSRPC").Named(opts.ServerURL).With("serverURL", opts.ServerURL), @@ -181,7 +181,7 @@ func (w *client) dial(ctx context.Context, opts ...wsrpc.DialOption) error { w.dialCountMetric.Inc() conn, err := w.dialWithContext(ctx, w.serverURL, append(opts, - wsrpc.WithTransportCreds(w.csaKey.Raw().Bytes(), w.serverPubKey), + wsrpc.WithTransportSigner(w.csaSigner, w.serverPubKey), wsrpc.WithLogger(w.logger), )..., ) diff --git a/core/services/relay/evm/mercury/wsrpc/client_test.go b/core/services/relay/evm/mercury/wsrpc/client_test.go index 2df752730d0..ce965c9a7eb 100644 --- a/core/services/relay/evm/mercury/wsrpc/client_test.go +++ b/core/services/relay/evm/mercury/wsrpc/client_test.go @@ -2,6 +2,8 @@ package wsrpc import ( "context" + "math/big" + "math/rand/v2" "testing" "time" @@ -76,7 +78,7 @@ func Test_Client_Transmit(t *testing.T) { } opts := ClientOpts{ logger.Sugared(lggr), - csakey.KeyV2{}, + csakey.MustNewV2XXXTestingOnly(new(big.Int).SetInt64(rand.Int64())).PrivateKey(), nil, "", noopCacheSet, @@ -167,7 +169,7 @@ func Test_Client_LatestReport(t *testing.T) { conn := &mocks.MockConn{ Ready: true, } - c := newClient(ClientOpts{logger.Sugared(lggr), csakey.KeyV2{}, nil, "", cacheSet, nil}) + c := newClient(ClientOpts{logger.Sugared(lggr), csakey.MustNewV2XXXTestingOnly(big.NewInt(rand.Int64())).PrivateKey(), nil, "", cacheSet, nil}) c.conn = conn c.rawClient = wsrpcClient diff --git a/core/services/relay/evm/mercury/wsrpc/pool.go b/core/services/relay/evm/mercury/wsrpc/pool.go index 4cd3648e25e..f494a2489eb 100644 --- a/core/services/relay/evm/mercury/wsrpc/pool.go +++ b/core/services/relay/evm/mercury/wsrpc/pool.go @@ -2,15 +2,13 @@ package wsrpc import ( "context" + "crypto" "errors" "sync" - "github.com/smartcontractkit/wsrpc/credentials" - "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/services" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/csakey" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/wsrpc/cache" "github.com/smartcontractkit/chainlink/v2/core/utils" ) @@ -34,10 +32,11 @@ type connection struct { // Client will be nil when checkouts is empty, if len(checkouts) > 0 then it is expected to be a non-nil, started client Client - lggr logger.Logger - clientPrivKey csakey.KeyV2 - serverPubKey []byte - serverURL string + lggr logger.Logger + clientPubKeyHex string + clientSigner crypto.Signer + serverPubKey []byte + serverURL string pool *pool @@ -60,7 +59,7 @@ func (conn *connection) checkout(ctx context.Context) (cco *clientCheckout, err // not thread-safe, access must be serialized func (conn *connection) ensureStartedClient(ctx context.Context) error { if len(conn.checkouts) == 0 { - conn.Client = conn.pool.newClient(ClientOpts{logger.Sugared(conn.lggr), conn.clientPrivKey, conn.serverPubKey, conn.serverURL, conn.pool.cacheSet, nil}) + conn.Client = conn.pool.newClient(ClientOpts{logger.Sugared(conn.lggr), conn.clientSigner, conn.serverPubKey, conn.serverURL, conn.pool.cacheSet, nil}) return conn.Client.Start(ctx) } return nil @@ -86,7 +85,7 @@ func (conn *connection) checkin(checkinCco *clientCheckout) { panic(err) } conn.Client = nil - conn.pool.remove(conn.serverURL, conn.clientPrivKey.StaticSizedPublicKey()) + conn.pool.remove(conn.serverURL, conn.clientPubKeyHex) } } @@ -111,14 +110,14 @@ type Pool interface { // The same underlying client can be checked out multiple times, the pool // handles lifecycle management. The consumer can treat it as if it were // its own unique client. - Checkout(ctx context.Context, clientPrivKey csakey.KeyV2, serverPubKey []byte, serverURL string) (client Client, err error) + Checkout(ctx context.Context, clientPubKeyHex string, clientSigner crypto.Signer, serverPubKey []byte, serverURL string) (client Client, err error) } // WSRPC allows only one connection per client key per server type pool struct { lggr logger.Logger - // server url => client public key => connection - connections map[string]map[credentials.StaticSizedPublicKey]*connection + // server url => client public key hex => connection + connections map[string]map[string]*connection // embedding newClient makes testing/mocking easier newClient func(opts ClientOpts) Client @@ -141,13 +140,11 @@ func NewPool(lggr logger.Logger, cacheCfg cache.Config) Pool { func newPool(lggr logger.Logger) *pool { return &pool{ lggr: lggr, - connections: make(map[string]map[credentials.StaticSizedPublicKey]*connection), + connections: make(map[string]map[string]*connection), } } -func (p *pool) Checkout(ctx context.Context, clientPrivKey csakey.KeyV2, serverPubKey []byte, serverURL string) (client Client, err error) { - clientPubKey := clientPrivKey.StaticSizedPublicKey() - +func (p *pool) Checkout(ctx context.Context, clientPubKeyHex string, clientSigner crypto.Signer, serverPubKey []byte, serverURL string) (client Client, err error) { p.mu.Lock() if p.closed { @@ -157,13 +154,13 @@ func (p *pool) Checkout(ctx context.Context, clientPrivKey csakey.KeyV2, serverP server, exists := p.connections[serverURL] if !exists { - server = make(map[credentials.StaticSizedPublicKey]*connection) + server = make(map[string]*connection) p.connections[serverURL] = server } - conn, exists := server[clientPubKey] + conn, exists := server[clientPubKeyHex] if !exists { - conn = p.newConnection(p.lggr, clientPrivKey, serverPubKey, serverURL) - server[clientPubKey] = conn + conn = p.newConnection(p.lggr, clientPubKeyHex, clientSigner, serverPubKey, serverURL) + server[clientPubKeyHex] = conn } p.mu.Unlock() @@ -174,22 +171,23 @@ func (p *pool) Checkout(ctx context.Context, clientPrivKey csakey.KeyV2, serverP } // remove performs garbage collection on the connections map after connections are no longer used -func (p *pool) remove(serverURL string, clientPubKey credentials.StaticSizedPublicKey) { +func (p *pool) remove(serverURL string, clientPubKeyHex string) { p.mu.Lock() defer p.mu.Unlock() - delete(p.connections[serverURL], clientPubKey) + delete(p.connections[serverURL], clientPubKeyHex) if len(p.connections[serverURL]) == 0 { delete(p.connections, serverURL) } } -func (p *pool) newConnection(lggr logger.Logger, clientPrivKey csakey.KeyV2, serverPubKey []byte, serverURL string) *connection { +func (p *pool) newConnection(lggr logger.Logger, clientPubKeyHex string, clientSigner crypto.Signer, serverPubKey []byte, serverURL string) *connection { return &connection{ - lggr: lggr, - clientPrivKey: clientPrivKey, - serverPubKey: serverPubKey, - serverURL: serverURL, - pool: p, + lggr: lggr, + clientPubKeyHex: clientPubKeyHex, + clientSigner: clientSigner, + serverPubKey: serverPubKey, + serverURL: serverURL, + pool: p, } } diff --git a/core/services/relay/evm/mercury/wsrpc/pool_test.go b/core/services/relay/evm/mercury/wsrpc/pool_test.go index a7015ed412e..040242aa6e4 100644 --- a/core/services/relay/evm/mercury/wsrpc/pool_test.go +++ b/core/services/relay/evm/mercury/wsrpc/pool_test.go @@ -65,13 +65,12 @@ func Test_Pool(t *testing.T) { client := newMockClient(lggr) p.newClient = func(opts ClientOpts) Client { - assert.Equal(t, clientPrivKey, opts.ClientPrivKey) assert.Equal(t, serverPubKey, opts.ServerPubKey) assert.Equal(t, serverURL, opts.ServerURL) return client } - c, err := p.Checkout(ctx, clientPrivKey, serverPubKey, serverURL) + c, err := p.Checkout(ctx, clientPrivKey.PublicKeyString(), clientPrivKey.PrivateKey(), serverPubKey, serverURL) require.NoError(t, err) assert.True(t, client.started) @@ -83,7 +82,7 @@ func Test_Pool(t *testing.T) { assert.Len(t, conn.checkouts, 1) assert.Same(t, lggr, conn.lggr) - assert.Equal(t, clientPrivKey, conn.clientPrivKey) + assert.Equal(t, clientPrivKey.PublicKeyString(), conn.clientPubKeyHex) assert.Equal(t, serverPubKey, conn.serverPubKey) assert.Equal(t, serverURL, conn.serverURL) assert.Same(t, p, conn.pool) @@ -260,7 +259,7 @@ func Test_Pool(t *testing.T) { } func mustCheckout(t *testing.T, p *pool, clientPrivKey csakey.KeyV2, serverPubKey []byte, serverURL string) Client { - c, err := p.Checkout(testutils.Context(t), clientPrivKey, serverPubKey, serverURL) + c, err := p.Checkout(testutils.Context(t), clientPrivKey.PublicKeyString(), clientPrivKey.PrivateKey(), serverPubKey, serverURL) require.NoError(t, err) return c } diff --git a/core/services/relay/evm/mercury_provider.go b/core/services/relay/evm/mercury_provider.go index 07e421c2136..1803d260507 100644 --- a/core/services/relay/evm/mercury_provider.go +++ b/core/services/relay/evm/mercury_provider.go @@ -3,23 +3,33 @@ package evm import ( "context" "errors" + "fmt" + "math/big" ocrtypes "github.com/smartcontractkit/libocr/offchainreporting2plus/types" + "github.com/smartcontractkit/chainlink-common/pkg/capabilities/triggers" "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/services" commontypes "github.com/smartcontractkit/chainlink-common/pkg/types" + coretypes "github.com/smartcontractkit/chainlink-common/pkg/types/core" mercurytypes "github.com/smartcontractkit/chainlink-common/pkg/types/mercury" v1 "github.com/smartcontractkit/chainlink-common/pkg/types/mercury/v1" v2 "github.com/smartcontractkit/chainlink-common/pkg/types/mercury/v2" v3 "github.com/smartcontractkit/chainlink-common/pkg/types/mercury/v3" v4 "github.com/smartcontractkit/chainlink-common/pkg/types/mercury/v4" - "github.com/smartcontractkit/chainlink-data-streams/mercury" - "github.com/smartcontractkit/chainlink-integrations/evm/heads" + "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/mercury/config" evmmercury "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury" + mercuryutils "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/utils" + reportcodecv1 "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/v1/reportcodec" + reportcodecv2 "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/v2/reportcodec" + reportcodecv3 "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/v3/reportcodec" + reportcodecv4 "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/v4/reportcodec" + "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/wsrpc" + "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/types" ) var _ commontypes.MercuryProvider = (*mercuryProvider)(nil) @@ -27,6 +37,7 @@ var _ commontypes.MercuryProvider = (*mercuryProvider)(nil) type mercuryProvider struct { cp commontypes.ConfigProvider codec commontypes.Codec + csaSigner *coretypes.Ed25519Signer transmitter evmmercury.Transmitter reportCodecV1 v1.ReportCodec reportCodecV2 v2.ReportCodec @@ -38,19 +49,71 @@ type mercuryProvider struct { } func NewMercuryProvider( + ctx context.Context, + jobID int32, + relayConfig types.RelayConfig, + cfg config.PluginConfig, + transmitterCfg evmmercury.TransmitterConfig, cp commontypes.ConfigProvider, codec commontypes.Codec, mercuryChainReader mercurytypes.ChainReader, - transmitter evmmercury.Transmitter, - reportCodecV1 v1.ReportCodec, - reportCodecV2 v2.ReportCodec, - reportCodecV3 v3.ReportCodec, - reportCodecV4 v4.ReportCodec, - lggr logger.Logger, -) *mercuryProvider { + lggr logger.SugaredLogger, + csaKeystore coretypes.Keystore, + mercuryPool wsrpc.Pool, + mercuryORM evmmercury.ORM, + triggerCapability *triggers.MercuryTriggerService, +) (*mercuryProvider, error) { + reportCodecV1 := reportcodecv1.NewReportCodec(*relayConfig.FeedID, lggr.Named("ReportCodecV1")) + reportCodecV2 := reportcodecv2.NewReportCodec(*relayConfig.FeedID, lggr.Named("ReportCodecV2")) + reportCodecV3 := reportcodecv3.NewReportCodec(*relayConfig.FeedID, lggr.Named("ReportCodecV3")) + reportCodecV4 := reportcodecv4.NewReportCodec(*relayConfig.FeedID, lggr.Named("ReportCodecV4")) + + getCodecForFeed := func(feedID mercuryutils.FeedID) (evmmercury.TransmitterReportDecoder, error) { + var transmitterCodec evmmercury.TransmitterReportDecoder + switch feedID.Version() { + case 1: + transmitterCodec = reportCodecV1 + case 2: + transmitterCodec = reportCodecV2 + case 3: + transmitterCodec = reportCodecV3 + case 4: + transmitterCodec = reportCodecV4 + default: + return nil, fmt.Errorf("invalid feed version %d", feedID.Version()) + } + return transmitterCodec, nil + } + + benchmarkPriceDecoder := func(ctx context.Context, feedID mercuryutils.FeedID, report ocrtypes.Report) (*big.Int, error) { + benchmarkPriceCodec, benchmarkPriceErr := getCodecForFeed(feedID) + if benchmarkPriceErr != nil { + return nil, benchmarkPriceErr + } + return benchmarkPriceCodec.BenchmarkPriceFromReport(ctx, report) + } + + csaPub := relayConfig.EffectiveTransmitterID.String + csaSigner, err := coretypes.NewEd25519Signer(csaPub, csaKeystore.Sign) + if err != nil { + return nil, fmt.Errorf("failed to create ed25519 signer: %w", err) + } + clients := make(map[string]wsrpc.Client) + for _, server := range cfg.GetServers() { + clients[server.URL], err = mercuryPool.Checkout(ctx, csaPub, csaSigner, server.PubKey, server.URL) + if err != nil { + return nil, err + } + } + transmitterCodec, err := getCodecForFeed(mercuryutils.FeedID(*relayConfig.FeedID)) + if err != nil { + return nil, err + } + transmitter := evmmercury.NewTransmitter(lggr, transmitterCfg, clients, csaPub, jobID, *relayConfig.FeedID, mercuryORM, transmitterCodec, benchmarkPriceDecoder, triggerCapability) return &mercuryProvider{ cp, codec, + csaSigner, transmitter, reportCodecV1, reportCodecV2, @@ -59,11 +122,11 @@ func NewMercuryProvider( mercuryChainReader, lggr, services.MultiStart{}, - } + }, nil } func (p *mercuryProvider) Start(ctx context.Context) error { - return p.ms.Start(ctx, p.cp, p.transmitter) + return p.ms.Start(ctx, p.cp, p.transmitter, p.csaSigner) } func (p *mercuryProvider) Close() error { diff --git a/core/services/relay/evm/ocr2keeper.go b/core/services/relay/evm/ocr2keeper.go index 6e4fc8fe972..dd97f554542 100644 --- a/core/services/relay/evm/ocr2keeper.go +++ b/core/services/relay/evm/ocr2keeper.go @@ -17,11 +17,11 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/sqlutil" commontypes "github.com/smartcontractkit/chainlink-common/pkg/types" "github.com/smartcontractkit/chainlink-common/pkg/types/automation" + "github.com/smartcontractkit/chainlink-integrations/evm/keys" evmtypes "github.com/smartcontractkit/chainlink-integrations/evm/types" "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" ac "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/i_automation_v21_plus_common" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore" evm "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/encoding" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2/plugins/ocr2keeper/evmregistry/v21/logprovider" @@ -67,11 +67,11 @@ type ocr2keeperRelayer struct { ds sqlutil.DataSource chain legacyevm.Chain lggr logger.Logger - ethKeystore keystore.Eth + ethKeystore keys.Store } // NewOCR2KeeperRelayer is the constructor of ocr2keeperRelayer -func NewOCR2KeeperRelayer(ds sqlutil.DataSource, chain legacyevm.Chain, lggr logger.Logger, ethKeystore keystore.Eth) OCR2KeeperRelayer { +func NewOCR2KeeperRelayer(ds sqlutil.DataSource, chain legacyevm.Chain, lggr logger.Logger, ethKeystore keys.Store) OCR2KeeperRelayer { return &ocr2keeperRelayer{ ds: ds, chain: chain, diff --git a/core/services/relay/evm/relayer_extender.go b/core/services/relay/evm/relayer_extender.go index 67da2eb46f5..3770fde894d 100644 --- a/core/services/relay/evm/relayer_extender.go +++ b/core/services/relay/evm/relayer_extender.go @@ -1,15 +1,17 @@ package evm import ( - "context" "errors" "fmt" "go.uber.org/multierr" + "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-integrations/evm/config/toml" "github.com/smartcontractkit/chainlink-integrations/evm/gas/rollups" + "github.com/smartcontractkit/chainlink-integrations/evm/keys" "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" + "github.com/smartcontractkit/chainlink/v2/core/services/keystore" ) // ErrNoChains indicates that no EVM chains have been started @@ -36,50 +38,52 @@ func (r *LegacyChainsAndConfig) Len() int { return len(r.rs) } -func NewLegacyChains(ctx context.Context, opts legacyevm.ChainRelayOpts) (result []legacyevm.Chain, err error) { - if err = opts.Validate(); err != nil { - return - } - +func NewLegacyChains( + lggr logger.Logger, + ks keystore.Eth, + chainOpts legacyevm.ChainOpts, +) (result []legacyevm.Chain, err error) { unique := make(map[string]struct{}) - - evmConfigs := opts.ChainConfigs var enabled []*toml.EVMConfig - for i, cfg := range evmConfigs { + for i, cfg := range chainOpts.ChainConfigs { _, alreadyExists := unique[cfg.ChainID.String()] if alreadyExists { return nil, fmt.Errorf("duplicate chain definition for evm chain id %s", cfg.ChainID.String()) } unique[cfg.ChainID.String()] = struct{}{} - if evmConfigs[i].IsEnabled() { - enabled = append(enabled, evmConfigs[i]) + if chainOpts.ChainConfigs[i].IsEnabled() { + enabled = append(enabled, chainOpts.ChainConfigs[i]) } } // map with lazy initialization for the txm to access evm clients for different chain var clientsByChainID = make(map[string]rollups.DAClient) for i := range enabled { - cid := enabled[i].ChainID.String() - privOpts := legacyevm.ChainRelayOpts{ - Logger: opts.Logger.Named(cid), - ChainOpts: opts.ChainOpts, - KeyStore: opts.KeyStore, + cid := enabled[i].ChainID.ToInt() + opts := legacyevm.ChainRelayOpts{ + Logger: logger.Named(lggr, cid.String()), + KeyStore: keys.NewChainStore(keystore.NewEthSigner(ks, cid), cid), + ChainOpts: chainOpts, } - privOpts.Logger.Infow(fmt.Sprintf("Loading chain %s", cid), "evmChainID", cid) - chain, err2 := legacyevm.NewTOMLChain(ctx, enabled[i], privOpts, clientsByChainID) + opts.Logger.Infow(fmt.Sprintf("Loading chain %s", cid), "evmChainID", cid) + chain, err2 := legacyevm.NewTOMLChain(enabled[i], opts, clientsByChainID) if err2 != nil { err = multierr.Combine(err, fmt.Errorf("failed to create chain %s: %w", cid, err2)) continue } - clientsByChainID[cid] = chain.Client() + clientsByChainID[cid.String()] = chain.Client() result = append(result, chain) } return } -func NewLegacyChainsAndConfig(ctx context.Context, opts legacyevm.ChainRelayOpts) (*LegacyChainsAndConfig, error) { - result, err := NewLegacyChains(ctx, opts) +func NewLegacyChainsAndConfig( + lggr logger.Logger, + ks keystore.Eth, + chainOpts legacyevm.ChainOpts, +) (*LegacyChainsAndConfig, error) { + result, err := NewLegacyChains(lggr, ks, chainOpts) // always return because it's accumulating errors - return &LegacyChainsAndConfig{result, opts.ChainConfigs}, err + return &LegacyChainsAndConfig{result, chainOpts.ChainConfigs}, err } diff --git a/core/services/relay/evm/relayer_extender_test.go b/core/services/relay/evm/relayer_extender_test.go deleted file mode 100644 index ed262ca0640..00000000000 --- a/core/services/relay/evm/relayer_extender_test.go +++ /dev/null @@ -1,76 +0,0 @@ -package evm_test - -import ( - "math/big" - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - evmclient "github.com/smartcontractkit/chainlink-integrations/evm/client" - "github.com/smartcontractkit/chainlink-integrations/evm/client/clienttest" - "github.com/smartcontractkit/chainlink-integrations/evm/config/toml" - ubig "github.com/smartcontractkit/chainlink-integrations/evm/utils/big" - "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/configtest" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/evmtest" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" - "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" - evmrelay "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm" -) - -func TestChainRelayExtenders(t *testing.T) { - t.Parallel() - ctx := testutils.Context(t) - - newId := testutils.NewRandomEVMChainID() - cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { - one := uint32(1) - c.EVM[0].MinIncomingConfirmations = &one - t := true - c.EVM = append(c.EVM, &toml.EVMConfig{ChainID: ubig.New(newId), Enabled: &t, Chain: toml.Defaults(nil)}) - }) - db := pgtest.NewSqlxDB(t) - kst := cltest.NewKeyStore(t, db) - require.NoError(t, kst.Unlock(ctx, cltest.Password)) - - opts := evmtest.NewChainOpts(t, evmtest.TestChainOpts{ - DB: db, - KeyStore: kst.Eth(), - ChainConfigs: cfg.EVMConfigs(), - DatabaseConfig: cfg.Database(), - FeatureConfig: cfg.Feature(), - ListenerConfig: cfg.Database().Listener(), - }) - opts.GenEthClient = func(*big.Int) evmclient.Client { - return cltest.NewEthMocksWithStartupAssertions(t) - } - relayExtenders, err := evmrelay.NewLegacyChains(testutils.Context(t), opts) - require.NoError(t, err) - - require.Equal(t, len(relayExtenders), 2) - relayExtendersInstances := relayExtenders - for _, c := range relayExtendersInstances { - require.NoError(t, c.Start(testutils.Context(t))) - require.NoError(t, c.Ready()) - } - - require.NotEqual(t, relayExtendersInstances[0].ID().String(), relayExtendersInstances[1].ID().String()) - - for _, c := range relayExtendersInstances { - require.NoError(t, c.Close()) - } - - relayExtendersInstances[0].Client().(*clienttest.Client).AssertCalled(t, "Close") - relayExtendersInstances[1].Client().(*clienttest.Client).AssertCalled(t, "Close") - - assert.Error(t, relayExtendersInstances[0].Ready()) - assert.Error(t, relayExtendersInstances[1].Ready()) - - // test extender methods on single instance - relayExt := relayExtendersInstances[0] - s, err := relayExt.GetChainStatus(testutils.Context(t)) - assert.NotEmpty(t, s) - assert.NoError(t, err) -} diff --git a/core/services/relay/evm/write_target_test.go b/core/services/relay/evm/write_target_test.go index c4712d69970..33e132e5556 100644 --- a/core/services/relay/evm/write_target_test.go +++ b/core/services/relay/evm/write_target_test.go @@ -17,6 +17,7 @@ import ( commonTypes "github.com/smartcontractkit/chainlink-common/pkg/types" "github.com/smartcontractkit/chainlink-common/pkg/values" "github.com/smartcontractkit/chainlink-integrations/evm/heads/headstest" + "github.com/smartcontractkit/chainlink/v2/core/services/keystore" "github.com/smartcontractkit/chainlink-integrations/evm/client/clienttest" gasmocks "github.com/smartcontractkit/chainlink-integrations/evm/gas/mocks" @@ -146,9 +147,10 @@ func TestEvmWrite(t *testing.T) { lggr := logger.TestLogger(t) cRegistry := evmcapabilities.NewRegistry(lggr) - relayer, err := relayevm.NewRelayer(testutils.Context(t), lggr, chain, relayevm.RelayerOpts{ + relayer, err := relayevm.NewRelayer(lggr, chain, relayevm.RelayerOpts{ DS: db, - CSAETHKeystore: keyStore, + EVMKeystore: keystore.NewEthSigner(keyStore.Eth(), chain.ID()), + CSAKeystore: &keystore.CSASigner{CSA: keyStore.CSA()}, CapabilitiesRegistry: cRegistry, }) require.NoError(t, err) @@ -274,9 +276,10 @@ func TestEvmWrite(t *testing.T) { testChain.On("Config").Return(evmtest.NewChainScopedConfig(t, testCfg)) capabilityRegistry := evmcapabilities.NewRegistry(lggr) - _, err := relayevm.NewRelayer(ctx, lggr, testChain, relayevm.RelayerOpts{ + _, err := relayevm.NewRelayer(lggr, testChain, relayevm.RelayerOpts{ DS: db, - CSAETHKeystore: keyStore, + EVMKeystore: keystore.NewEthSigner(keyStore.Eth(), chain.ID()), + CSAKeystore: &keystore.CSASigner{CSA: keyStore.CSA()}, CapabilitiesRegistry: capabilityRegistry, }) require.NoError(t, err) diff --git a/core/services/synchronization/helpers_test.go b/core/services/synchronization/helpers_test.go index aea9bf77f49..4a20a7b779d 100644 --- a/core/services/synchronization/helpers_test.go +++ b/core/services/synchronization/helpers_test.go @@ -11,15 +11,15 @@ import ( ) // NewTestTelemetryIngressClient calls NewTelemetryIngressClient and injects telemClient. -func NewTestTelemetryIngressClient(t *testing.T, url *url.URL, serverPubKeyHex string, ks keystore.CSA, logging bool, telemClient telemPb.TelemClient) TelemetryService { - tc := NewTelemetryIngressClient(url, serverPubKeyHex, ks, logging, logger.TestLogger(t), 100) +func NewTestTelemetryIngressClient(t *testing.T, url *url.URL, serverPubKeyHex string, csaKeyStore keystore.CSA, telemClient telemPb.TelemClient) TelemetryService { + tc := NewTelemetryIngressClient(url, serverPubKeyHex, csaKeyStore, logger.TestLogger(t), 100) tc.(*telemetryIngressClient).telemClient = telemClient return tc } // NewTestTelemetryIngressBatchClient calls NewTelemetryIngressBatchClient and injects telemClient. -func NewTestTelemetryIngressBatchClient(t *testing.T, url *url.URL, serverPubKeyHex string, ks keystore.CSA, logging bool, telemClient telemPb.TelemClient, sendInterval time.Duration, uniconn bool) TelemetryService { - tc := NewTelemetryIngressBatchClient(url, serverPubKeyHex, ks, logging, logger.TestLogger(t), 100, 50, sendInterval, time.Second, uniconn) +func NewTestTelemetryIngressBatchClient(t *testing.T, url *url.URL, serverPubKeyHex string, csaKeyStore keystore.CSA, logging bool, telemClient telemPb.TelemClient, sendInterval time.Duration, uniconn bool) TelemetryService { + tc := NewTelemetryIngressBatchClient(url, serverPubKeyHex, csaKeyStore, logging, logger.TestLogger(t), 100, 50, sendInterval, time.Second, uniconn) tc.(*telemetryIngressBatchClient).closeFn = func() error { return nil } tc.(*telemetryIngressBatchClient).telemClient = telemClient return tc diff --git a/core/services/synchronization/telemetry_ingress_batch_client.go b/core/services/synchronization/telemetry_ingress_batch_client.go index 8ca03d67ef6..904f023b189 100644 --- a/core/services/synchronization/telemetry_ingress_batch_client.go +++ b/core/services/synchronization/telemetry_ingress_batch_client.go @@ -9,14 +9,18 @@ import ( "sync/atomic" "time" + "google.golang.org/grpc/connectivity" + "github.com/smartcontractkit/wsrpc" + "github.com/smartcontractkit/wsrpc/credentials" "github.com/smartcontractkit/wsrpc/examples/simple/keys" - "google.golang.org/grpc/connectivity" "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/services" "github.com/smartcontractkit/chainlink-common/pkg/timeutil" + "github.com/smartcontractkit/chainlink-common/pkg/types/core" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" + telemPb "github.com/smartcontractkit/chainlink/v2/core/services/synchronization/telem" ) @@ -43,7 +47,8 @@ type telemetryIngressBatchClient struct { eng *services.Engine url *url.URL - ks keystore.CSA + csaKeyStore keystore.CSA + csaSigner *core.Ed25519Signer serverPubKeyHex string connected atomic.Bool @@ -67,14 +72,14 @@ type telemetryIngressBatchClient struct { // NewTelemetryIngressBatchClient returns a client backed by wsrpc that // can send telemetry to the telemetry ingress server -func NewTelemetryIngressBatchClient(url *url.URL, serverPubKeyHex string, ks keystore.CSA, logging bool, lggr logger.Logger, telemBufferSize uint, telemMaxBatchSize uint, telemSendInterval time.Duration, telemSendTimeout time.Duration, useUniconn bool) TelemetryService { +func NewTelemetryIngressBatchClient(url *url.URL, serverPubKeyHex string, csaKeyStore keystore.CSA, logging bool, lggr logger.Logger, telemBufferSize uint, telemMaxBatchSize uint, telemSendInterval time.Duration, telemSendTimeout time.Duration, useUniconn bool) TelemetryService { c := &telemetryIngressBatchClient{ telemBufferSize: telemBufferSize, telemMaxBatchSize: telemMaxBatchSize, telemSendInterval: telemSendInterval, telemSendTimeout: telemSendTimeout, url: url, - ks: ks, + csaKeyStore: csaKeyStore, serverPubKeyHex: serverPubKeyHex, logging: logging, workers: make(map[string]*telemetryIngressBatchWorker), @@ -96,19 +101,33 @@ func NewTelemetryIngressBatchClient(url *url.URL, serverPubKeyHex string, ks key // server does come back up, wsrpc will establish the connection without any interaction // on behalf of the node operator. func (tc *telemetryIngressBatchClient) start(ctx context.Context) error { - clientPrivKey, err := tc.getCSAPrivateKey() - if err != nil { - return err - } - serverPubKey := keys.FromHex(tc.serverPubKeyHex) // Initialize a new wsrpc client caller // This is used to call RPC methods on the server if tc.telemClient == nil { // only preset for tests + key, err := keystore.GetDefault(ctx, tc.csaKeyStore) + if err != nil { + return err + } + tc.csaSigner, err = core.NewEd25519Signer(key.ID(), keystore.CSASigner{CSA: tc.csaKeyStore}.Sign) + if err != nil { + return err + } if tc.useUniConn { tc.eng.Go(func(ctx context.Context) { - conn, err := wsrpc.DialUniWithContext(ctx, tc.eng, tc.url.String(), clientPrivKey, serverPubKey) + conn, err := func() (*wsrpc.UniClientConn, error) { + pubs, err := credentials.ValidPublicKeysFromEd25519(serverPubKey) + if err != nil { + return nil, err + } + tlsConfig, err := credentials.NewClientTLSSigner(tc.csaSigner, pubs) + if err != nil { + return nil, err + } + conn := wsrpc.NewTLSUniClientConn(tc.eng, tc.url.String(), tlsConfig) + return conn, conn.Dial(ctx) + }() if err != nil { if ctx.Err() != nil { tc.eng.Warnw("gave up connecting to telemetry endpoint", "err", err) @@ -123,8 +142,8 @@ func (tc *telemetryIngressBatchClient) start(ctx context.Context) error { tc.connected.Store(true) }) } else { - // Spawns a goroutine that will eventually connect - conn, err := wsrpc.DialWithContext(ctx, tc.url.String(), wsrpc.WithTransportCreds(clientPrivKey, serverPubKey), wsrpc.WithLogger(tc.eng)) + // Spawns a goroutine that will eventually connect. Don't pass ctx, which is cancelled after returning. + conn, err := wsrpc.Dial(tc.url.String(), wsrpc.WithTransportSigner(tc.csaSigner, serverPubKey), wsrpc.WithLogger(tc.eng)) if err != nil { return fmt.Errorf("could not start TelemIngressBatchClient, Dial returned error: %v", err) } @@ -163,27 +182,17 @@ func (tc *telemetryIngressBatchClient) startHealthMonitoring(ctx context.Context } // Close disconnects the wsrpc client from the ingress server and waits for all workers to exit -func (tc *telemetryIngressBatchClient) close() error { +func (tc *telemetryIngressBatchClient) close() (err error) { if tc.healthMonitorCancel != nil { tc.healthMonitorCancel() } if (tc.useUniConn && tc.connected.Load()) || !tc.useUniConn { - return tc.closeFn() + err = errors.Join(err, tc.closeFn()) } - return nil -} - -// getCSAPrivateKey gets the client's CSA private key -func (tc *telemetryIngressBatchClient) getCSAPrivateKey() (privkey []byte, err error) { - keys, err := tc.ks.GetAll() - if err != nil { - return privkey, err - } - if len(keys) < 1 { - return privkey, errors.New("CSA key does not exist") + if tc.csaSigner != nil { + err = errors.Join(err, tc.csaSigner.Close()) } - - return keys[0].Raw(), nil + return } // Send directs incoming telmetry messages to the worker responsible for pushing it to diff --git a/core/services/synchronization/telemetry_ingress_batch_client_test.go b/core/services/synchronization/telemetry_ingress_batch_client_test.go index 964fc9b25b2..c745bb00352 100644 --- a/core/services/synchronization/telemetry_ingress_batch_client_test.go +++ b/core/services/synchronization/telemetry_ingress_batch_client_test.go @@ -11,10 +11,11 @@ import ( "github.com/stretchr/testify/mock" "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" - "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/csakey" ksmocks "github.com/smartcontractkit/chainlink/v2/core/services/keystore/mocks" + + "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/services/synchronization" "github.com/smartcontractkit/chainlink/v2/core/services/synchronization/mocks" telemPb "github.com/smartcontractkit/chainlink/v2/core/services/synchronization/telem" @@ -25,6 +26,7 @@ func TestTelemetryIngressBatchClient_HappyPath(t *testing.T) { // Create mocks telemClient := mocks.NewTelemClient(t) + csaKeystore := new(ksmocks.CSA) // Set mock handlers for keystore diff --git a/core/services/synchronization/telemetry_ingress_client.go b/core/services/synchronization/telemetry_ingress_client.go index 1ed55bb5468..d91dae1f466 100644 --- a/core/services/synchronization/telemetry_ingress_client.go +++ b/core/services/synchronization/telemetry_ingress_client.go @@ -2,7 +2,6 @@ package synchronization import ( "context" - "errors" "net/url" "sync/atomic" "time" @@ -12,7 +11,9 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/types/core" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" + telemPb "github.com/smartcontractkit/chainlink/v2/core/services/synchronization/telem" ) @@ -37,8 +38,10 @@ type telemetryIngressClient struct { services.Service eng *services.Engine - url *url.URL - ks keystore.CSA + url *url.URL + csaKeyStore keystore.CSA + csaSigner *core.Ed25519Signer + serverPubKeyHex string telemClient telemPb.TelemClient @@ -50,37 +53,43 @@ type telemetryIngressClient struct { // NewTelemetryIngressClient returns a client backed by wsrpc that // can send telemetry to the telemetry ingress server -func NewTelemetryIngressClient(url *url.URL, serverPubKeyHex string, ks keystore.CSA, logging bool, lggr logger.Logger, telemBufferSize uint) TelemetryService { +func NewTelemetryIngressClient(url *url.URL, serverPubKeyHex string, csaKeyStore keystore.CSA, lggr logger.Logger, telemBufferSize uint) TelemetryService { c := &telemetryIngressClient{ url: url, - ks: ks, + csaKeyStore: csaKeyStore, serverPubKeyHex: serverPubKeyHex, - logging: logging, chTelemetry: make(chan TelemPayload, telemBufferSize), } c.Service, c.eng = services.Config{ Name: "TelemetryIngressClient", Start: c.start, + Close: c.close, }.NewServiceEngine(lggr) return c } -// Start connects the wsrpc client to the telemetry ingress server -func (tc *telemetryIngressClient) start(context.Context) error { - privkey, err := tc.getCSAPrivateKey() - if err != nil { - return err +func (tc *telemetryIngressClient) close() error { + if tc.csaSigner != nil { + return tc.csaSigner.Close() } - - tc.connect(privkey) - return nil } -func (tc *telemetryIngressClient) connect(clientPrivKey []byte) { +// Start connects the wsrpc client to the telemetry ingress server +func (tc *telemetryIngressClient) start(context.Context) error { tc.eng.Go(func(ctx context.Context) { - serverPubKey := keys.FromHex(tc.serverPubKeyHex) - conn, err := wsrpc.DialWithContext(ctx, tc.url.String(), wsrpc.WithTransportCreds(clientPrivKey, serverPubKey), wsrpc.WithLogger(tc.eng)) + conn, err := func() (*wsrpc.ClientConn, error) { + serverPubKey := keys.FromHex(tc.serverPubKeyHex) + key, err := keystore.GetDefault(ctx, tc.csaKeyStore) + if err != nil { + return nil, err + } + tc.csaSigner, err = core.NewEd25519Signer(key.ID(), keystore.CSASigner{CSA: tc.csaKeyStore}.Sign) + if err != nil { + return nil, err + } + return wsrpc.DialWithContext(ctx, tc.url.String(), wsrpc.WithTransportSigner(tc.csaSigner, serverPubKey), wsrpc.WithLogger(tc.eng)) + }() if err != nil { if ctx.Err() != nil { tc.eng.Warnw("gave up connecting to telemetry endpoint", "err", err) @@ -104,6 +113,7 @@ func (tc *telemetryIngressClient) connect(clientPrivKey []byte) { // Wait for close <-ctx.Done() }) + return nil } func (tc *telemetryIngressClient) handleTelemetry() { @@ -152,20 +162,6 @@ func (tc *telemetryIngressClient) logBufferFullWithExpBackoff(payload TelemPaylo } } -// getCSAPrivateKey gets the client's CSA private key -func (tc *telemetryIngressClient) getCSAPrivateKey() (privkey []byte, err error) { - // Fetch the client's public key - keys, err := tc.ks.GetAll() - if err != nil { - return privkey, err - } - if len(keys) < 1 { - return privkey, errors.New("CSA key does not exist") - } - - return keys[0].Raw(), nil -} - // Send sends telemetry to the ingress server using wsrpc if the client is ready. // Also stores telemetry in a small buffer in case of backpressure from wsrpc, // throwing away messages once buffer is full diff --git a/core/services/synchronization/telemetry_ingress_client_test.go b/core/services/synchronization/telemetry_ingress_client_test.go index 407051ff19b..250b302f259 100644 --- a/core/services/synchronization/telemetry_ingress_client_test.go +++ b/core/services/synchronization/telemetry_ingress_client_test.go @@ -11,10 +11,11 @@ import ( "github.com/stretchr/testify/mock" "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" - "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/csakey" ksmocks "github.com/smartcontractkit/chainlink/v2/core/services/keystore/mocks" + + "github.com/smartcontractkit/chainlink/v2/core/internal/cltest" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/services/synchronization" "github.com/smartcontractkit/chainlink/v2/core/services/synchronization/mocks" telemPb "github.com/smartcontractkit/chainlink/v2/core/services/synchronization/telem" @@ -24,17 +25,20 @@ import ( func TestTelemetryIngressClient_Send_HappyPath(t *testing.T) { // Create mocks telemClient := mocks.NewTelemClient(t) + csaKeystore := new(ksmocks.CSA) // Set mock handlers for keystore key := cltest.DefaultCSAKey keyList := []csakey.KeyV2{key} + csaKeystore.On("EnsureKey", mock.Anything).Return(nil) csaKeystore.On("GetAll").Return(keyList, nil) + csaKeystore.On("Get", key.ID()).Return(key, nil) // Wire up the telem ingress client url := &url.URL{} serverPubKeyHex := telem.GetDummyKeyString() - telemIngressClient := synchronization.NewTestTelemetryIngressClient(t, url, serverPubKeyHex, csaKeystore, false, telemClient) + telemIngressClient := synchronization.NewTestTelemetryIngressClient(t, url, serverPubKeyHex, csaKeystore, telemClient) servicetest.Run(t, telemIngressClient) // Create the telemetry payload diff --git a/core/services/telemetry/manager.go b/core/services/telemetry/manager.go index 7b788c4806c..154539df520 100644 --- a/core/services/telemetry/manager.go +++ b/core/services/telemetry/manager.go @@ -11,8 +11,9 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/logger" common "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink-common/pkg/services" - "github.com/smartcontractkit/chainlink/v2/core/config" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" + + "github.com/smartcontractkit/chainlink/v2/core/config" "github.com/smartcontractkit/chainlink/v2/core/services/synchronization" ) @@ -112,7 +113,7 @@ func (m *Manager) newEndpoint(e config.TelemetryIngressEndpoint, lggr logger.Log if m.useBatchSend { tClient = synchronization.NewTelemetryIngressBatchClient(e.URL(), e.ServerPubKey(), m.ks, cfg.Logging(), lggr, cfg.BufferSize(), cfg.MaxBatchSize(), cfg.SendInterval(), cfg.SendTimeout(), cfg.UniConn()) } else { - tClient = synchronization.NewTelemetryIngressClient(e.URL(), e.ServerPubKey(), m.ks, cfg.Logging(), lggr, cfg.BufferSize()) + tClient = synchronization.NewTelemetryIngressClient(e.URL(), e.ServerPubKey(), m.ks, lggr, cfg.BufferSize()) } te := telemetryEndpoint{ diff --git a/core/services/telemetry/manager_test.go b/core/services/telemetry/manager_test.go index df8e87018bc..977426da8ec 100644 --- a/core/services/telemetry/manager_test.go +++ b/core/services/telemetry/manager_test.go @@ -18,7 +18,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/csakey" - mocks3 "github.com/smartcontractkit/chainlink/v2/core/services/keystore/mocks" + keymocks "github.com/smartcontractkit/chainlink/v2/core/services/keystore/mocks" "github.com/smartcontractkit/chainlink/v2/core/services/synchronization" mocks2 "github.com/smartcontractkit/chainlink/v2/core/services/synchronization/mocks" ) @@ -48,7 +48,7 @@ func TestManagerAgents(t *testing.T) { lggr, _ := logger.TestLoggerObserved(t, zapcore.InfoLevel) - ks := mocks3.NewCSA(t) + ks := keymocks.NewCSA(t) tm := NewManager(tic, ks, lggr) require.Equal(t, "*synchronization.telemetryIngressBatchClient", reflect.TypeOf(tm.endpoints[0].client).String()) @@ -148,10 +148,11 @@ func TestNewManager(t *testing.T) { lggr, logObs := logger.TestLoggerObserved(t, zapcore.InfoLevel) - ks := mocks3.NewCSA(t) - - ks.On("GetAll").Return([]csakey.KeyV2{csakey.MustNewV2XXXTestingOnly(big.NewInt(0))}, nil) - + ks := keymocks.NewCSA(t) + ks.On("EnsureKey", mock.Anything).Return(nil) + key := csakey.MustNewV2XXXTestingOnly(big.NewInt(0)) + ks.On("GetAll").Return([]csakey.KeyV2{key}, nil) + ks.On("Get", key.ID()).Return(key, nil) m := NewManager(tic, ks, lggr) require.Equal(t, uint(123), m.bufferSize) @@ -199,8 +200,8 @@ func TestCorrectEndpointRouting(t *testing.T) { tic.On("Endpoints").Return(nil) lggr, obsLogs := logger.TestLoggerObserved(t, zapcore.InfoLevel) - ks := mocks3.NewCSA(t) + ks := keymocks.NewCSA(t) tm := NewManager(tic, ks, lggr) type testEndpoint struct { diff --git a/core/services/vrf/delegate_test.go b/core/services/vrf/delegate_test.go index 8052e2e8742..8f731971511 100644 --- a/core/services/vrf/delegate_test.go +++ b/core/services/vrf/delegate_test.go @@ -16,6 +16,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox/mailboxtest" + "github.com/smartcontractkit/chainlink-integrations/evm/keys" "github.com/smartcontractkit/chainlink-integrations/evm/assets" "github.com/smartcontractkit/chainlink-integrations/evm/client/clienttest" @@ -82,14 +83,14 @@ func buildVrfUni(t *testing.T, db *sqlx.DB, cfg chainlink.GeneralConfig) vrfUniv btORM := bridges.NewORM(db) ks := keystore.NewInMemory(db, utils.FastScryptParams, lggr) _, dbConfig, evmConfig := txmgr.MakeTestConfigs(t) - txm, err := txmgr.NewTxm(db, evmConfig, evmConfig.GasEstimator(), evmConfig.Transactions(), nil, dbConfig, dbConfig.Listener(), ec, logger.TestLogger(t), nil, ks.Eth(), nil, nil, nil) + evmKs := keys.NewChainStore(keystore.NewEthSigner(ks.Eth(), ec.ConfiguredChainID()), ec.ConfiguredChainID()) + txm, err := txmgr.NewTxm(db, evmConfig, evmConfig.GasEstimator(), evmConfig.Transactions(), nil, dbConfig, dbConfig.Listener(), ec, logger.TestLogger(t), nil, evmKs, nil, nil, nil) orm := heads.NewORM(*testutils.FixtureChainID, db) require.NoError(t, orm.IdempotentInsertHead(testutils.Context(t), cltest.Head(51))) jrm := job.NewORM(db, prm, btORM, ks, lggr) t.Cleanup(func() { assert.NoError(t, jrm.Close()) }) legacyChains := evmtest.NewLegacyChains(t, evmtest.TestChainOpts{ LogBroadcaster: lb, - KeyStore: ks.Eth(), Client: ec, DB: db, ChainConfigs: cfg.EVMConfigs(), @@ -97,6 +98,7 @@ func buildVrfUni(t *testing.T, db *sqlx.DB, cfg chainlink.GeneralConfig) vrfUniv FeatureConfig: cfg.Feature(), ListenerConfig: cfg.Database().Listener(), TxManager: txm, + KeyStore: ks.Eth(), }) pr := pipeline.NewRunner(prm, btORM, cfg.JobPipeline(), cfg.WebServer(), legacyChains, ks.Eth(), ks.VRF(), lggr, nil, nil) require.NoError(t, ks.Unlock(ctx, testutils.Password)) diff --git a/core/services/vrf/v2/integration_v2_test.go b/core/services/vrf/v2/integration_v2_test.go index b6e0646ccb0..50af4bd7b4b 100644 --- a/core/services/vrf/v2/integration_v2_test.go +++ b/core/services/vrf/v2/integration_v2_test.go @@ -31,18 +31,19 @@ import ( commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink-common/pkg/sqlutil" "github.com/smartcontractkit/chainlink-common/pkg/utils/tests" - txmgrcommon "github.com/smartcontractkit/chainlink-framework/chains/txmgr" txmgrtypes "github.com/smartcontractkit/chainlink-framework/chains/txmgr/types" "github.com/smartcontractkit/chainlink-integrations/evm/assets" "github.com/smartcontractkit/chainlink-integrations/evm/client/clienttest" "github.com/smartcontractkit/chainlink-integrations/evm/config/toml" "github.com/smartcontractkit/chainlink-integrations/evm/gas" + "github.com/smartcontractkit/chainlink-integrations/evm/keys" evmtestutils "github.com/smartcontractkit/chainlink-integrations/evm/testutils" "github.com/smartcontractkit/chainlink-integrations/evm/types" evmutils "github.com/smartcontractkit/chainlink-integrations/evm/utils" ubig "github.com/smartcontractkit/chainlink-integrations/evm/utils/big" evmlogger "github.com/smartcontractkit/chainlink/v2/core/chains/evm/log" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/batch_blockhash_store" @@ -137,10 +138,11 @@ type coordinatorV2Universe struct { batchCoordinatorContractAddress common.Address } -func makeTestTxm(t *testing.T, txStore txmgr.TestEvmTxStore, keyStore keystore.Master, ec *clienttest.Client) txmgrcommon.TxManager[*big.Int, *types.Head, common.Address, common.Hash, common.Hash, types.Nonce, gas.EvmFee] { +func makeTestTxm(t *testing.T, txStore txmgr.TestEvmTxStore, keyStore keystore.Eth, ec *clienttest.Client) txmgrcommon.TxManager[*big.Int, *types.Head, common.Address, common.Hash, common.Hash, types.Nonce, gas.EvmFee] { _, _, evmConfig := txmgr.MakeTestConfigs(t) txmConfig := txmgr.NewEvmTxmConfig(evmConfig) - txm := txmgr.NewEvmTxm(ec.ConfiguredChainID(), txmConfig, evmConfig.Transactions(), keyStore.Eth(), logger.TestLogger(t), nil, nil, + ks := keys.NewStore(keystore.NewEthSigner(keyStore, ec.ConfiguredChainID())) + txm := txmgr.NewEvmTxm(ec.ConfiguredChainID(), txmConfig, evmConfig.Transactions(), ks, logger.TestLogger(t), nil, nil, nil, txStore, nil, nil, nil, nil, nil, nil) return txm @@ -2103,7 +2105,7 @@ func TestStartingCountsV1(t *testing.T) { ec := clienttest.NewClient(t) ec.On("ConfiguredChainID").Return(testutils.SimulatedChainID) ec.On("LatestBlockHeight", mock.Anything).Return(big.NewInt(2), nil).Maybe() - txm := makeTestTxm(t, txStore, ks, ec) + txm := makeTestTxm(t, txStore, ks.Eth(), ec) legacyChains := evmtest.NewLegacyChains(t, evmtest.TestChainOpts{ KeyStore: ks.Eth(), Client: ec, diff --git a/core/services/vrf/v2/listener_v2_test.go b/core/services/vrf/v2/listener_v2_test.go index b628a01ab83..181feca0dcf 100644 --- a/core/services/vrf/v2/listener_v2_test.go +++ b/core/services/vrf/v2/listener_v2_test.go @@ -16,9 +16,9 @@ import ( clnull "github.com/smartcontractkit/chainlink-common/pkg/utils/null" txmgrcommon "github.com/smartcontractkit/chainlink-framework/chains/txmgr" txmgrtypes "github.com/smartcontractkit/chainlink-framework/chains/txmgr/types" - "github.com/smartcontractkit/chainlink-integrations/evm/client/clienttest" "github.com/smartcontractkit/chainlink-integrations/evm/gas" + "github.com/smartcontractkit/chainlink-integrations/evm/keys" evmtypes "github.com/smartcontractkit/chainlink-integrations/evm/types" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" @@ -38,7 +38,8 @@ func makeTestTxm(t *testing.T, txStore txmgr.TestEvmTxStore, keyStore keystore.M _, _, evmConfig := txmgr.MakeTestConfigs(t) ec := clienttest.NewClientWithDefaultChainID(t) txmConfig := txmgr.NewEvmTxmConfig(evmConfig) - txm := txmgr.NewEvmTxm(ec.ConfiguredChainID(), txmConfig, evmConfig.Transactions(), keyStore.Eth(), logger.TestLogger(t), nil, nil, + ks := keys.NewChainStore(keystore.NewEthSigner(keyStore.Eth(), ec.ConfiguredChainID()), ec.ConfiguredChainID()) + txm := txmgr.NewEvmTxm(ec.ConfiguredChainID(), txmConfig, evmConfig.Transactions(), ks, logger.TestLogger(t), nil, nil, nil, txStore, nil, nil, nil, nil, nil, nil) return txm diff --git a/core/web/eth_keys_controller_test.go b/core/web/eth_keys_controller_test.go index 5442f842adf..0039c519f1e 100644 --- a/core/web/eth_keys_controller_test.go +++ b/core/web/eth_keys_controller_test.go @@ -389,7 +389,7 @@ func TestETHKeysController_ChainSuccess_ResetWithAbandon(t *testing.T) { ctx := testutils.Context(t) ethClient := cltest.NewEthMocksWithStartupAssertions(t) - ethClient.On("NonceAt", mock.Anything, mock.Anything, mock.Anything).Return(uint64(0), nil).Once() + ethClient.On("NonceAt", mock.Anything, mock.Anything, mock.Anything).Return(uint64(0), nil).Maybe() cfg := configtest.NewGeneralConfig(t, func(c *chainlink.Config, s *chainlink.Secrets) { c.EVM[0].NonceAutoSync = ptr(false) c.EVM[0].BalanceMonitor.Enabled = ptr(false) diff --git a/deployment/environment/memory/node.go b/deployment/environment/memory/node.go index 4593024c71a..fe436f67fbe 100644 --- a/deployment/environment/memory/node.go +++ b/deployment/environment/memory/node.go @@ -3,7 +3,6 @@ package memory import ( "context" "crypto/rand" - "encoding/hex" "fmt" "math/big" @@ -26,8 +25,6 @@ import ( nodev1 "github.com/smartcontractkit/chainlink-protos/job-distributor/v1/node" "github.com/smartcontractkit/chainlink-common/pkg/config" - "github.com/smartcontractkit/chainlink-common/pkg/loop" - "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox" "github.com/smartcontractkit/chainlink-common/pkg/utils/tests" mnCfg "github.com/smartcontractkit/chainlink-framework/multinode/config" @@ -41,11 +38,14 @@ import ( v2toml "github.com/smartcontractkit/chainlink-integrations/evm/config/toml" "github.com/smartcontractkit/chainlink-integrations/evm/testutils" evmutils "github.com/smartcontractkit/chainlink-integrations/evm/utils/big" + pb "github.com/smartcontractkit/chainlink-protos/orchestrator/feedsmanager" + "github.com/smartcontractkit/chainlink/v2/core/capabilities" - "github.com/smartcontractkit/chainlink/v2/core/chains/legacyevm" configv2 "github.com/smartcontractkit/chainlink/v2/core/config/toml" "github.com/smartcontractkit/chainlink/v2/core/logger/audit" "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" + feeds2 "github.com/smartcontractkit/chainlink/v2/core/services/feeds" + feedsMocks "github.com/smartcontractkit/chainlink/v2/core/services/feeds/mocks" "github.com/smartcontractkit/chainlink/v2/core/services/keystore" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/chaintype" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/csakey" @@ -56,11 +56,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/utils" "github.com/smartcontractkit/chainlink/v2/core/utils/crypto" "github.com/smartcontractkit/chainlink/v2/core/utils/testutils/heavyweight" - "github.com/smartcontractkit/chainlink/v2/plugins" - - pb "github.com/smartcontractkit/chainlink-protos/orchestrator/feedsmanager" - feeds2 "github.com/smartcontractkit/chainlink/v2/core/services/feeds" - feedsMocks "github.com/smartcontractkit/chainlink/v2/core/services/feeds/mocks" ) type Node struct { @@ -311,78 +306,34 @@ func NewNode( // Create keystore master := keystore.New(db, utils.FastScryptParams, lggr) - kStore := KeystoreSim{ - eks: &EthKeystoreSim{ - Eth: master.Eth(), - }, - csa: master.CSA(), - workflow: master.Workflow(), - } - // Build evm factory using clients + keystore. - mailMon := mailbox.NewMonitor("node", lggr.Named("mailbox")) - evmOpts := chainlink.EVMFactoryConfig{ - ChainOpts: legacyevm.ChainOpts{ - ChainConfigs: cfg.EVMConfigs(), - DatabaseConfig: cfg.Database(), - ListenerConfig: cfg.Database().Listener(), - FeatureConfig: cfg.Feature(), - GenEthClient: func(i *big.Int) client.Client { + ctx := tests.Context(t) + require.NoError(t, master.Unlock(ctx, "password")) + require.NoError(t, master.CSA().EnsureKey(ctx)) + require.NoError(t, master.Workflow().EnsureKey(ctx)) + + app, err := chainlink.NewApplication(ctx, chainlink.ApplicationOpts{ + CREOpts: chainlink.CREOpts{ + CapabilitiesRegistry: capabilities.NewRegistry(lggr), + }, + Config: cfg, + DS: db, + KeyStore: master, + EVMFactoryConfigFn: func(fc *chainlink.EVMFactoryConfig) { + fc.GenEthClient = func(i *big.Int) client.Client { ethClient, ok := clients[i.Uint64()] if !ok { t.Fatal("no backend for chainID", i) } return ethClient - }, - MailMon: mailMon, - DS: db, + } }, - CSAETHKeystore: kStore, - } - - solanaOpts := chainlink.SolanaFactoryConfig{ - Keystore: master.Solana(), - TOMLConfigs: cfg.SolanaConfigs(), - DS: db, - } - - // Build Beholder auth - ctx := tests.Context(t) - require.NoError(t, master.Unlock(ctx, "password")) - require.NoError(t, master.CSA().EnsureKey(ctx)) - require.NoError(t, master.Workflow().EnsureKey(ctx)) - beholderAuthHeaders, csaPubKeyHex, err := keystore.BuildBeholderAuth(master) - require.NoError(t, err) - - loopRegistry := plugins.NewLoopRegistry(lggr.Named("LoopRegistry"), cfg.Database(), cfg.Tracing(), cfg.Telemetry(), beholderAuthHeaders, csaPubKeyHex) - - // Build relayer factory - relayerFactory := chainlink.RelayerFactory{ - Logger: lggr, - LoopRegistry: loopRegistry, - GRPCOpts: loop.GRPCOpts{}, - CapabilitiesRegistry: capabilities.NewRegistry(lggr), - } - initOps := []chainlink.CoreRelayerChainInitFunc{ - chainlink.InitEVM(context.Background(), relayerFactory, evmOpts), - chainlink.InitSolana(context.Background(), relayerFactory, solanaOpts), - } - rci, err := chainlink.NewCoreRelayerChainInteroperators(initOps...) - require.NoError(t, err) - - app, err := chainlink.NewApplication(chainlink.ApplicationOpts{ - Config: cfg, - DS: db, - KeyStore: master, - RelayerChainInteroperators: rci, - Logger: lggr, - ExternalInitiatorManager: nil, - CloseLogger: lggr.Sync, - UnrestrictedHTTPClient: &http.Client{}, - RestrictedHTTPClient: &http.Client{}, - AuditLogger: audit.NoopLogger, - MailMon: mailMon, - LoopRegistry: loopRegistry, + Logger: lggr, + ExternalInitiatorManager: nil, + CloseLogger: lggr.Sync, + UnrestrictedHTTPClient: &http.Client{}, + RestrictedHTTPClient: &http.Client{}, + AuditLogger: audit.NoopLogger, }) require.NoError(t, err) t.Cleanup(func() { @@ -424,9 +375,8 @@ func CreateKeys(t *testing.T, err = app.GetKeyStore().CSA().EnsureKey(ctx) require.NoError(t, err) - csaKeys, err := app.GetKeyStore().CSA().GetAll() + csaKey, err := keystore.GetDefault(ctx, app.GetKeyStore().CSA()) require.NoError(t, err) - csaKey := csaKeys[0] p2pIDs, err := app.GetKeyStore().P2P().GetAll() require.NoError(t, err) @@ -603,20 +553,6 @@ func (e *EthKeystoreSim) SignTx(ctx context.Context, address common.Address, tx return e.Eth.SignTx(ctx, address, tx, big.NewInt(1337)) } -type KeystoreSim struct { - eks keystore.Eth - csa keystore.CSA - workflow keystore.Workflow -} - -func (e KeystoreSim) Eth() keystore.Eth { - return e.eks -} - -func (e KeystoreSim) CSA() keystore.CSA { - return e.csa -} - func setupJD(t *testing.T, app chainlink.Application) { secret := randomBytes32(t) pkey, err := crypto.PublicKeyFromHex(hex.EncodeToString(secret)) diff --git a/deployment/go.mod b/deployment/go.mod index fba83dc264c..9f32017533f 100644 --- a/deployment/go.mod +++ b/deployment/go.mod @@ -33,9 +33,9 @@ require ( github.com/smartcontractkit/chain-selectors v1.0.43 github.com/smartcontractkit/chainlink-ccip v0.0.0-20250307145254-e603dcbe3db1 github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20250307105933-7912a5e97ad0 - github.com/smartcontractkit/chainlink-common v0.4.2-0.20250310180230-58f4a9810e21 + github.com/smartcontractkit/chainlink-common v0.4.2-0.20250311155151-6b258d69b8a4 github.com/smartcontractkit/chainlink-framework/multinode v0.0.0-20250211162441-3d6cea220efb - github.com/smartcontractkit/chainlink-integrations/evm v0.0.0-20250304212534-9eff2fa32bea + github.com/smartcontractkit/chainlink-integrations/evm v0.0.0-20250311123343-5a841c234992 github.com/smartcontractkit/chainlink-protos/job-distributor v0.9.0 github.com/smartcontractkit/chainlink-protos/orchestrator v0.5.0 github.com/smartcontractkit/chainlink-solana v1.1.2-0.20250219165127-be60782e4448 @@ -356,14 +356,14 @@ require ( github.com/smartcontractkit/chainlink-automation v0.8.1 // indirect github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20250228145850-f846693a6fd5 // indirect github.com/smartcontractkit/chainlink-feeds v0.1.2-0.20250227211209-7cd000095135 // indirect - github.com/smartcontractkit/chainlink-framework/chains v0.0.0-20250227163723-3c71fefea680 // indirect + github.com/smartcontractkit/chainlink-framework/chains v0.0.0-20250311143712-d83af6d2a580 // indirect github.com/smartcontractkit/chainlink-protos/rmn/v1.6/go v0.0.0-20250131130834-15e0d4cde2a6 // indirect github.com/smartcontractkit/chainlink-protos/svr v1.1.0 // indirect github.com/smartcontractkit/chainlink-testing-framework/seth v1.50.10 // indirect github.com/smartcontractkit/grpc-proxy v0.0.0-20240830132753-a7e17fec5ab7 // indirect github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20241009055228-33d0c0bf38de // indirect github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20241009055228-33d0c0bf38de // indirect - github.com/smartcontractkit/wsrpc v0.8.3 // indirect + github.com/smartcontractkit/wsrpc v0.8.5-0.20250310183704-ea183816e1d1 // indirect github.com/spf13/cast v1.7.1 // indirect github.com/spf13/cobra v1.8.1 // indirect github.com/spf13/pflag v1.0.6 // indirect diff --git a/deployment/go.sum b/deployment/go.sum index 488d9d48b2d..29c857fc315 100644 --- a/deployment/go.sum +++ b/deployment/go.sum @@ -1168,18 +1168,18 @@ github.com/smartcontractkit/chainlink-ccip v0.0.0-20250307145254-e603dcbe3db1 h1 github.com/smartcontractkit/chainlink-ccip v0.0.0-20250307145254-e603dcbe3db1/go.mod h1:AhqYIeGF2k94J+/gzRx5dQttlgUdZid2N6E4HlHVIVA= github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20250307105933-7912a5e97ad0 h1:q19ElpBhjcA8yklJnHnNA04P9W3R7X+J2NTc1ZJvN4Q= github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20250307105933-7912a5e97ad0/go.mod h1:2Y6JRpvj9EkgKgymvenuqCnra07+NYVB6+0rQGETSGA= -github.com/smartcontractkit/chainlink-common v0.4.2-0.20250310180230-58f4a9810e21 h1:Z+IZ7znVnD2idSmZAT72ilj13rKYLxVt4GVBOCNOPUc= -github.com/smartcontractkit/chainlink-common v0.4.2-0.20250310180230-58f4a9810e21/go.mod h1:YQuXIqQpmpAqstWV0LHaDTJ5nsSWuip5ivEM+Fisb+4= +github.com/smartcontractkit/chainlink-common v0.4.2-0.20250311155151-6b258d69b8a4 h1:1pdgg/h8tYlE8oPP8LIaX5n9bioEzBK5vbAnSqeQAbU= +github.com/smartcontractkit/chainlink-common v0.4.2-0.20250311155151-6b258d69b8a4/go.mod h1:YQuXIqQpmpAqstWV0LHaDTJ5nsSWuip5ivEM+Fisb+4= github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20250228145850-f846693a6fd5 h1:cJpPJ5hEwc6vlMoxmATS60uWPUi62ydnTVBabu6WKEE= github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20250228145850-f846693a6fd5/go.mod h1:2yUpKW1/jFxpozO/Zkh3fKDzI0jthXoEcU2xuDq+vlo= github.com/smartcontractkit/chainlink-feeds v0.1.2-0.20250227211209-7cd000095135 h1:8u9xUrC+yHrTDexOKDd+jrA6LCzFFHeX1G82oj2fsSI= github.com/smartcontractkit/chainlink-feeds v0.1.2-0.20250227211209-7cd000095135/go.mod h1:NkvE4iQgiT7dMCP6U3xPELHhWhN5Xr6rHC0axRebyMU= -github.com/smartcontractkit/chainlink-framework/chains v0.0.0-20250227163723-3c71fefea680 h1:Es/V5imh4at3NdHDWlbDMjljd24TrJQCy/+8xAVajl0= -github.com/smartcontractkit/chainlink-framework/chains v0.0.0-20250227163723-3c71fefea680/go.mod h1:tHem58EihQh63kR2LlAOKDAs9Vbghf1dJKZRGy6LG8g= +github.com/smartcontractkit/chainlink-framework/chains v0.0.0-20250311143712-d83af6d2a580 h1:Ctff6yL9mnsFEyefj0LwqLAUvN5flxyGJiZ5pKZpqAA= +github.com/smartcontractkit/chainlink-framework/chains v0.0.0-20250311143712-d83af6d2a580/go.mod h1:tHem58EihQh63kR2LlAOKDAs9Vbghf1dJKZRGy6LG8g= github.com/smartcontractkit/chainlink-framework/multinode v0.0.0-20250211162441-3d6cea220efb h1:LWijSyJ2lhppkFLN19EGsLHZXQ5wen2DEk1cyR0tV+o= github.com/smartcontractkit/chainlink-framework/multinode v0.0.0-20250211162441-3d6cea220efb/go.mod h1:4JqpgFy01LaqG1yM2iFTzwX3ZgcAvW9WdstBZQgPHzU= -github.com/smartcontractkit/chainlink-integrations/evm v0.0.0-20250304212534-9eff2fa32bea h1:qcbJAI8cfLezQiWi1OS87jiLFqqzdTaHbp4zNfNGiSU= -github.com/smartcontractkit/chainlink-integrations/evm v0.0.0-20250304212534-9eff2fa32bea/go.mod h1:SnIqxMeK33uC2og+sgMftKauW5dCioMBG5XzxA8tx6o= +github.com/smartcontractkit/chainlink-integrations/evm v0.0.0-20250311123343-5a841c234992 h1:JozqMfkum2Sbsj+LXi3ZpyCw6T6QTpNbQCm4Mjcb5f4= +github.com/smartcontractkit/chainlink-integrations/evm v0.0.0-20250311123343-5a841c234992/go.mod h1:Lx4JdHoPK1m5rV5iE7+4rGipwpAqa3qWkWrixKX2IXo= github.com/smartcontractkit/chainlink-protos/job-distributor v0.9.0 h1:hfMRj2ny6oNHd8w1rhJHdoX3YkoWJtCkBK6wTlCE4+c= github.com/smartcontractkit/chainlink-protos/job-distributor v0.9.0/go.mod h1:/dVVLXrsp+V0AbcYGJo3XMzKg3CkELsweA/TTopCsKE= github.com/smartcontractkit/chainlink-protos/orchestrator v0.5.0 h1:xRgu/kMkxcY4LeDKMBhaXU4khgya7v2wyb4Sa5Nzb+Y= @@ -1206,8 +1206,8 @@ github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20241009055228- github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20241009055228-33d0c0bf38de/go.mod h1:Sl2MF/Fp3fgJIVzhdGhmZZX2BlnM0oUUyBP4s4xYb6o= github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20241009055228-33d0c0bf38de h1:66VQxXx3lvTaAZrMBkIcdH9VEjujUEvmBQdnyOJnkOc= github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20241009055228-33d0c0bf38de/go.mod h1:NSc7hgOQbXG3DAwkOdWnZzLTZENXSwDJ7Va1nBp0YU0= -github.com/smartcontractkit/wsrpc v0.8.3 h1:9tDf7Ut61g36RJIyxV9iI73SqoOMasKPfURV9oMLrPg= -github.com/smartcontractkit/wsrpc v0.8.3/go.mod h1:2u/wfnhl5R4RlSXseN4n6HHIWk8w1Am3AT6gWftQbNg= +github.com/smartcontractkit/wsrpc v0.8.5-0.20250310183704-ea183816e1d1 h1:yfukbG7KzP3FGe3WOV4GHowHqnRW1Pg7fDz2vBucS10= +github.com/smartcontractkit/wsrpc v0.8.5-0.20250310183704-ea183816e1d1/go.mod h1:m3pdp17i4bD50XgktkzWetcV5yaLsi7Gunbv4ZgN6qg= github.com/smarty/assertions v1.15.0/go.mod h1:yABtdzeQs6l1brC900WlRNwj6ZR55d7B+E8C6HtKdec= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= diff --git a/go.mod b/go.mod index 93043b2aa7a..647edf1594d 100644 --- a/go.mod +++ b/go.mod @@ -77,19 +77,19 @@ require ( github.com/smartcontractkit/chainlink-automation v0.8.1 github.com/smartcontractkit/chainlink-ccip v0.0.0-20250307145254-e603dcbe3db1 github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20250302020946-0f2d5f4a8326 - github.com/smartcontractkit/chainlink-common v0.4.2-0.20250310180230-58f4a9810e21 + github.com/smartcontractkit/chainlink-common v0.4.2-0.20250311155151-6b258d69b8a4 github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20250228145850-f846693a6fd5 github.com/smartcontractkit/chainlink-feeds v0.1.2-0.20250227211209-7cd000095135 - github.com/smartcontractkit/chainlink-framework/chains v0.0.0-20250227163723-3c71fefea680 + github.com/smartcontractkit/chainlink-framework/chains v0.0.0-20250311143712-d83af6d2a580 github.com/smartcontractkit/chainlink-framework/multinode v0.0.0-20250211162441-3d6cea220efb - github.com/smartcontractkit/chainlink-integrations/evm v0.0.0-20250304212534-9eff2fa32bea + github.com/smartcontractkit/chainlink-integrations/evm v0.0.0-20250311123343-5a841c234992 github.com/smartcontractkit/chainlink-protos/orchestrator v0.5.0 github.com/smartcontractkit/chainlink-protos/svr v1.1.0 github.com/smartcontractkit/chainlink-solana v1.1.2-0.20250219165127-be60782e4448 github.com/smartcontractkit/libocr v0.0.0-20250220133800-f3b940c4f298 github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20241009055228-33d0c0bf38de github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20241009055228-33d0c0bf38de - github.com/smartcontractkit/wsrpc v0.8.2 + github.com/smartcontractkit/wsrpc v0.8.5-0.20250310183704-ea183816e1d1 github.com/spf13/cast v1.7.1 github.com/stretchr/testify v1.10.0 github.com/theodesp/go-heaps v0.0.0-20190520121037-88e35354fe0a diff --git a/go.sum b/go.sum index 8666e4a1d35..3bee8a9e16a 100644 --- a/go.sum +++ b/go.sum @@ -1021,18 +1021,18 @@ github.com/smartcontractkit/chainlink-ccip v0.0.0-20250307145254-e603dcbe3db1 h1 github.com/smartcontractkit/chainlink-ccip v0.0.0-20250307145254-e603dcbe3db1/go.mod h1:AhqYIeGF2k94J+/gzRx5dQttlgUdZid2N6E4HlHVIVA= github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20250302020946-0f2d5f4a8326 h1:KRL3qg6ceUxB+F66UOF6Le4fDylf5UkDb5ii9yjAtbk= github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20250302020946-0f2d5f4a8326/go.mod h1:ARwstg2HUGjtuZgG/IwxpYk4QdQtcqX69V95FUtlHdE= -github.com/smartcontractkit/chainlink-common v0.4.2-0.20250310180230-58f4a9810e21 h1:Z+IZ7znVnD2idSmZAT72ilj13rKYLxVt4GVBOCNOPUc= -github.com/smartcontractkit/chainlink-common v0.4.2-0.20250310180230-58f4a9810e21/go.mod h1:YQuXIqQpmpAqstWV0LHaDTJ5nsSWuip5ivEM+Fisb+4= +github.com/smartcontractkit/chainlink-common v0.4.2-0.20250311155151-6b258d69b8a4 h1:1pdgg/h8tYlE8oPP8LIaX5n9bioEzBK5vbAnSqeQAbU= +github.com/smartcontractkit/chainlink-common v0.4.2-0.20250311155151-6b258d69b8a4/go.mod h1:YQuXIqQpmpAqstWV0LHaDTJ5nsSWuip5ivEM+Fisb+4= github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20250228145850-f846693a6fd5 h1:cJpPJ5hEwc6vlMoxmATS60uWPUi62ydnTVBabu6WKEE= github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20250228145850-f846693a6fd5/go.mod h1:2yUpKW1/jFxpozO/Zkh3fKDzI0jthXoEcU2xuDq+vlo= github.com/smartcontractkit/chainlink-feeds v0.1.2-0.20250227211209-7cd000095135 h1:8u9xUrC+yHrTDexOKDd+jrA6LCzFFHeX1G82oj2fsSI= github.com/smartcontractkit/chainlink-feeds v0.1.2-0.20250227211209-7cd000095135/go.mod h1:NkvE4iQgiT7dMCP6U3xPELHhWhN5Xr6rHC0axRebyMU= -github.com/smartcontractkit/chainlink-framework/chains v0.0.0-20250227163723-3c71fefea680 h1:Es/V5imh4at3NdHDWlbDMjljd24TrJQCy/+8xAVajl0= -github.com/smartcontractkit/chainlink-framework/chains v0.0.0-20250227163723-3c71fefea680/go.mod h1:tHem58EihQh63kR2LlAOKDAs9Vbghf1dJKZRGy6LG8g= +github.com/smartcontractkit/chainlink-framework/chains v0.0.0-20250311143712-d83af6d2a580 h1:Ctff6yL9mnsFEyefj0LwqLAUvN5flxyGJiZ5pKZpqAA= +github.com/smartcontractkit/chainlink-framework/chains v0.0.0-20250311143712-d83af6d2a580/go.mod h1:tHem58EihQh63kR2LlAOKDAs9Vbghf1dJKZRGy6LG8g= github.com/smartcontractkit/chainlink-framework/multinode v0.0.0-20250211162441-3d6cea220efb h1:LWijSyJ2lhppkFLN19EGsLHZXQ5wen2DEk1cyR0tV+o= github.com/smartcontractkit/chainlink-framework/multinode v0.0.0-20250211162441-3d6cea220efb/go.mod h1:4JqpgFy01LaqG1yM2iFTzwX3ZgcAvW9WdstBZQgPHzU= -github.com/smartcontractkit/chainlink-integrations/evm v0.0.0-20250304212534-9eff2fa32bea h1:qcbJAI8cfLezQiWi1OS87jiLFqqzdTaHbp4zNfNGiSU= -github.com/smartcontractkit/chainlink-integrations/evm v0.0.0-20250304212534-9eff2fa32bea/go.mod h1:SnIqxMeK33uC2og+sgMftKauW5dCioMBG5XzxA8tx6o= +github.com/smartcontractkit/chainlink-integrations/evm v0.0.0-20250311123343-5a841c234992 h1:JozqMfkum2Sbsj+LXi3ZpyCw6T6QTpNbQCm4Mjcb5f4= +github.com/smartcontractkit/chainlink-integrations/evm v0.0.0-20250311123343-5a841c234992/go.mod h1:Lx4JdHoPK1m5rV5iE7+4rGipwpAqa3qWkWrixKX2IXo= github.com/smartcontractkit/chainlink-protos/orchestrator v0.5.0 h1:xRgu/kMkxcY4LeDKMBhaXU4khgya7v2wyb4Sa5Nzb+Y= github.com/smartcontractkit/chainlink-protos/orchestrator v0.5.0/go.mod h1:m/A3lqD7ms/RsQ9BT5P2uceYY0QX5mIt4KQxT2G6qEo= github.com/smartcontractkit/chainlink-protos/rmn/v1.6/go v0.0.0-20250131130834-15e0d4cde2a6 h1:L6KJ4kGv/yNNoCk8affk7Y1vAY0qglPMXC/hevV/IsA= @@ -1049,8 +1049,8 @@ github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20241009055228- github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20241009055228-33d0c0bf38de/go.mod h1:Sl2MF/Fp3fgJIVzhdGhmZZX2BlnM0oUUyBP4s4xYb6o= github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20241009055228-33d0c0bf38de h1:66VQxXx3lvTaAZrMBkIcdH9VEjujUEvmBQdnyOJnkOc= github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20241009055228-33d0c0bf38de/go.mod h1:NSc7hgOQbXG3DAwkOdWnZzLTZENXSwDJ7Va1nBp0YU0= -github.com/smartcontractkit/wsrpc v0.8.2 h1:XB/xcn/MMseHW+8JE8+a/rceA86ck7Ur6cEa9LiUC8M= -github.com/smartcontractkit/wsrpc v0.8.2/go.mod h1:2u/wfnhl5R4RlSXseN4n6HHIWk8w1Am3AT6gWftQbNg= +github.com/smartcontractkit/wsrpc v0.8.5-0.20250310183704-ea183816e1d1 h1:yfukbG7KzP3FGe3WOV4GHowHqnRW1Pg7fDz2vBucS10= +github.com/smartcontractkit/wsrpc v0.8.5-0.20250310183704-ea183816e1d1/go.mod h1:m3pdp17i4bD50XgktkzWetcV5yaLsi7Gunbv4ZgN6qg= github.com/smarty/assertions v1.15.0/go.mod h1:yABtdzeQs6l1brC900WlRNwj6ZR55d7B+E8C6HtKdec= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= diff --git a/integration-tests/go.mod b/integration-tests/go.mod index 419257d49f9..2150ed42ddd 100644 --- a/integration-tests/go.mod +++ b/integration-tests/go.mod @@ -45,8 +45,8 @@ require ( github.com/smartcontractkit/chain-selectors v1.0.43 github.com/smartcontractkit/chainlink-automation v0.8.1 github.com/smartcontractkit/chainlink-ccip v0.0.0-20250307145254-e603dcbe3db1 - github.com/smartcontractkit/chainlink-common v0.4.2-0.20250310180230-58f4a9810e21 - github.com/smartcontractkit/chainlink-integrations/evm v0.0.0-20250304212534-9eff2fa32bea + github.com/smartcontractkit/chainlink-common v0.4.2-0.20250311155151-6b258d69b8a4 + github.com/smartcontractkit/chainlink-integrations/evm v0.0.0-20250311123343-5a841c234992 github.com/smartcontractkit/chainlink-protos/job-distributor v0.9.0 github.com/smartcontractkit/chainlink-testing-framework/havoc v1.50.5 github.com/smartcontractkit/chainlink-testing-framework/lib v1.52.0 @@ -441,7 +441,7 @@ require ( github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20250307105933-7912a5e97ad0 // indirect github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20250228145850-f846693a6fd5 // indirect github.com/smartcontractkit/chainlink-feeds v0.1.2-0.20250227211209-7cd000095135 // indirect - github.com/smartcontractkit/chainlink-framework/chains v0.0.0-20250227163723-3c71fefea680 // indirect + github.com/smartcontractkit/chainlink-framework/chains v0.0.0-20250311143712-d83af6d2a580 // indirect github.com/smartcontractkit/chainlink-framework/multinode v0.0.0-20250211162441-3d6cea220efb // indirect github.com/smartcontractkit/chainlink-protos/orchestrator v0.5.0 // indirect github.com/smartcontractkit/chainlink-protos/rmn/v1.6/go v0.0.0-20250131130834-15e0d4cde2a6 // indirect @@ -452,7 +452,7 @@ require ( github.com/smartcontractkit/mcms v0.13.0 // indirect github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20241009055228-33d0c0bf38de // indirect github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20241009055228-33d0c0bf38de // indirect - github.com/smartcontractkit/wsrpc v0.8.3 // indirect + github.com/smartcontractkit/wsrpc v0.8.5-0.20250310183704-ea183816e1d1 // indirect github.com/sony/gobreaker/v2 v2.1.0 // indirect github.com/spf13/cast v1.7.1 // indirect github.com/spf13/pflag v1.0.6 // indirect diff --git a/integration-tests/go.sum b/integration-tests/go.sum index 4c9de96fe86..56f3a5e7fa1 100644 --- a/integration-tests/go.sum +++ b/integration-tests/go.sum @@ -1426,18 +1426,18 @@ github.com/smartcontractkit/chainlink-ccip v0.0.0-20250307145254-e603dcbe3db1 h1 github.com/smartcontractkit/chainlink-ccip v0.0.0-20250307145254-e603dcbe3db1/go.mod h1:AhqYIeGF2k94J+/gzRx5dQttlgUdZid2N6E4HlHVIVA= github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20250307105933-7912a5e97ad0 h1:q19ElpBhjcA8yklJnHnNA04P9W3R7X+J2NTc1ZJvN4Q= github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20250307105933-7912a5e97ad0/go.mod h1:2Y6JRpvj9EkgKgymvenuqCnra07+NYVB6+0rQGETSGA= -github.com/smartcontractkit/chainlink-common v0.4.2-0.20250310180230-58f4a9810e21 h1:Z+IZ7znVnD2idSmZAT72ilj13rKYLxVt4GVBOCNOPUc= -github.com/smartcontractkit/chainlink-common v0.4.2-0.20250310180230-58f4a9810e21/go.mod h1:YQuXIqQpmpAqstWV0LHaDTJ5nsSWuip5ivEM+Fisb+4= +github.com/smartcontractkit/chainlink-common v0.4.2-0.20250311155151-6b258d69b8a4 h1:1pdgg/h8tYlE8oPP8LIaX5n9bioEzBK5vbAnSqeQAbU= +github.com/smartcontractkit/chainlink-common v0.4.2-0.20250311155151-6b258d69b8a4/go.mod h1:YQuXIqQpmpAqstWV0LHaDTJ5nsSWuip5ivEM+Fisb+4= github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20250228145850-f846693a6fd5 h1:cJpPJ5hEwc6vlMoxmATS60uWPUi62ydnTVBabu6WKEE= github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20250228145850-f846693a6fd5/go.mod h1:2yUpKW1/jFxpozO/Zkh3fKDzI0jthXoEcU2xuDq+vlo= github.com/smartcontractkit/chainlink-feeds v0.1.2-0.20250227211209-7cd000095135 h1:8u9xUrC+yHrTDexOKDd+jrA6LCzFFHeX1G82oj2fsSI= github.com/smartcontractkit/chainlink-feeds v0.1.2-0.20250227211209-7cd000095135/go.mod h1:NkvE4iQgiT7dMCP6U3xPELHhWhN5Xr6rHC0axRebyMU= -github.com/smartcontractkit/chainlink-framework/chains v0.0.0-20250227163723-3c71fefea680 h1:Es/V5imh4at3NdHDWlbDMjljd24TrJQCy/+8xAVajl0= -github.com/smartcontractkit/chainlink-framework/chains v0.0.0-20250227163723-3c71fefea680/go.mod h1:tHem58EihQh63kR2LlAOKDAs9Vbghf1dJKZRGy6LG8g= +github.com/smartcontractkit/chainlink-framework/chains v0.0.0-20250311143712-d83af6d2a580 h1:Ctff6yL9mnsFEyefj0LwqLAUvN5flxyGJiZ5pKZpqAA= +github.com/smartcontractkit/chainlink-framework/chains v0.0.0-20250311143712-d83af6d2a580/go.mod h1:tHem58EihQh63kR2LlAOKDAs9Vbghf1dJKZRGy6LG8g= github.com/smartcontractkit/chainlink-framework/multinode v0.0.0-20250211162441-3d6cea220efb h1:LWijSyJ2lhppkFLN19EGsLHZXQ5wen2DEk1cyR0tV+o= github.com/smartcontractkit/chainlink-framework/multinode v0.0.0-20250211162441-3d6cea220efb/go.mod h1:4JqpgFy01LaqG1yM2iFTzwX3ZgcAvW9WdstBZQgPHzU= -github.com/smartcontractkit/chainlink-integrations/evm v0.0.0-20250304212534-9eff2fa32bea h1:qcbJAI8cfLezQiWi1OS87jiLFqqzdTaHbp4zNfNGiSU= -github.com/smartcontractkit/chainlink-integrations/evm v0.0.0-20250304212534-9eff2fa32bea/go.mod h1:SnIqxMeK33uC2og+sgMftKauW5dCioMBG5XzxA8tx6o= +github.com/smartcontractkit/chainlink-integrations/evm v0.0.0-20250311123343-5a841c234992 h1:JozqMfkum2Sbsj+LXi3ZpyCw6T6QTpNbQCm4Mjcb5f4= +github.com/smartcontractkit/chainlink-integrations/evm v0.0.0-20250311123343-5a841c234992/go.mod h1:Lx4JdHoPK1m5rV5iE7+4rGipwpAqa3qWkWrixKX2IXo= github.com/smartcontractkit/chainlink-protos/job-distributor v0.9.0 h1:hfMRj2ny6oNHd8w1rhJHdoX3YkoWJtCkBK6wTlCE4+c= github.com/smartcontractkit/chainlink-protos/job-distributor v0.9.0/go.mod h1:/dVVLXrsp+V0AbcYGJo3XMzKg3CkELsweA/TTopCsKE= github.com/smartcontractkit/chainlink-protos/orchestrator v0.5.0 h1:xRgu/kMkxcY4LeDKMBhaXU4khgya7v2wyb4Sa5Nzb+Y= @@ -1472,8 +1472,8 @@ github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20241009055228- github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20241009055228-33d0c0bf38de/go.mod h1:Sl2MF/Fp3fgJIVzhdGhmZZX2BlnM0oUUyBP4s4xYb6o= github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20241009055228-33d0c0bf38de h1:66VQxXx3lvTaAZrMBkIcdH9VEjujUEvmBQdnyOJnkOc= github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20241009055228-33d0c0bf38de/go.mod h1:NSc7hgOQbXG3DAwkOdWnZzLTZENXSwDJ7Va1nBp0YU0= -github.com/smartcontractkit/wsrpc v0.8.3 h1:9tDf7Ut61g36RJIyxV9iI73SqoOMasKPfURV9oMLrPg= -github.com/smartcontractkit/wsrpc v0.8.3/go.mod h1:2u/wfnhl5R4RlSXseN4n6HHIWk8w1Am3AT6gWftQbNg= +github.com/smartcontractkit/wsrpc v0.8.5-0.20250310183704-ea183816e1d1 h1:yfukbG7KzP3FGe3WOV4GHowHqnRW1Pg7fDz2vBucS10= +github.com/smartcontractkit/wsrpc v0.8.5-0.20250310183704-ea183816e1d1/go.mod h1:m3pdp17i4bD50XgktkzWetcV5yaLsi7Gunbv4ZgN6qg= github.com/smarty/assertions v1.15.0/go.mod h1:yABtdzeQs6l1brC900WlRNwj6ZR55d7B+E8C6HtKdec= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= diff --git a/integration-tests/load/go.mod b/integration-tests/load/go.mod index 8f667b1ce0a..d6afa4497e0 100644 --- a/integration-tests/load/go.mod +++ b/integration-tests/load/go.mod @@ -27,8 +27,8 @@ require ( github.com/slack-go/slack v0.15.0 github.com/smartcontractkit/chain-selectors v1.0.43 github.com/smartcontractkit/chainlink-ccip v0.0.0-20250307145254-e603dcbe3db1 - github.com/smartcontractkit/chainlink-common v0.4.2-0.20250310180230-58f4a9810e21 - github.com/smartcontractkit/chainlink-integrations/evm v0.0.0-20250304212534-9eff2fa32bea + github.com/smartcontractkit/chainlink-common v0.4.2-0.20250311155151-6b258d69b8a4 + github.com/smartcontractkit/chainlink-integrations/evm v0.0.0-20250311123343-5a841c234992 github.com/smartcontractkit/chainlink-testing-framework/lib v1.52.0 github.com/smartcontractkit/chainlink-testing-framework/seth v1.51.0 github.com/smartcontractkit/chainlink-testing-framework/wasp v1.51.0 @@ -431,7 +431,7 @@ require ( github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20250307105933-7912a5e97ad0 // indirect github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20250228145850-f846693a6fd5 // indirect github.com/smartcontractkit/chainlink-feeds v0.1.2-0.20250227211209-7cd000095135 // indirect - github.com/smartcontractkit/chainlink-framework/chains v0.0.0-20250227163723-3c71fefea680 // indirect + github.com/smartcontractkit/chainlink-framework/chains v0.0.0-20250311143712-d83af6d2a580 // indirect github.com/smartcontractkit/chainlink-framework/multinode v0.0.0-20250211162441-3d6cea220efb // indirect github.com/smartcontractkit/chainlink-protos/job-distributor v0.9.0 // indirect github.com/smartcontractkit/chainlink-protos/orchestrator v0.5.0 // indirect @@ -445,7 +445,7 @@ require ( github.com/smartcontractkit/libocr v0.0.0-20250220133800-f3b940c4f298 // indirect github.com/smartcontractkit/mcms v0.13.0 // indirect github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20241009055228-33d0c0bf38de // indirect - github.com/smartcontractkit/wsrpc v0.8.3 // indirect + github.com/smartcontractkit/wsrpc v0.8.5-0.20250310183704-ea183816e1d1 // indirect github.com/sony/gobreaker/v2 v2.1.0 // indirect github.com/spf13/cast v1.7.1 // indirect github.com/spf13/cobra v1.8.1 // indirect diff --git a/integration-tests/load/go.sum b/integration-tests/load/go.sum index 1a77c8bbb1f..ea33161710c 100644 --- a/integration-tests/load/go.sum +++ b/integration-tests/load/go.sum @@ -1411,18 +1411,18 @@ github.com/smartcontractkit/chainlink-ccip v0.0.0-20250307145254-e603dcbe3db1 h1 github.com/smartcontractkit/chainlink-ccip v0.0.0-20250307145254-e603dcbe3db1/go.mod h1:AhqYIeGF2k94J+/gzRx5dQttlgUdZid2N6E4HlHVIVA= github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20250307105933-7912a5e97ad0 h1:q19ElpBhjcA8yklJnHnNA04P9W3R7X+J2NTc1ZJvN4Q= github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20250307105933-7912a5e97ad0/go.mod h1:2Y6JRpvj9EkgKgymvenuqCnra07+NYVB6+0rQGETSGA= -github.com/smartcontractkit/chainlink-common v0.4.2-0.20250310180230-58f4a9810e21 h1:Z+IZ7znVnD2idSmZAT72ilj13rKYLxVt4GVBOCNOPUc= -github.com/smartcontractkit/chainlink-common v0.4.2-0.20250310180230-58f4a9810e21/go.mod h1:YQuXIqQpmpAqstWV0LHaDTJ5nsSWuip5ivEM+Fisb+4= +github.com/smartcontractkit/chainlink-common v0.4.2-0.20250311155151-6b258d69b8a4 h1:1pdgg/h8tYlE8oPP8LIaX5n9bioEzBK5vbAnSqeQAbU= +github.com/smartcontractkit/chainlink-common v0.4.2-0.20250311155151-6b258d69b8a4/go.mod h1:YQuXIqQpmpAqstWV0LHaDTJ5nsSWuip5ivEM+Fisb+4= github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20250228145850-f846693a6fd5 h1:cJpPJ5hEwc6vlMoxmATS60uWPUi62ydnTVBabu6WKEE= github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20250228145850-f846693a6fd5/go.mod h1:2yUpKW1/jFxpozO/Zkh3fKDzI0jthXoEcU2xuDq+vlo= github.com/smartcontractkit/chainlink-feeds v0.1.2-0.20250227211209-7cd000095135 h1:8u9xUrC+yHrTDexOKDd+jrA6LCzFFHeX1G82oj2fsSI= github.com/smartcontractkit/chainlink-feeds v0.1.2-0.20250227211209-7cd000095135/go.mod h1:NkvE4iQgiT7dMCP6U3xPELHhWhN5Xr6rHC0axRebyMU= -github.com/smartcontractkit/chainlink-framework/chains v0.0.0-20250227163723-3c71fefea680 h1:Es/V5imh4at3NdHDWlbDMjljd24TrJQCy/+8xAVajl0= -github.com/smartcontractkit/chainlink-framework/chains v0.0.0-20250227163723-3c71fefea680/go.mod h1:tHem58EihQh63kR2LlAOKDAs9Vbghf1dJKZRGy6LG8g= +github.com/smartcontractkit/chainlink-framework/chains v0.0.0-20250311143712-d83af6d2a580 h1:Ctff6yL9mnsFEyefj0LwqLAUvN5flxyGJiZ5pKZpqAA= +github.com/smartcontractkit/chainlink-framework/chains v0.0.0-20250311143712-d83af6d2a580/go.mod h1:tHem58EihQh63kR2LlAOKDAs9Vbghf1dJKZRGy6LG8g= github.com/smartcontractkit/chainlink-framework/multinode v0.0.0-20250211162441-3d6cea220efb h1:LWijSyJ2lhppkFLN19EGsLHZXQ5wen2DEk1cyR0tV+o= github.com/smartcontractkit/chainlink-framework/multinode v0.0.0-20250211162441-3d6cea220efb/go.mod h1:4JqpgFy01LaqG1yM2iFTzwX3ZgcAvW9WdstBZQgPHzU= -github.com/smartcontractkit/chainlink-integrations/evm v0.0.0-20250304212534-9eff2fa32bea h1:qcbJAI8cfLezQiWi1OS87jiLFqqzdTaHbp4zNfNGiSU= -github.com/smartcontractkit/chainlink-integrations/evm v0.0.0-20250304212534-9eff2fa32bea/go.mod h1:SnIqxMeK33uC2og+sgMftKauW5dCioMBG5XzxA8tx6o= +github.com/smartcontractkit/chainlink-integrations/evm v0.0.0-20250311123343-5a841c234992 h1:JozqMfkum2Sbsj+LXi3ZpyCw6T6QTpNbQCm4Mjcb5f4= +github.com/smartcontractkit/chainlink-integrations/evm v0.0.0-20250311123343-5a841c234992/go.mod h1:Lx4JdHoPK1m5rV5iE7+4rGipwpAqa3qWkWrixKX2IXo= github.com/smartcontractkit/chainlink-protos/job-distributor v0.9.0 h1:hfMRj2ny6oNHd8w1rhJHdoX3YkoWJtCkBK6wTlCE4+c= github.com/smartcontractkit/chainlink-protos/job-distributor v0.9.0/go.mod h1:/dVVLXrsp+V0AbcYGJo3XMzKg3CkELsweA/TTopCsKE= github.com/smartcontractkit/chainlink-protos/orchestrator v0.5.0 h1:xRgu/kMkxcY4LeDKMBhaXU4khgya7v2wyb4Sa5Nzb+Y= @@ -1455,8 +1455,8 @@ github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20241009055228- github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20241009055228-33d0c0bf38de/go.mod h1:Sl2MF/Fp3fgJIVzhdGhmZZX2BlnM0oUUyBP4s4xYb6o= github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20241009055228-33d0c0bf38de h1:66VQxXx3lvTaAZrMBkIcdH9VEjujUEvmBQdnyOJnkOc= github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20241009055228-33d0c0bf38de/go.mod h1:NSc7hgOQbXG3DAwkOdWnZzLTZENXSwDJ7Va1nBp0YU0= -github.com/smartcontractkit/wsrpc v0.8.3 h1:9tDf7Ut61g36RJIyxV9iI73SqoOMasKPfURV9oMLrPg= -github.com/smartcontractkit/wsrpc v0.8.3/go.mod h1:2u/wfnhl5R4RlSXseN4n6HHIWk8w1Am3AT6gWftQbNg= +github.com/smartcontractkit/wsrpc v0.8.5-0.20250310183704-ea183816e1d1 h1:yfukbG7KzP3FGe3WOV4GHowHqnRW1Pg7fDz2vBucS10= +github.com/smartcontractkit/wsrpc v0.8.5-0.20250310183704-ea183816e1d1/go.mod h1:m3pdp17i4bD50XgktkzWetcV5yaLsi7Gunbv4ZgN6qg= github.com/smarty/assertions v1.15.0/go.mod h1:yABtdzeQs6l1brC900WlRNwj6ZR55d7B+E8C6HtKdec= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= diff --git a/system-tests/lib/go.mod b/system-tests/lib/go.mod index ebfcf23e771..3ac6c053a55 100644 --- a/system-tests/lib/go.mod +++ b/system-tests/lib/go.mod @@ -18,7 +18,7 @@ require ( github.com/pelletier/go-toml/v2 v2.2.3 github.com/pkg/errors v0.9.1 github.com/rs/zerolog v1.33.0 - github.com/smartcontractkit/chainlink-common v0.4.2-0.20250310180230-58f4a9810e21 + github.com/smartcontractkit/chainlink-common v0.4.2-0.20250311155151-6b258d69b8a4 github.com/smartcontractkit/chainlink-protos/job-distributor v0.9.0 github.com/smartcontractkit/chainlink-testing-framework/framework v0.5.8 github.com/smartcontractkit/chainlink-testing-framework/lib v1.52.0 @@ -342,9 +342,9 @@ require ( github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20250307105933-7912a5e97ad0 // indirect github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20250228145850-f846693a6fd5 // indirect github.com/smartcontractkit/chainlink-feeds v0.1.2-0.20250227211209-7cd000095135 // indirect - github.com/smartcontractkit/chainlink-framework/chains v0.0.0-20250227163723-3c71fefea680 // indirect + github.com/smartcontractkit/chainlink-framework/chains v0.0.0-20250311143712-d83af6d2a580 // indirect github.com/smartcontractkit/chainlink-framework/multinode v0.0.0-20250211162441-3d6cea220efb // indirect - github.com/smartcontractkit/chainlink-integrations/evm v0.0.0-20250304212534-9eff2fa32bea // indirect + github.com/smartcontractkit/chainlink-integrations/evm v0.0.0-20250311123343-5a841c234992 // indirect github.com/smartcontractkit/chainlink-protos/orchestrator v0.5.0 // indirect github.com/smartcontractkit/chainlink-protos/rmn/v1.6/go v0.0.0-20250131130834-15e0d4cde2a6 // indirect github.com/smartcontractkit/chainlink-protos/svr v1.1.0 // indirect @@ -354,7 +354,7 @@ require ( github.com/smartcontractkit/mcms v0.13.0 // indirect github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20241009055228-33d0c0bf38de // indirect github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20241009055228-33d0c0bf38de // indirect - github.com/smartcontractkit/wsrpc v0.8.3 // indirect + github.com/smartcontractkit/wsrpc v0.8.5-0.20250310183704-ea183816e1d1 // indirect github.com/spf13/cast v1.7.1 // indirect github.com/spf13/cobra v1.8.1 // indirect github.com/spf13/pflag v1.0.6 // indirect diff --git a/system-tests/lib/go.sum b/system-tests/lib/go.sum index 53d2a603536..a393ad70c5e 100644 --- a/system-tests/lib/go.sum +++ b/system-tests/lib/go.sum @@ -1156,18 +1156,18 @@ github.com/smartcontractkit/chainlink-ccip v0.0.0-20250307145254-e603dcbe3db1 h1 github.com/smartcontractkit/chainlink-ccip v0.0.0-20250307145254-e603dcbe3db1/go.mod h1:AhqYIeGF2k94J+/gzRx5dQttlgUdZid2N6E4HlHVIVA= github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20250307105933-7912a5e97ad0 h1:q19ElpBhjcA8yklJnHnNA04P9W3R7X+J2NTc1ZJvN4Q= github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20250307105933-7912a5e97ad0/go.mod h1:2Y6JRpvj9EkgKgymvenuqCnra07+NYVB6+0rQGETSGA= -github.com/smartcontractkit/chainlink-common v0.4.2-0.20250310180230-58f4a9810e21 h1:Z+IZ7znVnD2idSmZAT72ilj13rKYLxVt4GVBOCNOPUc= -github.com/smartcontractkit/chainlink-common v0.4.2-0.20250310180230-58f4a9810e21/go.mod h1:YQuXIqQpmpAqstWV0LHaDTJ5nsSWuip5ivEM+Fisb+4= +github.com/smartcontractkit/chainlink-common v0.4.2-0.20250311155151-6b258d69b8a4 h1:1pdgg/h8tYlE8oPP8LIaX5n9bioEzBK5vbAnSqeQAbU= +github.com/smartcontractkit/chainlink-common v0.4.2-0.20250311155151-6b258d69b8a4/go.mod h1:YQuXIqQpmpAqstWV0LHaDTJ5nsSWuip5ivEM+Fisb+4= github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20250228145850-f846693a6fd5 h1:cJpPJ5hEwc6vlMoxmATS60uWPUi62ydnTVBabu6WKEE= github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20250228145850-f846693a6fd5/go.mod h1:2yUpKW1/jFxpozO/Zkh3fKDzI0jthXoEcU2xuDq+vlo= github.com/smartcontractkit/chainlink-feeds v0.1.2-0.20250227211209-7cd000095135 h1:8u9xUrC+yHrTDexOKDd+jrA6LCzFFHeX1G82oj2fsSI= github.com/smartcontractkit/chainlink-feeds v0.1.2-0.20250227211209-7cd000095135/go.mod h1:NkvE4iQgiT7dMCP6U3xPELHhWhN5Xr6rHC0axRebyMU= -github.com/smartcontractkit/chainlink-framework/chains v0.0.0-20250227163723-3c71fefea680 h1:Es/V5imh4at3NdHDWlbDMjljd24TrJQCy/+8xAVajl0= -github.com/smartcontractkit/chainlink-framework/chains v0.0.0-20250227163723-3c71fefea680/go.mod h1:tHem58EihQh63kR2LlAOKDAs9Vbghf1dJKZRGy6LG8g= +github.com/smartcontractkit/chainlink-framework/chains v0.0.0-20250311143712-d83af6d2a580 h1:Ctff6yL9mnsFEyefj0LwqLAUvN5flxyGJiZ5pKZpqAA= +github.com/smartcontractkit/chainlink-framework/chains v0.0.0-20250311143712-d83af6d2a580/go.mod h1:tHem58EihQh63kR2LlAOKDAs9Vbghf1dJKZRGy6LG8g= github.com/smartcontractkit/chainlink-framework/multinode v0.0.0-20250211162441-3d6cea220efb h1:LWijSyJ2lhppkFLN19EGsLHZXQ5wen2DEk1cyR0tV+o= github.com/smartcontractkit/chainlink-framework/multinode v0.0.0-20250211162441-3d6cea220efb/go.mod h1:4JqpgFy01LaqG1yM2iFTzwX3ZgcAvW9WdstBZQgPHzU= -github.com/smartcontractkit/chainlink-integrations/evm v0.0.0-20250304212534-9eff2fa32bea h1:qcbJAI8cfLezQiWi1OS87jiLFqqzdTaHbp4zNfNGiSU= -github.com/smartcontractkit/chainlink-integrations/evm v0.0.0-20250304212534-9eff2fa32bea/go.mod h1:SnIqxMeK33uC2og+sgMftKauW5dCioMBG5XzxA8tx6o= +github.com/smartcontractkit/chainlink-integrations/evm v0.0.0-20250311123343-5a841c234992 h1:JozqMfkum2Sbsj+LXi3ZpyCw6T6QTpNbQCm4Mjcb5f4= +github.com/smartcontractkit/chainlink-integrations/evm v0.0.0-20250311123343-5a841c234992/go.mod h1:Lx4JdHoPK1m5rV5iE7+4rGipwpAqa3qWkWrixKX2IXo= github.com/smartcontractkit/chainlink-protos/job-distributor v0.9.0 h1:hfMRj2ny6oNHd8w1rhJHdoX3YkoWJtCkBK6wTlCE4+c= github.com/smartcontractkit/chainlink-protos/job-distributor v0.9.0/go.mod h1:/dVVLXrsp+V0AbcYGJo3XMzKg3CkELsweA/TTopCsKE= github.com/smartcontractkit/chainlink-protos/orchestrator v0.5.0 h1:xRgu/kMkxcY4LeDKMBhaXU4khgya7v2wyb4Sa5Nzb+Y= @@ -1194,8 +1194,8 @@ github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20241009055228- github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20241009055228-33d0c0bf38de/go.mod h1:Sl2MF/Fp3fgJIVzhdGhmZZX2BlnM0oUUyBP4s4xYb6o= github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20241009055228-33d0c0bf38de h1:66VQxXx3lvTaAZrMBkIcdH9VEjujUEvmBQdnyOJnkOc= github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20241009055228-33d0c0bf38de/go.mod h1:NSc7hgOQbXG3DAwkOdWnZzLTZENXSwDJ7Va1nBp0YU0= -github.com/smartcontractkit/wsrpc v0.8.3 h1:9tDf7Ut61g36RJIyxV9iI73SqoOMasKPfURV9oMLrPg= -github.com/smartcontractkit/wsrpc v0.8.3/go.mod h1:2u/wfnhl5R4RlSXseN4n6HHIWk8w1Am3AT6gWftQbNg= +github.com/smartcontractkit/wsrpc v0.8.5-0.20250310183704-ea183816e1d1 h1:yfukbG7KzP3FGe3WOV4GHowHqnRW1Pg7fDz2vBucS10= +github.com/smartcontractkit/wsrpc v0.8.5-0.20250310183704-ea183816e1d1/go.mod h1:m3pdp17i4bD50XgktkzWetcV5yaLsi7Gunbv4ZgN6qg= github.com/smarty/assertions v1.15.0/go.mod h1:yABtdzeQs6l1brC900WlRNwj6ZR55d7B+E8C6HtKdec= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= diff --git a/system-tests/tests/go.mod b/system-tests/tests/go.mod index 55370b8a248..267cd8dffd4 100644 --- a/system-tests/tests/go.mod +++ b/system-tests/tests/go.mod @@ -343,12 +343,12 @@ require ( github.com/smartcontractkit/chainlink-automation v0.8.1 // indirect github.com/smartcontractkit/chainlink-ccip v0.0.0-20250307145254-e603dcbe3db1 // indirect github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20250307105933-7912a5e97ad0 // indirect - github.com/smartcontractkit/chainlink-common v0.4.2-0.20250310180230-58f4a9810e21 // indirect + github.com/smartcontractkit/chainlink-common v0.4.2-0.20250311155151-6b258d69b8a4 // indirect github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20250228145850-f846693a6fd5 // indirect github.com/smartcontractkit/chainlink-feeds v0.1.2-0.20250227211209-7cd000095135 // indirect - github.com/smartcontractkit/chainlink-framework/chains v0.0.0-20250227163723-3c71fefea680 // indirect + github.com/smartcontractkit/chainlink-framework/chains v0.0.0-20250311143712-d83af6d2a580 // indirect github.com/smartcontractkit/chainlink-framework/multinode v0.0.0-20250211162441-3d6cea220efb // indirect - github.com/smartcontractkit/chainlink-integrations/evm v0.0.0-20250304212534-9eff2fa32bea // indirect + github.com/smartcontractkit/chainlink-integrations/evm v0.0.0-20250311123343-5a841c234992 // indirect github.com/smartcontractkit/chainlink-protos/job-distributor v0.9.0 // indirect github.com/smartcontractkit/chainlink-protos/orchestrator v0.5.0 // indirect github.com/smartcontractkit/chainlink-protos/rmn/v1.6/go v0.0.0-20250131130834-15e0d4cde2a6 // indirect @@ -359,7 +359,7 @@ require ( github.com/smartcontractkit/mcms v0.13.0 // indirect github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20241009055228-33d0c0bf38de // indirect github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20241009055228-33d0c0bf38de // indirect - github.com/smartcontractkit/wsrpc v0.8.3 // indirect + github.com/smartcontractkit/wsrpc v0.8.5-0.20250310183704-ea183816e1d1 // indirect github.com/spf13/cast v1.7.1 // indirect github.com/spf13/cobra v1.8.1 // indirect github.com/spf13/pflag v1.0.6 // indirect diff --git a/system-tests/tests/go.sum b/system-tests/tests/go.sum index 80bcba926c6..6be2b4c67af 100644 --- a/system-tests/tests/go.sum +++ b/system-tests/tests/go.sum @@ -1156,18 +1156,18 @@ github.com/smartcontractkit/chainlink-ccip v0.0.0-20250307145254-e603dcbe3db1 h1 github.com/smartcontractkit/chainlink-ccip v0.0.0-20250307145254-e603dcbe3db1/go.mod h1:AhqYIeGF2k94J+/gzRx5dQttlgUdZid2N6E4HlHVIVA= github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20250307105933-7912a5e97ad0 h1:q19ElpBhjcA8yklJnHnNA04P9W3R7X+J2NTc1ZJvN4Q= github.com/smartcontractkit/chainlink-ccip/chains/solana v0.0.0-20250307105933-7912a5e97ad0/go.mod h1:2Y6JRpvj9EkgKgymvenuqCnra07+NYVB6+0rQGETSGA= -github.com/smartcontractkit/chainlink-common v0.4.2-0.20250310180230-58f4a9810e21 h1:Z+IZ7znVnD2idSmZAT72ilj13rKYLxVt4GVBOCNOPUc= -github.com/smartcontractkit/chainlink-common v0.4.2-0.20250310180230-58f4a9810e21/go.mod h1:YQuXIqQpmpAqstWV0LHaDTJ5nsSWuip5ivEM+Fisb+4= +github.com/smartcontractkit/chainlink-common v0.4.2-0.20250311155151-6b258d69b8a4 h1:1pdgg/h8tYlE8oPP8LIaX5n9bioEzBK5vbAnSqeQAbU= +github.com/smartcontractkit/chainlink-common v0.4.2-0.20250311155151-6b258d69b8a4/go.mod h1:YQuXIqQpmpAqstWV0LHaDTJ5nsSWuip5ivEM+Fisb+4= github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20250228145850-f846693a6fd5 h1:cJpPJ5hEwc6vlMoxmATS60uWPUi62ydnTVBabu6WKEE= github.com/smartcontractkit/chainlink-data-streams v0.1.1-0.20250228145850-f846693a6fd5/go.mod h1:2yUpKW1/jFxpozO/Zkh3fKDzI0jthXoEcU2xuDq+vlo= github.com/smartcontractkit/chainlink-feeds v0.1.2-0.20250227211209-7cd000095135 h1:8u9xUrC+yHrTDexOKDd+jrA6LCzFFHeX1G82oj2fsSI= github.com/smartcontractkit/chainlink-feeds v0.1.2-0.20250227211209-7cd000095135/go.mod h1:NkvE4iQgiT7dMCP6U3xPELHhWhN5Xr6rHC0axRebyMU= -github.com/smartcontractkit/chainlink-framework/chains v0.0.0-20250227163723-3c71fefea680 h1:Es/V5imh4at3NdHDWlbDMjljd24TrJQCy/+8xAVajl0= -github.com/smartcontractkit/chainlink-framework/chains v0.0.0-20250227163723-3c71fefea680/go.mod h1:tHem58EihQh63kR2LlAOKDAs9Vbghf1dJKZRGy6LG8g= +github.com/smartcontractkit/chainlink-framework/chains v0.0.0-20250311143712-d83af6d2a580 h1:Ctff6yL9mnsFEyefj0LwqLAUvN5flxyGJiZ5pKZpqAA= +github.com/smartcontractkit/chainlink-framework/chains v0.0.0-20250311143712-d83af6d2a580/go.mod h1:tHem58EihQh63kR2LlAOKDAs9Vbghf1dJKZRGy6LG8g= github.com/smartcontractkit/chainlink-framework/multinode v0.0.0-20250211162441-3d6cea220efb h1:LWijSyJ2lhppkFLN19EGsLHZXQ5wen2DEk1cyR0tV+o= github.com/smartcontractkit/chainlink-framework/multinode v0.0.0-20250211162441-3d6cea220efb/go.mod h1:4JqpgFy01LaqG1yM2iFTzwX3ZgcAvW9WdstBZQgPHzU= -github.com/smartcontractkit/chainlink-integrations/evm v0.0.0-20250304212534-9eff2fa32bea h1:qcbJAI8cfLezQiWi1OS87jiLFqqzdTaHbp4zNfNGiSU= -github.com/smartcontractkit/chainlink-integrations/evm v0.0.0-20250304212534-9eff2fa32bea/go.mod h1:SnIqxMeK33uC2og+sgMftKauW5dCioMBG5XzxA8tx6o= +github.com/smartcontractkit/chainlink-integrations/evm v0.0.0-20250311123343-5a841c234992 h1:JozqMfkum2Sbsj+LXi3ZpyCw6T6QTpNbQCm4Mjcb5f4= +github.com/smartcontractkit/chainlink-integrations/evm v0.0.0-20250311123343-5a841c234992/go.mod h1:Lx4JdHoPK1m5rV5iE7+4rGipwpAqa3qWkWrixKX2IXo= github.com/smartcontractkit/chainlink-protos/job-distributor v0.9.0 h1:hfMRj2ny6oNHd8w1rhJHdoX3YkoWJtCkBK6wTlCE4+c= github.com/smartcontractkit/chainlink-protos/job-distributor v0.9.0/go.mod h1:/dVVLXrsp+V0AbcYGJo3XMzKg3CkELsweA/TTopCsKE= github.com/smartcontractkit/chainlink-protos/orchestrator v0.5.0 h1:xRgu/kMkxcY4LeDKMBhaXU4khgya7v2wyb4Sa5Nzb+Y= @@ -1194,8 +1194,8 @@ github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20241009055228- github.com/smartcontractkit/tdh2/go/ocr2/decryptionplugin v0.0.0-20241009055228-33d0c0bf38de/go.mod h1:Sl2MF/Fp3fgJIVzhdGhmZZX2BlnM0oUUyBP4s4xYb6o= github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20241009055228-33d0c0bf38de h1:66VQxXx3lvTaAZrMBkIcdH9VEjujUEvmBQdnyOJnkOc= github.com/smartcontractkit/tdh2/go/tdh2 v0.0.0-20241009055228-33d0c0bf38de/go.mod h1:NSc7hgOQbXG3DAwkOdWnZzLTZENXSwDJ7Va1nBp0YU0= -github.com/smartcontractkit/wsrpc v0.8.3 h1:9tDf7Ut61g36RJIyxV9iI73SqoOMasKPfURV9oMLrPg= -github.com/smartcontractkit/wsrpc v0.8.3/go.mod h1:2u/wfnhl5R4RlSXseN4n6HHIWk8w1Am3AT6gWftQbNg= +github.com/smartcontractkit/wsrpc v0.8.5-0.20250310183704-ea183816e1d1 h1:yfukbG7KzP3FGe3WOV4GHowHqnRW1Pg7fDz2vBucS10= +github.com/smartcontractkit/wsrpc v0.8.5-0.20250310183704-ea183816e1d1/go.mod h1:m3pdp17i4bD50XgktkzWetcV5yaLsi7Gunbv4ZgN6qg= github.com/smarty/assertions v1.15.0/go.mod h1:yABtdzeQs6l1brC900WlRNwj6ZR55d7B+E8C6HtKdec= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=