From 44daea3c82f2199bb2e0fc4e7bfb4c4bd665e7ec Mon Sep 17 00:00:00 2001 From: Giorgio Gambino <151543+giogam@users.noreply.github.com> Date: Mon, 14 Oct 2024 21:40:14 +0200 Subject: [PATCH] feat(feeds) adds support for non EVM chain configs (#14731) * feat(feeds) adds support for non EVM chain configs * feat(feeds) add multichain to Test_CreateFeedsManagerChainConfig tests * feat(feeds): adds tests for aptos chain configs * chore(feeds): update mocks --------- Co-authored-by: James Kong --- core/services/feeds/models.go | 16 + core/services/feeds/service.go | 8 +- core/services/feeds/service_test.go | 450 +++++++++++------- .../feeds_manager_chain_config_test.go | 279 ++++++++++- 4 files changed, 548 insertions(+), 205 deletions(-) diff --git a/core/services/feeds/models.go b/core/services/feeds/models.go index 3fedc98d0f1..45a232faaa2 100644 --- a/core/services/feeds/models.go +++ b/core/services/feeds/models.go @@ -11,6 +11,7 @@ import ( "github.com/pkg/errors" "gopkg.in/guregu/null.v4" + proto "github.com/smartcontractkit/chainlink/v2/core/services/feeds/proto" "github.com/smartcontractkit/chainlink/v2/core/utils/crypto" ) @@ -77,7 +78,9 @@ type ChainType string const ( ChainTypeUnknown ChainType = "UNKNOWN" + ChainTypeAptos ChainType = "APTOS" ChainTypeEVM ChainType = "EVM" + ChainTypeSolana ChainType = "SOLANA" ChainTypeStarknet ChainType = "STARKNET" ) @@ -87,11 +90,24 @@ func NewChainType(s string) (ChainType, error) { return ChainTypeEVM, nil case "STARKNET": return ChainTypeStarknet, nil + case "SOLANA": + return ChainTypeSolana, nil + case "APTOS": + return ChainTypeAptos, nil default: return ChainTypeUnknown, errors.New("invalid chain type") } } +// ChainTypeToProtoChainType converts a ChainType to a proto.ChainType. +func ChainTypeToProtoChainType(chainType ChainType) proto.ChainType { + prefixed := "CHAIN_TYPE_" + string(chainType) + if chainType, exists := proto.ChainType_value[prefixed]; exists { + return proto.ChainType(chainType) + } + return proto.ChainType_CHAIN_TYPE_UNSPECIFIED +} + // FeedsManager defines a registered Feeds Manager Service and the connection // information. type FeedsManager struct { diff --git a/core/services/feeds/service.go b/core/services/feeds/service.go index d5c8c1ba22e..c736f5dabc0 100644 --- a/core/services/feeds/service.go +++ b/core/services/feeds/service.go @@ -1225,9 +1225,9 @@ func (s *service) generateJob(ctx context.Context, spec string) (*job.Job, error // newChainConfigMsg generates a chain config protobuf message. func (s *service) newChainConfigMsg(cfg ChainConfig) (*pb.ChainConfig, error) { - // Only supports EVM Chains - if cfg.ChainType != "EVM" { - return nil, errors.New("unsupported chain type") + protoChainType := ChainTypeToProtoChainType(cfg.ChainType) + if protoChainType == pb.ChainType_CHAIN_TYPE_UNSPECIFIED { + return nil, errors.Errorf("unsupported chain type: %s", cfg.ChainType) } ocr1Cfg, err := s.newOCR1ConfigMsg(cfg.OCR1Config) @@ -1243,7 +1243,7 @@ func (s *service) newChainConfigMsg(cfg ChainConfig) (*pb.ChainConfig, error) { pbChainConfig := pb.ChainConfig{ Chain: &pb.Chain{ Id: cfg.ChainID, - Type: pb.ChainType_CHAIN_TYPE_EVM, + Type: protoChainType, }, AccountAddress: cfg.AccountAddress, AdminAddress: cfg.AdminAddress, diff --git a/core/services/feeds/service_test.go b/core/services/feeds/service_test.go index 88c034657dc..396b59d75a9 100644 --- a/core/services/feeds/service_test.go +++ b/core/services/feeds/service_test.go @@ -484,57 +484,93 @@ func Test_Service_ListManagersByIDs(t *testing.T) { } func Test_Service_CreateChainConfig(t *testing.T) { - var ( - mgr = feeds.FeedsManager{ID: 1} - nodeVersion = &versioning.NodeVersion{ - Version: "1.0.0", - } - cfg = feeds.ChainConfig{ - FeedsManagerID: mgr.ID, - ChainID: "42", - ChainType: feeds.ChainTypeEVM, - AccountAddress: "0x0000000000000000000000000000000000000000", - AccountAddressPublicKey: null.StringFrom("0x0000000000000000000000000000000000000002"), - AdminAddress: "0x0000000000000000000000000000000000000001", - FluxMonitorConfig: feeds.FluxMonitorConfig{ - Enabled: true, - }, - OCR1Config: feeds.OCR1Config{ - Enabled: false, - }, - OCR2Config: feeds.OCR2ConfigModel{ - Enabled: false, - }, - } + tests := []struct { + name string + chainType feeds.ChainType + expectedID int64 + expectedChainType proto.ChainType + }{ + { + name: "EVM Chain Type", + chainType: feeds.ChainTypeEVM, + expectedID: int64(1), + expectedChainType: proto.ChainType_CHAIN_TYPE_EVM, + }, + { + name: "Solana Chain Type", + chainType: feeds.ChainTypeSolana, + expectedID: int64(1), + expectedChainType: proto.ChainType_CHAIN_TYPE_SOLANA, + }, + { + name: "Starknet Chain Type", + chainType: feeds.ChainTypeStarknet, + expectedID: int64(1), + expectedChainType: proto.ChainType_CHAIN_TYPE_STARKNET, + }, + { + name: "Aptos Chain Type", + chainType: feeds.ChainTypeAptos, + expectedID: int64(1), + expectedChainType: proto.ChainType_CHAIN_TYPE_APTOS, + }, + } - svc = setupTestService(t) - ) + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + var ( + mgr = feeds.FeedsManager{ID: 1} + nodeVersion = &versioning.NodeVersion{ + Version: "1.0.0", + } + cfg = feeds.ChainConfig{ + FeedsManagerID: mgr.ID, + ChainID: "42", + ChainType: tt.chainType, + AccountAddress: "0x0000000000000000000000000000000000000000", + AccountAddressPublicKey: null.StringFrom("0x0000000000000000000000000000000000000002"), + AdminAddress: "0x0000000000000000000000000000000000000001", + FluxMonitorConfig: feeds.FluxMonitorConfig{ + Enabled: true, + }, + OCR1Config: feeds.OCR1Config{ + Enabled: false, + }, + OCR2Config: feeds.OCR2ConfigModel{ + Enabled: false, + }, + } - svc.orm.On("CreateChainConfig", mock.Anything, cfg).Return(int64(1), nil) - svc.orm.On("GetManager", mock.Anything, mgr.ID).Return(&mgr, nil) - svc.connMgr.On("GetClient", mgr.ID).Return(svc.fmsClient, nil) - svc.orm.On("ListChainConfigsByManagerIDs", mock.Anything, []int64{mgr.ID}).Return([]feeds.ChainConfig{cfg}, nil) - svc.fmsClient.On("UpdateNode", mock.Anything, &proto.UpdateNodeRequest{ - Version: nodeVersion.Version, - ChainConfigs: []*proto.ChainConfig{ - { - Chain: &proto.Chain{ - Id: cfg.ChainID, - Type: proto.ChainType_CHAIN_TYPE_EVM, + svc = setupTestService(t) + ) + + svc.orm.On("CreateChainConfig", mock.Anything, cfg).Return(int64(1), nil) + svc.orm.On("GetManager", mock.Anything, mgr.ID).Return(&mgr, nil) + svc.connMgr.On("GetClient", mgr.ID).Return(svc.fmsClient, nil) + svc.orm.On("ListChainConfigsByManagerIDs", mock.Anything, []int64{mgr.ID}).Return([]feeds.ChainConfig{cfg}, nil) + svc.fmsClient.On("UpdateNode", mock.Anything, &proto.UpdateNodeRequest{ + Version: nodeVersion.Version, + ChainConfigs: []*proto.ChainConfig{ + { + Chain: &proto.Chain{ + Id: cfg.ChainID, + Type: tt.expectedChainType, + }, + AccountAddress: cfg.AccountAddress, + AccountAddressPublicKey: &cfg.AccountAddressPublicKey.String, + AdminAddress: cfg.AdminAddress, + FluxMonitorConfig: &proto.FluxMonitorConfig{Enabled: true}, + Ocr1Config: &proto.OCR1Config{Enabled: false}, + Ocr2Config: &proto.OCR2Config{Enabled: false}, + }, }, - AccountAddress: cfg.AccountAddress, - AccountAddressPublicKey: &cfg.AccountAddressPublicKey.String, - AdminAddress: cfg.AdminAddress, - FluxMonitorConfig: &proto.FluxMonitorConfig{Enabled: true}, - Ocr1Config: &proto.OCR1Config{Enabled: false}, - Ocr2Config: &proto.OCR2Config{Enabled: false}, - }, - }, - }).Return(&proto.UpdateNodeResponse{}, nil) + }).Return(&proto.UpdateNodeResponse{}, nil) - actual, err := svc.CreateChainConfig(testutils.Context(t), cfg) - require.NoError(t, err) - assert.Equal(t, int64(1), actual) + actual, err := svc.CreateChainConfig(testutils.Context(t), cfg) + require.NoError(t, err) + assert.Equal(t, tt.expectedID, actual) + }) + } } func Test_Service_CreateChainConfig_InvalidAdminAddress(t *testing.T) { @@ -608,51 +644,82 @@ func Test_Service_ListChainConfigsByManagerIDs(t *testing.T) { } func Test_Service_UpdateChainConfig(t *testing.T) { - var ( - mgr = feeds.FeedsManager{ID: 1} - nodeVersion = &versioning.NodeVersion{ - Version: "1.0.0", - } - cfg = feeds.ChainConfig{ - FeedsManagerID: mgr.ID, - ChainID: "42", - ChainType: feeds.ChainTypeEVM, - AccountAddress: "0x0000000000000000000000000000000000000000", - AccountAddressPublicKey: null.StringFrom("0x0000000000000000000000000000000000000002"), - AdminAddress: "0x0000000000000000000000000000000000000001", - FluxMonitorConfig: feeds.FluxMonitorConfig{Enabled: false}, - OCR1Config: feeds.OCR1Config{Enabled: false}, - OCR2Config: feeds.OCR2ConfigModel{Enabled: false}, - } + tests := []struct { + name string + chainType feeds.ChainType + expectedChainType proto.ChainType + }{ + { + name: "EVM Chain Type", + chainType: feeds.ChainTypeEVM, + expectedChainType: proto.ChainType_CHAIN_TYPE_EVM, + }, + { + name: "Solana Chain Type", + chainType: feeds.ChainTypeSolana, + expectedChainType: proto.ChainType_CHAIN_TYPE_SOLANA, + }, + { + name: "Starknet Chain Type", + chainType: feeds.ChainTypeStarknet, + expectedChainType: proto.ChainType_CHAIN_TYPE_STARKNET, + }, + { + name: "Aptos Chain Type", + chainType: feeds.ChainTypeAptos, + expectedChainType: proto.ChainType_CHAIN_TYPE_APTOS, + }, + } - svc = setupTestService(t) - ) + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + var ( + mgr = feeds.FeedsManager{ID: 1} + nodeVersion = &versioning.NodeVersion{ + Version: "1.0.0", + } + cfg = feeds.ChainConfig{ + FeedsManagerID: mgr.ID, + ChainID: "42", + ChainType: tt.chainType, + AccountAddress: "0x0000000000000000000000000000000000000000", + AccountAddressPublicKey: null.StringFrom("0x0000000000000000000000000000000000000002"), + AdminAddress: "0x0000000000000000000000000000000000000001", + FluxMonitorConfig: feeds.FluxMonitorConfig{Enabled: false}, + OCR1Config: feeds.OCR1Config{Enabled: false}, + OCR2Config: feeds.OCR2ConfigModel{Enabled: false}, + } - svc.orm.On("UpdateChainConfig", mock.Anything, cfg).Return(int64(1), nil) - svc.orm.On("GetChainConfig", mock.Anything, cfg.ID).Return(&cfg, nil) - svc.connMgr.On("GetClient", mgr.ID).Return(svc.fmsClient, nil) - svc.orm.On("ListChainConfigsByManagerIDs", mock.Anything, []int64{mgr.ID}).Return([]feeds.ChainConfig{cfg}, nil) - svc.fmsClient.On("UpdateNode", mock.Anything, &proto.UpdateNodeRequest{ - Version: nodeVersion.Version, - ChainConfigs: []*proto.ChainConfig{ - { - Chain: &proto.Chain{ - Id: cfg.ChainID, - Type: proto.ChainType_CHAIN_TYPE_EVM, + svc = setupTestService(t) + ) + + svc.orm.On("UpdateChainConfig", mock.Anything, cfg).Return(int64(1), nil) + svc.orm.On("GetChainConfig", mock.Anything, cfg.ID).Return(&cfg, nil) + svc.connMgr.On("GetClient", mgr.ID).Return(svc.fmsClient, nil) + svc.orm.On("ListChainConfigsByManagerIDs", mock.Anything, []int64{mgr.ID}).Return([]feeds.ChainConfig{cfg}, nil) + svc.fmsClient.On("UpdateNode", mock.Anything, &proto.UpdateNodeRequest{ + Version: nodeVersion.Version, + ChainConfigs: []*proto.ChainConfig{ + { + Chain: &proto.Chain{ + Id: cfg.ChainID, + Type: tt.expectedChainType, + }, + AccountAddress: cfg.AccountAddress, + AdminAddress: cfg.AdminAddress, + AccountAddressPublicKey: &cfg.AccountAddressPublicKey.String, + FluxMonitorConfig: &proto.FluxMonitorConfig{Enabled: false}, + Ocr1Config: &proto.OCR1Config{Enabled: false}, + Ocr2Config: &proto.OCR2Config{Enabled: false}, + }, }, - AccountAddress: cfg.AccountAddress, - AdminAddress: cfg.AdminAddress, - AccountAddressPublicKey: &cfg.AccountAddressPublicKey.String, - FluxMonitorConfig: &proto.FluxMonitorConfig{Enabled: false}, - Ocr1Config: &proto.OCR1Config{Enabled: false}, - Ocr2Config: &proto.OCR2Config{Enabled: false}, - }, - }, - }).Return(&proto.UpdateNodeResponse{}, nil) + }).Return(&proto.UpdateNodeResponse{}, nil) - actual, err := svc.UpdateChainConfig(testutils.Context(t), cfg) - require.NoError(t, err) - assert.Equal(t, int64(1), actual) + actual, err := svc.UpdateChainConfig(testutils.Context(t), cfg) + require.NoError(t, err) + assert.Equal(t, int64(1), actual) + }) + } } func Test_Service_UpdateChainConfig_InvalidAdminAddress(t *testing.T) { @@ -1492,102 +1559,133 @@ answer1 [type=median index=0]; } func Test_Service_SyncNodeInfo(t *testing.T) { - p2pKey := keystest.NewP2PKeyV2(t) - - ocrKey, err := ocrkey.NewV2() - require.NoError(t, err) - - var ( - multiaddr = "/dns4/chain.link/tcp/1234/p2p/16Uiu2HAm58SP7UL8zsnpeuwHfytLocaqgnyaYKP8wu7qRdrixLju" - mgr = &feeds.FeedsManager{ID: 1} - forwarderAddr = "0x0002" - ccfg = feeds.ChainConfig{ - ID: 100, - FeedsManagerID: mgr.ID, - ChainID: "42", - ChainType: feeds.ChainTypeEVM, - AccountAddress: "0x0000", - AdminAddress: "0x0001", - FluxMonitorConfig: feeds.FluxMonitorConfig{ - Enabled: true, - }, - OCR1Config: feeds.OCR1Config{ - Enabled: true, - IsBootstrap: false, - P2PPeerID: null.StringFrom(p2pKey.PeerID().String()), - KeyBundleID: null.StringFrom(ocrKey.GetID()), - }, - OCR2Config: feeds.OCR2ConfigModel{ - Enabled: true, - IsBootstrap: true, - Multiaddr: null.StringFrom(multiaddr), - ForwarderAddress: null.StringFrom(forwarderAddr), - Plugins: feeds.Plugins{ - Commit: true, - Execute: true, - Median: false, - Mercury: true, - Rebalancer: true, - }, - }, - } - chainConfigs = []feeds.ChainConfig{ccfg} - nodeVersion = &versioning.NodeVersion{Version: "1.0.0"} - ) - - svc := setupTestService(t) + tests := []struct { + name string + chainType feeds.ChainType + protoType proto.ChainType + }{ + { + name: "EVM Chain Type", + chainType: feeds.ChainTypeEVM, + protoType: proto.ChainType_CHAIN_TYPE_EVM, + }, + { + name: "Solana Chain Type", + chainType: feeds.ChainTypeSolana, + protoType: proto.ChainType_CHAIN_TYPE_SOLANA, + }, + { + name: "Starknet Chain Type", + chainType: feeds.ChainTypeStarknet, + protoType: proto.ChainType_CHAIN_TYPE_STARKNET, + }, + { + name: "Aptos Chain Type", + chainType: feeds.ChainTypeAptos, + protoType: proto.ChainType_CHAIN_TYPE_APTOS, + }, + } - svc.connMgr.On("GetClient", mgr.ID).Return(svc.fmsClient, nil) - svc.orm.On("ListChainConfigsByManagerIDs", mock.Anything, []int64{mgr.ID}).Return(chainConfigs, nil) + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + p2pKey := keystest.NewP2PKeyV2(t) - // OCR1 key fetching - svc.p2pKeystore.On("Get", p2pKey.PeerID()).Return(p2pKey, nil) - svc.ocr1Keystore.On("Get", ocrKey.GetID()).Return(ocrKey, nil) + ocrKey, err := ocrkey.NewV2() + require.NoError(t, err) - svc.fmsClient.On("UpdateNode", mock.Anything, &proto.UpdateNodeRequest{ - Version: nodeVersion.Version, - ChainConfigs: []*proto.ChainConfig{ - { - Chain: &proto.Chain{ - Id: ccfg.ChainID, - Type: proto.ChainType_CHAIN_TYPE_EVM, - }, - AccountAddress: ccfg.AccountAddress, - AdminAddress: ccfg.AdminAddress, - FluxMonitorConfig: &proto.FluxMonitorConfig{Enabled: true}, - Ocr1Config: &proto.OCR1Config{ - Enabled: true, - IsBootstrap: ccfg.OCR1Config.IsBootstrap, - P2PKeyBundle: &proto.OCR1Config_P2PKeyBundle{ - PeerId: p2pKey.PeerID().String(), - PublicKey: p2pKey.PublicKeyHex(), + var ( + multiaddr = "/dns4/chain.link/tcp/1234/p2p/16Uiu2HAm58SP7UL8zsnpeuwHfytLocaqgnyaYKP8wu7qRdrixLju" + mgr = &feeds.FeedsManager{ID: 1} + forwarderAddr = "0x0002" + ccfg = feeds.ChainConfig{ + ID: 100, + FeedsManagerID: mgr.ID, + ChainID: "42", + ChainType: tt.chainType, + AccountAddress: "0x0000", + AdminAddress: "0x0001", + FluxMonitorConfig: feeds.FluxMonitorConfig{ + Enabled: true, }, - OcrKeyBundle: &proto.OCR1Config_OCRKeyBundle{ - BundleId: ocrKey.GetID(), - ConfigPublicKey: ocrkey.ConfigPublicKey(ocrKey.PublicKeyConfig()).String(), - OffchainPublicKey: ocrKey.OffChainSigning.PublicKey().String(), - OnchainSigningAddress: ocrKey.OnChainSigning.Address().String(), + OCR1Config: feeds.OCR1Config{ + Enabled: true, + IsBootstrap: false, + P2PPeerID: null.StringFrom(p2pKey.PeerID().String()), + KeyBundleID: null.StringFrom(ocrKey.GetID()), }, - }, - Ocr2Config: &proto.OCR2Config{ - Enabled: true, - IsBootstrap: ccfg.OCR2Config.IsBootstrap, - Multiaddr: multiaddr, - ForwarderAddress: &forwarderAddr, - Plugins: &proto.OCR2Config_Plugins{ - Commit: ccfg.OCR2Config.Plugins.Commit, - Execute: ccfg.OCR2Config.Plugins.Execute, - Median: ccfg.OCR2Config.Plugins.Median, - Mercury: ccfg.OCR2Config.Plugins.Mercury, - Rebalancer: ccfg.OCR2Config.Plugins.Rebalancer, + OCR2Config: feeds.OCR2ConfigModel{ + Enabled: true, + IsBootstrap: true, + Multiaddr: null.StringFrom(multiaddr), + ForwarderAddress: null.StringFrom(forwarderAddr), + Plugins: feeds.Plugins{ + Commit: true, + Execute: true, + Median: false, + Mercury: true, + Rebalancer: true, + }, + }, + } + chainConfigs = []feeds.ChainConfig{ccfg} + nodeVersion = &versioning.NodeVersion{Version: "1.0.0"} + ) + + svc := setupTestService(t) + + svc.connMgr.On("GetClient", mgr.ID).Return(svc.fmsClient, nil) + svc.orm.On("ListChainConfigsByManagerIDs", mock.Anything, []int64{mgr.ID}).Return(chainConfigs, nil) + + // OCR1 key fetching + svc.p2pKeystore.On("Get", p2pKey.PeerID()).Return(p2pKey, nil) + svc.ocr1Keystore.On("Get", ocrKey.GetID()).Return(ocrKey, nil) + + svc.fmsClient.On("UpdateNode", mock.Anything, &proto.UpdateNodeRequest{ + Version: nodeVersion.Version, + ChainConfigs: []*proto.ChainConfig{ + { + Chain: &proto.Chain{ + Id: ccfg.ChainID, + Type: tt.protoType, + }, + AccountAddress: ccfg.AccountAddress, + AdminAddress: ccfg.AdminAddress, + FluxMonitorConfig: &proto.FluxMonitorConfig{Enabled: true}, + Ocr1Config: &proto.OCR1Config{ + Enabled: true, + IsBootstrap: ccfg.OCR1Config.IsBootstrap, + P2PKeyBundle: &proto.OCR1Config_P2PKeyBundle{ + PeerId: p2pKey.PeerID().String(), + PublicKey: p2pKey.PublicKeyHex(), + }, + OcrKeyBundle: &proto.OCR1Config_OCRKeyBundle{ + BundleId: ocrKey.GetID(), + ConfigPublicKey: ocrkey.ConfigPublicKey(ocrKey.PublicKeyConfig()).String(), + OffchainPublicKey: ocrKey.OffChainSigning.PublicKey().String(), + OnchainSigningAddress: ocrKey.OnChainSigning.Address().String(), + }, + }, + Ocr2Config: &proto.OCR2Config{ + Enabled: true, + IsBootstrap: ccfg.OCR2Config.IsBootstrap, + Multiaddr: multiaddr, + ForwarderAddress: &forwarderAddr, + Plugins: &proto.OCR2Config_Plugins{ + Commit: ccfg.OCR2Config.Plugins.Commit, + Execute: ccfg.OCR2Config.Plugins.Execute, + Median: ccfg.OCR2Config.Plugins.Median, + Mercury: ccfg.OCR2Config.Plugins.Mercury, + Rebalancer: ccfg.OCR2Config.Plugins.Rebalancer, + }, + }, }, }, - }, - }, - }).Return(&proto.UpdateNodeResponse{}, nil) + }).Return(&proto.UpdateNodeResponse{}, nil) - err = svc.SyncNodeInfo(testutils.Context(t), mgr.ID) - require.NoError(t, err) + err = svc.SyncNodeInfo(testutils.Context(t), mgr.ID) + require.NoError(t, err) + }) + } } func Test_Service_IsJobManaged(t *testing.T) { diff --git a/core/web/resolver/feeds_manager_chain_config_test.go b/core/web/resolver/feeds_manager_chain_config_test.go index bd4c1e05aeb..957583dbb7d 100644 --- a/core/web/resolver/feeds_manager_chain_config_test.go +++ b/core/web/resolver/feeds_manager_chain_config_test.go @@ -46,33 +46,37 @@ func Test_CreateFeedsManagerChainConfig(t *testing.T) { } } }` - variables = map[string]interface{}{ - "input": map[string]interface{}{ - "feedsManagerID": stringutils.FromInt64(mgrID), - "chainID": chainID, - "chainType": "EVM", - "accountAddr": accountAddr, - "accountAddrPubKey": acctAddrPubKey, - "adminAddr": adminAddr, - "fluxMonitorEnabled": false, - "ocr1Enabled": true, - "ocr1IsBootstrap": false, - "ocr1P2PPeerID": peerID.String, - "ocr1KeyBundleID": keyBundleID.String, - "ocr2Enabled": true, - "ocr2IsBootstrap": false, - "ocr2P2PPeerID": peerID.String, - "ocr2KeyBundleID": keyBundleID.String, - "ocr2Plugins": `{"commit":true,"execute":true,"median":false,"mercury":true,"rebalancer":true}`, - "ocr2ForwarderAddress": forwarderAddr, - }, + + withVariables = func(chainType string) map[string]interface{} { + variables := map[string]interface{}{ + "input": map[string]interface{}{ + "feedsManagerID": stringutils.FromInt64(mgrID), + "chainID": chainID, + "chainType": chainType, + "accountAddr": accountAddr, + "accountAddrPubKey": acctAddrPubKey, + "adminAddr": adminAddr, + "fluxMonitorEnabled": false, + "ocr1Enabled": true, + "ocr1IsBootstrap": false, + "ocr1P2PPeerID": peerID.String, + "ocr1KeyBundleID": keyBundleID.String, + "ocr2Enabled": true, + "ocr2IsBootstrap": false, + "ocr2P2PPeerID": peerID.String, + "ocr2KeyBundleID": keyBundleID.String, + "ocr2Plugins": `{"commit":true,"execute":true,"median":false,"mercury":true,"rebalancer":true}`, + "ocr2ForwarderAddress": forwarderAddr, + }, + } + return variables } ) testCases := []GQLTestCase{ - unauthorizedTestCase(GQLTestCase{query: mutation, variables: variables}, "createFeedsManagerChainConfig"), + unauthorizedTestCase(GQLTestCase{query: mutation, variables: withVariables("EVM")}, "createFeedsManagerChainConfig"), { - name: "success", + name: "success EVM", authenticated: true, before: func(ctx context.Context, f *gqlTestFramework) { f.App.On("GetFeedsService").Return(f.Mocks.feedsSvc) @@ -136,7 +140,232 @@ func Test_CreateFeedsManagerChainConfig(t *testing.T) { }, nil) }, query: mutation, - variables: variables, + variables: withVariables("EVM"), + result: ` + { + "createFeedsManagerChainConfig": { + "chainConfig": { + "id": "1" + } + } + }`, + }, + { + name: "success Solana", + authenticated: true, + before: func(ctx context.Context, f *gqlTestFramework) { + f.App.On("GetFeedsService").Return(f.Mocks.feedsSvc) + f.Mocks.feedsSvc.On("CreateChainConfig", mock.Anything, feeds.ChainConfig{ + FeedsManagerID: mgrID, + ChainType: feeds.ChainTypeSolana, + ChainID: chainID, + AccountAddress: accountAddr, + AccountAddressPublicKey: null.StringFrom(acctAddrPubKey), + AdminAddress: adminAddr, + FluxMonitorConfig: feeds.FluxMonitorConfig{ + Enabled: false, + }, + OCR1Config: feeds.OCR1Config{ + Enabled: true, + P2PPeerID: peerID, + KeyBundleID: keyBundleID, + }, + OCR2Config: feeds.OCR2ConfigModel{ + Enabled: true, + P2PPeerID: peerID, + KeyBundleID: keyBundleID, + ForwarderAddress: null.StringFrom(forwarderAddr), + Plugins: feeds.Plugins{ + Commit: true, + Execute: true, + Median: false, + Mercury: true, + Rebalancer: true, + }, + }, + }).Return(cfgID, nil) + f.Mocks.feedsSvc.On("GetChainConfig", mock.Anything, cfgID).Return(&feeds.ChainConfig{ + ID: cfgID, + ChainType: feeds.ChainTypeSolana, + ChainID: chainID, + AccountAddress: accountAddr, + AccountAddressPublicKey: null.StringFrom(acctAddrPubKey), + AdminAddress: adminAddr, + FluxMonitorConfig: feeds.FluxMonitorConfig{ + Enabled: false, + }, + OCR1Config: feeds.OCR1Config{ + Enabled: true, + P2PPeerID: peerID, + KeyBundleID: keyBundleID, + }, + OCR2Config: feeds.OCR2ConfigModel{ + Enabled: true, + P2PPeerID: peerID, + KeyBundleID: keyBundleID, + ForwarderAddress: null.StringFrom(forwarderAddr), + Plugins: feeds.Plugins{ + Commit: true, + Execute: true, + Median: false, + Mercury: true, + Rebalancer: true, + }, + }, + }, nil) + }, + query: mutation, + variables: withVariables("SOLANA"), + result: ` + { + "createFeedsManagerChainConfig": { + "chainConfig": { + "id": "1" + } + } + }`, + }, + { + name: "success Starknet", + authenticated: true, + before: func(ctx context.Context, f *gqlTestFramework) { + f.App.On("GetFeedsService").Return(f.Mocks.feedsSvc) + f.Mocks.feedsSvc.On("CreateChainConfig", mock.Anything, feeds.ChainConfig{ + FeedsManagerID: mgrID, + ChainType: feeds.ChainTypeStarknet, + ChainID: chainID, + AccountAddress: accountAddr, + AccountAddressPublicKey: null.StringFrom(acctAddrPubKey), + AdminAddress: adminAddr, + FluxMonitorConfig: feeds.FluxMonitorConfig{ + Enabled: false, + }, + OCR1Config: feeds.OCR1Config{ + Enabled: true, + P2PPeerID: peerID, + KeyBundleID: keyBundleID, + }, + OCR2Config: feeds.OCR2ConfigModel{ + Enabled: true, + P2PPeerID: peerID, + KeyBundleID: keyBundleID, + ForwarderAddress: null.StringFrom(forwarderAddr), + Plugins: feeds.Plugins{ + Commit: true, + Execute: true, + Median: false, + Mercury: true, + Rebalancer: true, + }, + }, + }).Return(cfgID, nil) + f.Mocks.feedsSvc.On("GetChainConfig", mock.Anything, cfgID).Return(&feeds.ChainConfig{ + ID: cfgID, + ChainType: feeds.ChainTypeStarknet, + ChainID: chainID, + AccountAddress: accountAddr, + AccountAddressPublicKey: null.StringFrom(acctAddrPubKey), + AdminAddress: adminAddr, + FluxMonitorConfig: feeds.FluxMonitorConfig{ + Enabled: false, + }, + OCR1Config: feeds.OCR1Config{ + Enabled: true, + P2PPeerID: peerID, + KeyBundleID: keyBundleID, + }, + OCR2Config: feeds.OCR2ConfigModel{ + Enabled: true, + P2PPeerID: peerID, + KeyBundleID: keyBundleID, + ForwarderAddress: null.StringFrom(forwarderAddr), + Plugins: feeds.Plugins{ + Commit: true, + Execute: true, + Median: false, + Mercury: true, + Rebalancer: true, + }, + }, + }, nil) + }, + query: mutation, + variables: withVariables("STARKNET"), + result: ` + { + "createFeedsManagerChainConfig": { + "chainConfig": { + "id": "1" + } + } + }`, + }, + { + name: "success APTOS", + authenticated: true, + before: func(ctx context.Context, f *gqlTestFramework) { + f.App.On("GetFeedsService").Return(f.Mocks.feedsSvc) + f.Mocks.feedsSvc.On("CreateChainConfig", mock.Anything, feeds.ChainConfig{ + FeedsManagerID: mgrID, + ChainType: feeds.ChainTypeAptos, + ChainID: chainID, + AccountAddress: accountAddr, + AccountAddressPublicKey: null.StringFrom(acctAddrPubKey), + AdminAddress: adminAddr, + FluxMonitorConfig: feeds.FluxMonitorConfig{ + Enabled: false, + }, + OCR1Config: feeds.OCR1Config{ + Enabled: true, + P2PPeerID: peerID, + KeyBundleID: keyBundleID, + }, + OCR2Config: feeds.OCR2ConfigModel{ + Enabled: true, + P2PPeerID: peerID, + KeyBundleID: keyBundleID, + ForwarderAddress: null.StringFrom(forwarderAddr), + Plugins: feeds.Plugins{ + Commit: true, + Execute: true, + Median: false, + Mercury: true, + Rebalancer: true, + }, + }, + }).Return(cfgID, nil) + f.Mocks.feedsSvc.On("GetChainConfig", mock.Anything, cfgID).Return(&feeds.ChainConfig{ + ID: cfgID, + ChainType: feeds.ChainTypeAptos, + ChainID: chainID, + AccountAddress: accountAddr, + AccountAddressPublicKey: null.StringFrom(acctAddrPubKey), + AdminAddress: adminAddr, + FluxMonitorConfig: feeds.FluxMonitorConfig{ + Enabled: false, + }, + OCR1Config: feeds.OCR1Config{ + Enabled: true, + P2PPeerID: peerID, + KeyBundleID: keyBundleID, + }, + OCR2Config: feeds.OCR2ConfigModel{ + Enabled: true, + P2PPeerID: peerID, + KeyBundleID: keyBundleID, + ForwarderAddress: null.StringFrom(forwarderAddr), + Plugins: feeds.Plugins{ + Commit: true, + Execute: true, + Median: false, + Mercury: true, + Rebalancer: true, + }, + }, + }, nil) + }, + query: mutation, + variables: withVariables("APTOS"), result: ` { "createFeedsManagerChainConfig": { @@ -154,7 +383,7 @@ func Test_CreateFeedsManagerChainConfig(t *testing.T) { f.Mocks.feedsSvc.On("CreateChainConfig", mock.Anything, mock.IsType(feeds.ChainConfig{})).Return(int64(0), sql.ErrNoRows) }, query: mutation, - variables: variables, + variables: withVariables("EVM"), result: ` { "createFeedsManagerChainConfig": { @@ -172,7 +401,7 @@ func Test_CreateFeedsManagerChainConfig(t *testing.T) { f.Mocks.feedsSvc.On("GetChainConfig", mock.Anything, cfgID).Return(nil, sql.ErrNoRows) }, query: mutation, - variables: variables, + variables: withVariables("EVM"), result: ` { "createFeedsManagerChainConfig": {