diff --git a/.github/e2e-tests.yml b/.github/e2e-tests.yml index 4b2e8fe8309..db9412c98a0 100644 --- a/.github/e2e-tests.yml +++ b/.github/e2e-tests.yml @@ -185,6 +185,23 @@ runner-test-matrix: # END: OCR tests + # START: CCIPv1.6 tests + + - id: smoke/ccip_test.go:* + path: integration-tests/smoke/ccip_test.go + test_env_type: docker + runs_on: ubuntu-latest + triggers: + - PR E2E Core Tests + - Merge Queue E2E Core Tests + - Nightly E2E Tests + test_cmd: cd integration-tests/ && go test smoke/ccip_test.go -timeout 12m -test.parallel=1 -count=1 -json + pyroscope_env: ci-smoke-ccipv1_6-evm-simulated + test_env_vars: + E2E_TEST_SELECTED_NETWORK: SIMULATED_1,SIMULATED_2 + + # END: CCIPv1.6 tests + # START: Automation tests - id: smoke/automation_test.go:^TestAutomationBasic/registry_2_0|TestAutomationBasic/registry_2_1_conditional|TestAutomationBasic/registry_2_1_logtrigger$ diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index 79db8c2859d..9fcc2b4c2f2 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -242,7 +242,7 @@ jobs: contents: read needs: [build-chainlink, changes] if: github.event_name == 'pull_request' && ( needs.changes.outputs.core_changes == 'true' || needs.changes.outputs.github_ci_changes == 'true') - uses: smartcontractkit/.github/.github/workflows/run-e2e-tests.yml@aad83f232743646faa35f5ac03ee3829148d37ce + uses: smartcontractkit/.github/.github/workflows/run-e2e-tests.yml@f2025f8695992ed7948c15ff5e458e4e9ddc9952 with: workflow_name: Run Core E2E Tests For PR chainlink_version: ${{ inputs.evm-ref || github.sha }} @@ -271,6 +271,7 @@ jobs: AWS_OIDC_IAM_ROLE_VALIDATION_PROD_ARN: ${{ secrets.AWS_OIDC_IAM_ROLE_VALIDATION_PROD_ARN }} AWS_API_GW_HOST_GRAFANA: ${{ secrets.AWS_API_GW_HOST_GRAFANA }} SLACK_BOT_TOKEN: ${{ secrets.QA_SLACK_API_KEY }} + AWS_ACCOUNT_ID_PROD: ${{ secrets.AWS_ACCOUNT_ID_PROD }} run-core-e2e-tests-for-merge-queue: name: Run Core E2E Tests For Merge Queue @@ -282,7 +283,7 @@ jobs: contents: read needs: [build-chainlink, changes] if: github.event_name == 'merge_group' && ( needs.changes.outputs.core_changes == 'true' || needs.changes.outputs.github_ci_changes == 'true') - uses: smartcontractkit/.github/.github/workflows/run-e2e-tests.yml@aad83f232743646faa35f5ac03ee3829148d37ce + uses: smartcontractkit/.github/.github/workflows/run-e2e-tests.yml@f2025f8695992ed7948c15ff5e458e4e9ddc9952 with: workflow_name: Run Core E2E Tests For Merge Queue chainlink_version: ${{ inputs.evm-ref || github.sha }} @@ -315,6 +316,7 @@ jobs: AWS_OIDC_IAM_ROLE_VALIDATION_PROD_ARN: ${{ secrets.AWS_OIDC_IAM_ROLE_VALIDATION_PROD_ARN }} AWS_API_GW_HOST_GRAFANA: ${{ secrets.AWS_API_GW_HOST_GRAFANA }} SLACK_BOT_TOKEN: ${{ secrets.QA_SLACK_API_KEY }} + AWS_ACCOUNT_ID_PROD: ${{ secrets.AWS_ACCOUNT_ID_PROD }} run-ccip-e2e-tests-for-pr: name: Run CCIP E2E Tests For PR @@ -326,7 +328,7 @@ jobs: contents: read needs: [build-chainlink, changes] if: github.event_name == 'pull_request' && (needs.changes.outputs.ccip_changes == 'true' || needs.changes.outputs.github_ci_changes == 'true') - uses: smartcontractkit/.github/.github/workflows/run-e2e-tests.yml@aad83f232743646faa35f5ac03ee3829148d37ce + uses: smartcontractkit/.github/.github/workflows/run-e2e-tests.yml@f2025f8695992ed7948c15ff5e458e4e9ddc9952 with: workflow_name: Run CCIP E2E Tests For PR chainlink_version: ${{ inputs.evm-ref || github.sha }} @@ -354,7 +356,8 @@ jobs: AWS_REGION: ${{ secrets.QA_AWS_REGION }} AWS_OIDC_IAM_ROLE_VALIDATION_PROD_ARN: ${{ secrets.AWS_OIDC_IAM_ROLE_VALIDATION_PROD_ARN }} AWS_API_GW_HOST_GRAFANA: ${{ secrets.AWS_API_GW_HOST_GRAFANA }} - SLACK_BOT_TOKEN: ${{ secrets.QA_SLACK_API_KEY }} + SLACK_BOT_TOKEN: ${{ secrets.QA_SLACK_API_KEY }} + AWS_ACCOUNT_ID_PROD: ${{ secrets.AWS_ACCOUNT_ID_PROD }} run-ccip-e2e-tests-for-merge-queue: name: Run CCIP E2E Tests For Merge Queue @@ -366,7 +369,7 @@ jobs: contents: read needs: [build-chainlink, changes] if: github.event_name == 'merge_group' && (needs.changes.outputs.ccip_changes == 'true' || needs.changes.outputs.github_ci_changes == 'true') - uses: smartcontractkit/.github/.github/workflows/run-e2e-tests.yml@aad83f232743646faa35f5ac03ee3829148d37ce + uses: smartcontractkit/.github/.github/workflows/run-e2e-tests.yml@f2025f8695992ed7948c15ff5e458e4e9ddc9952 with: workflow_name: Run CCIP E2E Tests For Merge Queue chainlink_version: ${{ inputs.evm-ref || github.sha }} @@ -395,6 +398,7 @@ jobs: AWS_OIDC_IAM_ROLE_VALIDATION_PROD_ARN: ${{ secrets.AWS_OIDC_IAM_ROLE_VALIDATION_PROD_ARN }} AWS_API_GW_HOST_GRAFANA: ${{ secrets.AWS_API_GW_HOST_GRAFANA }} SLACK_BOT_TOKEN: ${{ secrets.QA_SLACK_API_KEY }} + AWS_ACCOUNT_ID_PROD: ${{ secrets.AWS_ACCOUNT_ID_PROD }} check-e2e-test-results: if: always() diff --git a/core/capabilities/ccip/ccip_integration_tests/ccipreader/ccipreader_test.go b/core/capabilities/ccip/ccip_integration_tests/ccipreader/ccipreader_test.go index 00498ecb66a..c2cd25768a9 100644 --- a/core/capabilities/ccip/ccip_integration_tests/ccipreader/ccipreader_test.go +++ b/core/capabilities/ccip/ccip_integration_tests/ccipreader/ccipreader_test.go @@ -459,6 +459,7 @@ func testSetup(ctx context.Context, t *testing.T, readerChain, destChain cciptyp _, err1 := contract.SetSourceChainConfig(auth, uint64(sourceChain), ccip_reader_tester.OffRampSourceChainConfig{ IsEnabled: true, MinSeqNr: uint64(seqNum), + OnRamp: utils.RandomAddress().Bytes(), }) assert.NoError(t, err1) simulatedBackend.Commit() diff --git a/core/capabilities/ccip/ccip_integration_tests/usdcreader/usdcreader_test.go b/core/capabilities/ccip/ccip_integration_tests/usdcreader/usdcreader_test.go index e9ec613ce35..1699820da8b 100644 --- a/core/capabilities/ccip/ccip_integration_tests/usdcreader/usdcreader_test.go +++ b/core/capabilities/ccip/ccip_integration_tests/usdcreader/usdcreader_test.go @@ -11,6 +11,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/crypto" + "github.com/smartcontractkit/chainlink-common/pkg/utils/tests" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -197,7 +198,7 @@ func Test_USDCReader_MessageHashes(t *testing.T) { } } return true - }, 2*time.Second, 100*time.Millisecond) + }, tests.WaitTimeout(t), 100*time.Millisecond) }) } } diff --git a/core/scripts/go.mod b/core/scripts/go.mod index f86d91ecab1..d082e1ef2c1 100644 --- a/core/scripts/go.mod +++ b/core/scripts/go.mod @@ -273,7 +273,7 @@ require ( github.com/shirou/gopsutil v3.21.11+incompatible // indirect github.com/shirou/gopsutil/v3 v3.24.3 // indirect github.com/smartcontractkit/chain-selectors v1.0.23 // indirect - github.com/smartcontractkit/chainlink-ccip v0.0.0-20240924115754-8858b0423283 // indirect + github.com/smartcontractkit/chainlink-ccip v0.0.0-20240925142036-56f243802342 // indirect github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240911175228-daf2600bb7b7 // indirect github.com/smartcontractkit/chainlink-data-streams v0.0.0-20240916152957-433914114bd2 // indirect github.com/smartcontractkit/chainlink-feeds v0.0.0-20240910155501-42f20443189f // indirect diff --git a/core/scripts/go.sum b/core/scripts/go.sum index 8569a9ac200..a7d44e811ec 100644 --- a/core/scripts/go.sum +++ b/core/scripts/go.sum @@ -1085,8 +1085,8 @@ github.com/smartcontractkit/chain-selectors v1.0.23 h1:D2Eaex4Cw/O7Lg3tX6WklOqnj github.com/smartcontractkit/chain-selectors v1.0.23/go.mod h1:d4Hi+E1zqjy9HqMkjBE5q1vcG9VGgxf5VxiRHfzi2kE= github.com/smartcontractkit/chainlink-automation v1.0.4 h1:iyW181JjKHLNMnDleI8umfIfVVlwC7+n5izbLSFgjw8= github.com/smartcontractkit/chainlink-automation v1.0.4/go.mod h1:u4NbPZKJ5XiayfKHD/v3z3iflQWqvtdhj13jVZXj/cM= -github.com/smartcontractkit/chainlink-ccip v0.0.0-20240924115754-8858b0423283 h1:f0vdqcOL9kJZwfmWE76roIyEuiZx/R82js0IfXNAvXg= -github.com/smartcontractkit/chainlink-ccip v0.0.0-20240924115754-8858b0423283/go.mod h1:KP82vFCqm+M1G1t6Vos5CewGUGYJkxxCEdxnta4uLlE= +github.com/smartcontractkit/chainlink-ccip v0.0.0-20240925142036-56f243802342 h1:uEgdiVPKiPkwSXpsRgK9gxC2TMpjvE5GXpSPl/C20r0= +github.com/smartcontractkit/chainlink-ccip v0.0.0-20240925142036-56f243802342/go.mod h1:VyldDDFSelaLyEXO1M7xVoGTTtlT9apfxh90vIMeOwc= github.com/smartcontractkit/chainlink-common v0.2.3-0.20240925085218-aded1b263ecc h1:ALbyaoRzUSXQ2NhGFKVOyJqO22IB5yQjhjKWbIZGbrI= github.com/smartcontractkit/chainlink-common v0.2.3-0.20240925085218-aded1b263ecc/go.mod h1:F6WUS6N4mP5ScwpwyTyAJc9/vjR+GXbMCRUOVekQi1g= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240911175228-daf2600bb7b7 h1:lTGIOQYLk1Ufn++X/AvZnt6VOcuhste5yp+C157No/Q= diff --git a/go.mod b/go.mod index 6c796344ae8..19d5ae71265 100644 --- a/go.mod +++ b/go.mod @@ -75,7 +75,7 @@ require ( github.com/shopspring/decimal v1.4.0 github.com/smartcontractkit/chain-selectors v1.0.23 github.com/smartcontractkit/chainlink-automation v1.0.4 - github.com/smartcontractkit/chainlink-ccip v0.0.0-20240924115754-8858b0423283 + github.com/smartcontractkit/chainlink-ccip v0.0.0-20240925142036-56f243802342 github.com/smartcontractkit/chainlink-common v0.2.3-0.20240925085218-aded1b263ecc github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240911175228-daf2600bb7b7 github.com/smartcontractkit/chainlink-data-streams v0.0.0-20240916152957-433914114bd2 diff --git a/go.sum b/go.sum index 4b270409c3e..96761f00d17 100644 --- a/go.sum +++ b/go.sum @@ -1046,8 +1046,8 @@ github.com/smartcontractkit/chain-selectors v1.0.23 h1:D2Eaex4Cw/O7Lg3tX6WklOqnj github.com/smartcontractkit/chain-selectors v1.0.23/go.mod h1:d4Hi+E1zqjy9HqMkjBE5q1vcG9VGgxf5VxiRHfzi2kE= github.com/smartcontractkit/chainlink-automation v1.0.4 h1:iyW181JjKHLNMnDleI8umfIfVVlwC7+n5izbLSFgjw8= github.com/smartcontractkit/chainlink-automation v1.0.4/go.mod h1:u4NbPZKJ5XiayfKHD/v3z3iflQWqvtdhj13jVZXj/cM= -github.com/smartcontractkit/chainlink-ccip v0.0.0-20240924115754-8858b0423283 h1:f0vdqcOL9kJZwfmWE76roIyEuiZx/R82js0IfXNAvXg= -github.com/smartcontractkit/chainlink-ccip v0.0.0-20240924115754-8858b0423283/go.mod h1:KP82vFCqm+M1G1t6Vos5CewGUGYJkxxCEdxnta4uLlE= +github.com/smartcontractkit/chainlink-ccip v0.0.0-20240925142036-56f243802342 h1:uEgdiVPKiPkwSXpsRgK9gxC2TMpjvE5GXpSPl/C20r0= +github.com/smartcontractkit/chainlink-ccip v0.0.0-20240925142036-56f243802342/go.mod h1:VyldDDFSelaLyEXO1M7xVoGTTtlT9apfxh90vIMeOwc= github.com/smartcontractkit/chainlink-common v0.2.3-0.20240925085218-aded1b263ecc h1:ALbyaoRzUSXQ2NhGFKVOyJqO22IB5yQjhjKWbIZGbrI= github.com/smartcontractkit/chainlink-common v0.2.3-0.20240925085218-aded1b263ecc/go.mod h1:F6WUS6N4mP5ScwpwyTyAJc9/vjR+GXbMCRUOVekQi1g= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240911175228-daf2600bb7b7 h1:lTGIOQYLk1Ufn++X/AvZnt6VOcuhste5yp+C157No/Q= diff --git a/integration-tests/deployment/ccip/deploy_home_chain.go b/integration-tests/deployment/ccip/deploy_home_chain.go index c9d3814a672..5a625a1ef1c 100644 --- a/integration-tests/deployment/ccip/deploy_home_chain.go +++ b/integration-tests/deployment/ccip/deploy_home_chain.go @@ -3,12 +3,12 @@ package ccipdeployment import ( "bytes" "context" - "errors" "fmt" "time" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" + "github.com/pkg/errors" "github.com/smartcontractkit/chainlink-ccip/chainconfig" "github.com/smartcontractkit/chainlink-ccip/pluginconfig" @@ -140,6 +140,10 @@ func AddNodes( ) error { var nodeParams []capabilities_registry.CapabilitiesRegistryNodeParams for _, p2pID := range p2pIDs { + // if any p2pIDs are empty throw error + if bytes.Equal(p2pID[:], make([]byte, 32)) { + return errors.Wrapf(errors.New("empty p2pID"), "p2pID: %x selector: %d", p2pID, chain.Selector) + } nodeParam := capabilities_registry.CapabilitiesRegistryNodeParams{ NodeOperatorId: NodeOperatorID, Signer: p2pID, // Not used in tests diff --git a/integration-tests/deployment/ccip/test_helpers.go b/integration-tests/deployment/ccip/test_helpers.go index 8f7a7b6c90e..c306ba4fd6a 100644 --- a/integration-tests/deployment/ccip/test_helpers.go +++ b/integration-tests/deployment/ccip/test_helpers.go @@ -9,6 +9,9 @@ import ( "time" "github.com/ethereum/go-ethereum/accounts/abi/bind" + "golang.org/x/sync/errgroup" + + "github.com/smartcontractkit/chainlink-testing-framework/lib/utils/testcontext" "github.com/smartcontractkit/chainlink-testing-framework/lib/logging" @@ -23,6 +26,7 @@ import ( "github.com/smartcontractkit/chainlink/integration-tests/deployment" jobv1 "github.com/smartcontractkit/chainlink/integration-tests/deployment/jd/job/v1" "github.com/smartcontractkit/chainlink/integration-tests/deployment/memory" + "github.com/smartcontractkit/chainlink/integration-tests/docker/test_env" "github.com/smartcontractkit/chainlink-common/pkg/logger" @@ -55,12 +59,30 @@ func Context(tb testing.TB) context.Context { return ctx } -type DeployedTestEnvironment struct { +type DeployedEnv struct { Ab deployment.AddressBook Env deployment.Environment HomeChainSel uint64 FeedChainSel uint64 - Nodes map[string]memory.Node +} + +type DeployedTestEnvironment struct { + DeployedEnv + Nodes map[string]memory.Node +} + +func SetUpHomeAndFeedChains(t *testing.T, lggr logger.Logger, homeChainSel, feedChainSel uint64, chains map[uint64]deployment.Chain) (deployment.AddressBook, deployment.CapabilityRegistryConfig) { + homeChainEVM, _ := chainsel.ChainIdFromSelector(homeChainSel) + ab, capReg, err := DeployCapReg(lggr, chains[homeChainSel]) + require.NoError(t, err) + + feedAb, _, err := DeployFeeds(lggr, chains[feedChainSel]) + require.NoError(t, err) + require.NoError(t, ab.Merge(feedAb)) + return ab, deployment.CapabilityRegistryConfig{ + EVMChainID: homeChainEVM, + Contract: capReg, + } } // NewEnvironmentWithCRAndFeeds creates a new CCIP environment @@ -80,19 +102,10 @@ func NewEnvironmentWithCRAndFeeds(t *testing.T, lggr logger.Logger, numChains in }) // Take lowest for determinism. homeChainSel := chainSels[HomeChainIndex] - homeChainEVM, _ := chainsel.ChainIdFromSelector(homeChainSel) - ab, capReg, err := DeployCapReg(lggr, chains[homeChainSel]) - require.NoError(t, err) - feedSel := chainSels[FeedChainIndex] - feedAb, _, err := DeployFeeds(lggr, chains[feedSel]) - require.NoError(t, err) - require.NoError(t, ab.Merge(feedAb)) + ab, capReg := SetUpHomeAndFeedChains(t, lggr, homeChainSel, feedSel, chains) - nodes := memory.NewNodes(t, zapcore.InfoLevel, chains, 4, 1, deployment.CapabilityRegistryConfig{ - EVMChainID: homeChainEVM, - Contract: capReg, - }) + nodes := memory.NewNodes(t, zapcore.InfoLevel, chains, 4, 1, capReg) for _, node := range nodes { require.NoError(t, node.App.Start(ctx)) t.Cleanup(func() { @@ -102,11 +115,13 @@ func NewEnvironmentWithCRAndFeeds(t *testing.T, lggr logger.Logger, numChains in e := memory.NewMemoryEnvironmentFromChainsNodes(t, lggr, chains, nodes) return DeployedTestEnvironment{ - Ab: ab, - Env: e, - HomeChainSel: homeChainSel, - FeedChainSel: feedSel, - Nodes: nodes, + DeployedEnv: DeployedEnv{ + Ab: ab, + Env: e, + HomeChainSel: homeChainSel, + FeedChainSel: feedSel, + }, + Nodes: nodes, } } @@ -136,11 +151,13 @@ func NewEnvironmentWithCRAndJobs(t *testing.T, lggr logger.Logger, numChains int } func ReplayAllLogs(nodes map[string]memory.Node, chains map[uint64]deployment.Chain) error { + blockBySel := make(map[uint64]uint64) + for sel := range chains { + blockBySel[sel] = 1 + } for _, node := range nodes { - for sel := range chains { - if err := node.ReplayLogs(map[uint64]uint64{sel: 1}); err != nil { - return err - } + if err := node.ReplayLogs(blockBySel); err != nil { + return err } } return nil @@ -187,10 +204,28 @@ func SendRequest(t *testing.T, e deployment.Environment, state CCIPOnChainState, // DeployedLocalDevEnvironment is a helper struct for setting up a local dev environment with docker type DeployedLocalDevEnvironment struct { - Ab deployment.AddressBook - Env deployment.Environment - HomeChainSel uint64 - Nodes []devenv.Node + DeployedEnv + testEnv *test_env.CLClusterTestEnv + DON *devenv.DON +} + +func (d DeployedLocalDevEnvironment) RestartChainlinkNodes(t *testing.T) error { + errGrp := errgroup.Group{} + for _, n := range d.testEnv.ClCluster.Nodes { + n := n + errGrp.Go(func() error { + if err := n.Container.Terminate(testcontext.Get(t)); err != nil { + return err + } + err := n.RestartContainer() + if err != nil { + return err + } + return nil + }) + + } + return errGrp.Wait() } func NewDeployedLocalDevEnvironment(t *testing.T, lggr logger.Logger) DeployedLocalDevEnvironment { @@ -206,21 +241,12 @@ func NewDeployedLocalDevEnvironment(t *testing.T, lggr logger.Logger) DeployedLo // locate the home chain homeChainSel := envConfig.HomeChainSelector require.NotEmpty(t, homeChainSel, "homeChainSel should not be empty") - homeChainEVM, err := chainsel.ChainIdFromSelector(homeChainSel) - require.NoError(t, err) - require.NotEmpty(t, homeChainEVM, "homeChainEVM should not be empty") - - // deploy the capability registry - ab, capReg, err := DeployCapReg(lggr, chains[homeChainSel]) - require.NoError(t, err) + feedSel := envConfig.FeedChainSelector + require.NotEmpty(t, feedSel, "feedSel should not be empty") + ab, capReg := SetUpHomeAndFeedChains(t, lggr, homeChainSel, feedSel, chains) // start the chainlink nodes with the CR address - err = devenv.StartChainlinkNodes(t, - envConfig, deployment.CapabilityRegistryConfig{ - EVMChainID: homeChainEVM, - Contract: capReg, - }, - testEnv, cfg) + err = devenv.StartChainlinkNodes(t, envConfig, capReg, testEnv, cfg) require.NoError(t, err) e, don, err := devenv.NewEnvironment(ctx, lggr, *envConfig) @@ -230,11 +256,16 @@ func NewDeployedLocalDevEnvironment(t *testing.T, lggr logger.Logger) DeployedLo zeroLogLggr := logging.GetTestLogger(t) // fund the nodes devenv.FundNodes(t, zeroLogLggr, testEnv, cfg, don.PluginNodes()) + return DeployedLocalDevEnvironment{ - Ab: ab, - Env: *e, - HomeChainSel: homeChainSel, - Nodes: don.Nodes, + DeployedEnv: DeployedEnv{ + Ab: ab, + Env: *e, + HomeChainSel: homeChainSel, + FeedChainSel: feedSel, + }, + DON: don, + testEnv: testEnv, } } diff --git a/integration-tests/deployment/devenv/.sample.env b/integration-tests/deployment/devenv/.sample.env index f0505cf857a..ddf0b97e9a9 100644 --- a/integration-tests/deployment/devenv/.sample.env +++ b/integration-tests/deployment/devenv/.sample.env @@ -1,3 +1,6 @@ +# set the following if you don't want the test to tear down the docker containers after test run is finished +# TESTCONTAINERS_RYUK_DISABLED=true + E2E_JD_IMAGE= E2E_JD_VERSION= diff --git a/integration-tests/deployment/devenv/README.md b/integration-tests/deployment/devenv/README.md index a1f264dfce2..cb2b5cb8d6f 100644 --- a/integration-tests/deployment/devenv/README.md +++ b/integration-tests/deployment/devenv/README.md @@ -8,6 +8,10 @@ It can either create new simulated private Ethereum network containers or connec The tests created with this environment are run as [end-to-end integration smoke tests](../../smoke). +Pre-requisites: +- Docker +- Pull access for chainlink and job-distributor images + #### Setting Up Testconfig with Simulated Private Ethereum Network To run tests (e.g., [ccip-test](../../smoke/ccip_test.go)), diff --git a/integration-tests/deployment/devenv/build_env.go b/integration-tests/deployment/devenv/build_env.go index 61e677ca435..a36a6f51a69 100644 --- a/integration-tests/deployment/devenv/build_env.go +++ b/integration-tests/deployment/devenv/build_env.go @@ -110,24 +110,16 @@ func CreateDockerEnv(t *testing.T) ( } require.NotEmpty(t, jdConfig, "JD config is empty") - homeChainSelector, err := cfg.CCIP.GetHomeChainSelector() + homeChainSelector, err := cfg.CCIP.GetHomeChainSelector(evmNetworks) require.NoError(t, err, "Error getting home chain selector") - homeChainID, err := chainselectors.ChainIdFromSelector(homeChainSelector) - require.NoError(t, err, "Error getting chain id from selector") - // verify if the home chain selector is valid - validHomeChain := false - for _, net := range evmNetworks { - if net.ChainID == int64(homeChainID) { - validHomeChain = true - break - } - } - require.True(t, validHomeChain, "Invalid home chain selector, chain not found in network config") + feedChainSelector, err := cfg.CCIP.GetFeedChainSelector(evmNetworks) + require.NoError(t, err, "Error getting feed chain selector") return &EnvironmentConfig{ Chains: chains, JDConfig: jdConfig, HomeChainSelector: homeChainSelector, + FeedChainSelector: feedChainSelector, }, env, cfg } @@ -318,6 +310,7 @@ func CreateChainConfigFromNetworks( require.NoError(t, err) deployer, err := bind.NewKeyedTransactorWithChainID(pvtKey, big.NewInt(chainId)) require.NoError(t, err) + deployer.GasLimit = net.DefaultGasLimit chains = append(chains, ChainConfig{ ChainID: uint64(chainId), ChainName: chainName, @@ -344,7 +337,7 @@ func CreateChainConfigFromNetworks( chains = append(chains, ChainConfig{ ChainID: uint64(chainId), ChainName: chainName, - ChainType: "EVM", + ChainType: EVMChainType, WSRPCs: rpcProvider.PublicWsUrls(), HTTPRPCs: rpcProvider.PublicHttpUrls(), DeployerKey: deployer, diff --git a/integration-tests/deployment/devenv/chain.go b/integration-tests/deployment/devenv/chain.go index e40bbc066fd..de02437fec7 100644 --- a/integration-tests/deployment/devenv/chain.go +++ b/integration-tests/deployment/devenv/chain.go @@ -16,6 +16,10 @@ import ( "github.com/smartcontractkit/chainlink/integration-tests/deployment" ) +const ( + EVMChainType = "EVM" +) + // ChainConfig holds the configuration for a with a deployer key which can be used to send transactions to the chain. type ChainConfig struct { ChainID uint64 // chain id as per EIP-155, mainly applicable for EVM chains diff --git a/integration-tests/deployment/devenv/don.go b/integration-tests/deployment/devenv/don.go index ab64eab5c5e..9478b729f29 100644 --- a/integration-tests/deployment/devenv/don.go +++ b/integration-tests/deployment/devenv/don.go @@ -9,6 +9,7 @@ import ( "github.com/AlekSi/pointer" "github.com/hashicorp/go-multierror" "github.com/rs/zerolog" + chainsel "github.com/smartcontractkit/chain-selectors" clclient "github.com/smartcontractkit/chainlink/integration-tests/client" nodev1 "github.com/smartcontractkit/chainlink/integration-tests/deployment/jd/node/v1" @@ -47,6 +48,16 @@ func (don *DON) PluginNodes() []Node { return pluginNodes } +// ReplayAllLogs replays all logs for the chains on all nodes for given block numbers for each chain +func (don *DON) ReplayAllLogs(blockbyChain map[uint64]uint64) error { + for _, node := range don.Nodes { + if err := node.ReplayLogs(blockbyChain); err != nil { + return err + } + } + return nil +} + func (don *DON) NodeIds() []string { var nodeIds []string for _, node := range don.Nodes { @@ -55,13 +66,14 @@ func (don *DON) NodeIds() []string { return nodeIds } -func (don *DON) CreateSupportedChains(ctx context.Context, chains []ChainConfig) error { +func (don *DON) CreateSupportedChains(ctx context.Context, chains []ChainConfig, jd JobDistributor) error { var err error - for i, node := range don.Nodes { - if err1 := node.CreateCCIPOCRSupportedChains(ctx, chains); err1 != nil { + for i := range don.Nodes { + node := &don.Nodes[i] + if err1 := node.CreateCCIPOCRSupportedChains(ctx, chains, jd); err1 != nil { err = multierror.Append(err, err1) } - don.Nodes[i] = node + don.Nodes[i] = *node } return err } @@ -147,7 +159,7 @@ type Node struct { // It works under assumption that the node is already registered with the job distributor. // It expects bootstrap nodes to have label with key "type" and value as "bootstrap". // It fetches the account address, peer id, and OCR2 key bundle id and creates the JobDistributorChainConfig. -func (n *Node) CreateCCIPOCRSupportedChains(ctx context.Context, chains []ChainConfig) error { +func (n *Node) CreateCCIPOCRSupportedChains(ctx context.Context, chains []ChainConfig, jd JobDistributor) error { for _, chain := range chains { chainId := strconv.FormatUint(chain.ChainID, 10) accountAddr, err := n.gqlClient.FetchAccountAddress(ctx, chainId) @@ -184,21 +196,39 @@ func (n *Node) CreateCCIPOCRSupportedChains(ctx context.Context, chains []ChainC break } } - err = n.gqlClient.CreateJobDistributorChainConfig(ctx, client.JobDistributorChainConfigInput{ - JobDistributorID: n.JDId, - ChainID: chainId, - ChainType: chain.ChainType, - AccountAddr: pointer.GetString(accountAddr), - AdminAddr: n.adminAddr, - Ocr2Enabled: true, - Ocr2IsBootstrap: isBootstrap, - Ocr2Multiaddr: n.multiAddr, - Ocr2P2PPeerID: pointer.GetString(peerID), - Ocr2KeyBundleID: ocr2BundleId, - Ocr2Plugins: `{"commit":true,"execute":true,"median":false,"mercury":false}`, - }) - if err != nil { - return fmt.Errorf("failed to create CCIPOCR2SupportedChains for node %s: %w", n.Name, err) + // JD silently fails to update nodeChainConfig. Therefore, we fetch the node config and + // if it's not updated , we retry creating the chain config. + // as a workaround, we keep trying creating the chain config for 3 times until it's created + retryCount := 1 + for retryCount < 3 { + err = n.gqlClient.CreateJobDistributorChainConfig(ctx, client.JobDistributorChainConfigInput{ + JobDistributorID: n.JDId, + ChainID: chainId, + ChainType: chain.ChainType, + AccountAddr: pointer.GetString(accountAddr), + AdminAddr: n.adminAddr, + Ocr2Enabled: true, + Ocr2IsBootstrap: isBootstrap, + Ocr2Multiaddr: n.multiAddr, + Ocr2P2PPeerID: pointer.GetString(peerID), + Ocr2KeyBundleID: ocr2BundleId, + Ocr2Plugins: `{"commit":true,"execute":true,"median":false,"mercury":false}`, + }) + if err != nil { + return fmt.Errorf("failed to create CCIPOCR2SupportedChains for node %s: %w", n.Name, err) + } + + nodeChainConfigs, err := jd.ListNodeChainConfigs(context.Background(), &nodev1.ListNodeChainConfigsRequest{ + Filter: &nodev1.ListNodeChainConfigsRequest_Filter{ + NodeIds: []string{n.NodeId}, + }}) + if err != nil { + return fmt.Errorf("failed to list node chain configs for node %s: %w", n.Name, err) + } + if nodeChainConfigs != nil && len(nodeChainConfigs.ChainConfigs) > 0 { + break + } + retryCount++ } } return nil @@ -280,3 +310,21 @@ func (n *Node) SetUpAndLinkJobDistributor(ctx context.Context, jd JobDistributor func (n *Node) ExportEVMKeysForChain(chainId string) ([]*clclient.ExportedEVMKey, error) { return n.restClient.ExportEVMKeysForChain(chainId) } + +// ReplayLogs replays logs for the chains on the node for given block numbers for each chain +func (n *Node) ReplayLogs(blockByChain map[uint64]uint64) error { + for sel, block := range blockByChain { + chainID, err := chainsel.ChainIdFromSelector(sel) + if err != nil { + return err + } + response, _, err := n.restClient.ReplayLogPollerFromBlock(int64(block), int64(chainID)) + if err != nil { + return err + } + if response.Data.Attributes.Message != "Replay started" { + return fmt.Errorf("unexpected response message from log poller's replay: %s", response.Data.Attributes.Message) + } + } + return nil +} diff --git a/integration-tests/deployment/devenv/environment.go b/integration-tests/deployment/devenv/environment.go index f7513798e37..74cde258cc3 100644 --- a/integration-tests/deployment/devenv/environment.go +++ b/integration-tests/deployment/devenv/environment.go @@ -16,6 +16,7 @@ const ( type EnvironmentConfig struct { Chains []ChainConfig HomeChainSelector uint64 + FeedChainSelector uint64 nodeInfo []NodeInfo JDConfig JDConfig } @@ -40,7 +41,7 @@ func NewEnvironment(ctx context.Context, lggr logger.Logger, config EnvironmentC } nodeIDs := don.NodeIds() - err = don.CreateSupportedChains(ctx, config.Chains) + err = don.CreateSupportedChains(ctx, config.Chains, jd) if err != nil { return nil, nil, err } diff --git a/integration-tests/deployment/jd/node/v1/node.pb.go b/integration-tests/deployment/jd/node/v1/node.pb.go index 224109b8269..172e2856454 100644 --- a/integration-tests/deployment/jd/node/v1/node.pb.go +++ b/integration-tests/deployment/jd/node/v1/node.pb.go @@ -817,7 +817,7 @@ func (x *GetNodeResponse) GetNode() *Node { // * // ListNodesRequest is the request object for the ListNodes method. // -// Provide a filter to return a subset of data. NodesByPeerID can be filtered by: +// Provide a filter to return a subset of data. Nodes can be filtered by: // - ids - A list of node ids. // - archived - The archived state of the node. // - selectors - A list of selectors to filter nodes by their labels. diff --git a/integration-tests/go.mod b/integration-tests/go.mod index 68eb1ec7e48..b435c1b9051 100644 --- a/integration-tests/go.mod +++ b/integration-tests/go.mod @@ -39,7 +39,7 @@ require ( github.com/smartcontractkit/ccip-owner-contracts v0.0.0-20240919155713-f4bf4ae0b9c6 github.com/smartcontractkit/chain-selectors v1.0.23 github.com/smartcontractkit/chainlink-automation v1.0.4 - github.com/smartcontractkit/chainlink-ccip v0.0.0-20240924115754-8858b0423283 + github.com/smartcontractkit/chainlink-ccip v0.0.0-20240925142036-56f243802342 github.com/smartcontractkit/chainlink-common v0.2.3-0.20240925085218-aded1b263ecc github.com/smartcontractkit/chainlink-testing-framework/havoc v1.50.0 github.com/smartcontractkit/chainlink-testing-framework/lib v1.50.9 diff --git a/integration-tests/go.sum b/integration-tests/go.sum index 8a6a0d64934..1f6598256e0 100644 --- a/integration-tests/go.sum +++ b/integration-tests/go.sum @@ -1427,8 +1427,8 @@ github.com/smartcontractkit/chain-selectors v1.0.23 h1:D2Eaex4Cw/O7Lg3tX6WklOqnj github.com/smartcontractkit/chain-selectors v1.0.23/go.mod h1:d4Hi+E1zqjy9HqMkjBE5q1vcG9VGgxf5VxiRHfzi2kE= github.com/smartcontractkit/chainlink-automation v1.0.4 h1:iyW181JjKHLNMnDleI8umfIfVVlwC7+n5izbLSFgjw8= github.com/smartcontractkit/chainlink-automation v1.0.4/go.mod h1:u4NbPZKJ5XiayfKHD/v3z3iflQWqvtdhj13jVZXj/cM= -github.com/smartcontractkit/chainlink-ccip v0.0.0-20240924115754-8858b0423283 h1:f0vdqcOL9kJZwfmWE76roIyEuiZx/R82js0IfXNAvXg= -github.com/smartcontractkit/chainlink-ccip v0.0.0-20240924115754-8858b0423283/go.mod h1:KP82vFCqm+M1G1t6Vos5CewGUGYJkxxCEdxnta4uLlE= +github.com/smartcontractkit/chainlink-ccip v0.0.0-20240925142036-56f243802342 h1:uEgdiVPKiPkwSXpsRgK9gxC2TMpjvE5GXpSPl/C20r0= +github.com/smartcontractkit/chainlink-ccip v0.0.0-20240925142036-56f243802342/go.mod h1:VyldDDFSelaLyEXO1M7xVoGTTtlT9apfxh90vIMeOwc= github.com/smartcontractkit/chainlink-common v0.2.3-0.20240925085218-aded1b263ecc h1:ALbyaoRzUSXQ2NhGFKVOyJqO22IB5yQjhjKWbIZGbrI= github.com/smartcontractkit/chainlink-common v0.2.3-0.20240925085218-aded1b263ecc/go.mod h1:F6WUS6N4mP5ScwpwyTyAJc9/vjR+GXbMCRUOVekQi1g= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240911175228-daf2600bb7b7 h1:lTGIOQYLk1Ufn++X/AvZnt6VOcuhste5yp+C157No/Q= diff --git a/integration-tests/load/go.mod b/integration-tests/load/go.mod index 5dbf60f246d..3f7c219144b 100644 --- a/integration-tests/load/go.mod +++ b/integration-tests/load/go.mod @@ -32,6 +32,7 @@ require ( github.com/andybalholm/brotli v1.1.0 // indirect github.com/bytecodealliance/wasmtime-go/v23 v23.0.0 // indirect github.com/smartcontractkit/chainlink-automation v1.0.4 // indirect + github.com/smartcontractkit/chainlink-ccip v0.0.0-20240925142036-56f243802342 // indirect github.com/smartcontractkit/libocr v0.0.0-20240717100443-f6226e09bee7 // indirect ) @@ -388,7 +389,6 @@ require ( github.com/shopspring/decimal v1.4.0 // indirect github.com/sirupsen/logrus v1.9.3 // indirect github.com/smartcontractkit/chain-selectors v1.0.23 // indirect - github.com/smartcontractkit/chainlink-ccip v0.0.0-20240924115754-8858b0423283 // indirect github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240911175228-daf2600bb7b7 // indirect github.com/smartcontractkit/chainlink-data-streams v0.0.0-20240916152957-433914114bd2 // indirect github.com/smartcontractkit/chainlink-feeds v0.0.0-20240910155501-42f20443189f // indirect diff --git a/integration-tests/load/go.sum b/integration-tests/load/go.sum index 155a513bb4a..15a90f4d7b0 100644 --- a/integration-tests/load/go.sum +++ b/integration-tests/load/go.sum @@ -1401,8 +1401,8 @@ github.com/smartcontractkit/chain-selectors v1.0.23 h1:D2Eaex4Cw/O7Lg3tX6WklOqnj github.com/smartcontractkit/chain-selectors v1.0.23/go.mod h1:d4Hi+E1zqjy9HqMkjBE5q1vcG9VGgxf5VxiRHfzi2kE= github.com/smartcontractkit/chainlink-automation v1.0.4 h1:iyW181JjKHLNMnDleI8umfIfVVlwC7+n5izbLSFgjw8= github.com/smartcontractkit/chainlink-automation v1.0.4/go.mod h1:u4NbPZKJ5XiayfKHD/v3z3iflQWqvtdhj13jVZXj/cM= -github.com/smartcontractkit/chainlink-ccip v0.0.0-20240924115754-8858b0423283 h1:f0vdqcOL9kJZwfmWE76roIyEuiZx/R82js0IfXNAvXg= -github.com/smartcontractkit/chainlink-ccip v0.0.0-20240924115754-8858b0423283/go.mod h1:KP82vFCqm+M1G1t6Vos5CewGUGYJkxxCEdxnta4uLlE= +github.com/smartcontractkit/chainlink-ccip v0.0.0-20240925142036-56f243802342 h1:uEgdiVPKiPkwSXpsRgK9gxC2TMpjvE5GXpSPl/C20r0= +github.com/smartcontractkit/chainlink-ccip v0.0.0-20240925142036-56f243802342/go.mod h1:VyldDDFSelaLyEXO1M7xVoGTTtlT9apfxh90vIMeOwc= github.com/smartcontractkit/chainlink-common v0.2.3-0.20240925085218-aded1b263ecc h1:ALbyaoRzUSXQ2NhGFKVOyJqO22IB5yQjhjKWbIZGbrI= github.com/smartcontractkit/chainlink-common v0.2.3-0.20240925085218-aded1b263ecc/go.mod h1:F6WUS6N4mP5ScwpwyTyAJc9/vjR+GXbMCRUOVekQi1g= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240911175228-daf2600bb7b7 h1:lTGIOQYLk1Ufn++X/AvZnt6VOcuhste5yp+C157No/Q= diff --git a/integration-tests/smoke/ccip_test.go b/integration-tests/smoke/ccip_test.go index 759e8eac1ec..02c8435c222 100644 --- a/integration-tests/smoke/ccip_test.go +++ b/integration-tests/smoke/ccip_test.go @@ -6,6 +6,9 @@ import ( "github.com/stretchr/testify/require" + "github.com/smartcontractkit/chainlink-ccip/pluginconfig" + cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccipocr3" + "github.com/smartcontractkit/chainlink-testing-framework/lib/utils/testcontext" ccipdeployment "github.com/smartcontractkit/chainlink/integration-tests/deployment/ccip" @@ -19,14 +22,25 @@ func Test0002_InitialDeployOnLocal(t *testing.T) { ctx := ccipdeployment.Context(t) tenv := ccipdeployment.NewDeployedLocalDevEnvironment(t, lggr) e := tenv.Env - nodes := tenv.Nodes + don := tenv.DON state, err := ccipdeployment.LoadOnchainState(tenv.Env, tenv.Ab) require.NoError(t, err) + feeds := state.Chains[tenv.FeedChainSel].USDFeeds + tokenConfig := ccipdeployment.NewTokenConfig() + tokenConfig.UpsertTokenInfo(ccipdeployment.LinkSymbol, + pluginconfig.TokenInfo{ + AggregatorAddress: feeds[ccipdeployment.LinkSymbol].Address().String(), + Decimals: ccipdeployment.LinkDecimals, + DeviationPPB: cciptypes.NewBigIntFromInt64(1e9), + }, + ) // Apply migration output, err := changeset.Apply0002(tenv.Env, ccipdeployment.DeployCCIPContractConfig{ HomeChainSel: tenv.HomeChainSel, + FeedChainSel: tenv.FeedChainSel, + TokenConfig: tokenConfig, ChainsToDeploy: tenv.Env.AllChainSelectors(), // Capreg/config already exist. CCIPOnChainState: state, @@ -53,7 +67,7 @@ func Test0002_InitialDeployOnLocal(t *testing.T) { } // Accept all the jobs for this node. - for _, n := range nodes { + for _, n := range don.Nodes { jobsToAccept, exists := nodeIdToJobIds[n.NodeId] require.True(t, exists, "node %s has no jobs to accept", n.NodeId) for i, jobID := range jobsToAccept { @@ -85,6 +99,14 @@ func Test0002_InitialDeployOnLocal(t *testing.T) { // Wait for all commit reports to land. ccipdeployment.ConfirmCommitForAllWithExpectedSeqNums(t, e, state, expectedSeqNum, startBlocks) + // After commit is reported on all chains, token prices should be updated in FeeQuoter. + for dest := range e.Chains { + linkAddress := state.Chains[dest].LinkToken.Address() + feeQuoter := state.Chains[dest].FeeQuoter + timestampedPrice, err := feeQuoter.GetTokenPrice(nil, linkAddress) + require.NoError(t, err) + require.Equal(t, ccipdeployment.MockLinkPrice, timestampedPrice.Value) + } // Wait for all exec reports to land ccipdeployment.ConfirmExecWithSeqNrForAll(t, e, state, expectedSeqNum, startBlocks) } diff --git a/integration-tests/testconfig/ccip/ccip.toml b/integration-tests/testconfig/ccip/ccip.toml index 3a27d0cd54d..5ccda6ab4e3 100644 --- a/integration-tests/testconfig/ccip/ccip.toml +++ b/integration-tests/testconfig/ccip/ccip.toml @@ -89,8 +89,17 @@ DeltaDial = '500ms' DeltaReconcile = '5s' """ +CommonChainConfigTOML = """ +LogPollInterval = '500ms' +[Transactions] +ForwardersEnabled = false +[GasEstimator] +LimitDefault = 5000000 +""" + [CCIP] HomeChainSelector = '12922642891491394802' # for chain-2337 +FeedChainSelector = '3379446385462418246' # for chain-1337 [CCIP.CLNode] NoOfPluginNodes = 4 @@ -120,9 +129,6 @@ addresses_to_fund = [ "0x70997970C51812dc3A010C7d01b50e0d17dc79C8", ] -[CCIP.PrivateEthereumNetworks.SIMULATED_1.EthereumChainConfig.HardForkEpochs] -# eth2-only, epoch at which chain will upgrade do Dencun or Deneb/Cancun (1 is minimum) -Deneb = 500 #[CCIP.Env.PrivateEthereumNetworks.SIMULATED_1.CustomDockerImages] # custom docker image that will be used for execution layer client. It has to be one of: hyperledger/besu, nethermind/nethermind, thorax/erigon or ethereum/client-go. @@ -145,5 +151,6 @@ addresses_to_fund = [ "0x70997970C51812dc3A010C7d01b50e0d17dc79C8", ] -[CCIP.PrivateEthereumNetworks.SIMULATED_2.EthereumChainConfig.HardForkEpochs] -Deneb = 500 \ No newline at end of file +[Seth] +# Seth specific configuration, no need for generating ephemeral addresses for ccip-tests. +ephemeral_addresses_number = 0 \ No newline at end of file diff --git a/integration-tests/testconfig/ccip/config.go b/integration-tests/testconfig/ccip/config.go index b9d969fed1f..1b11d246a30 100644 --- a/integration-tests/testconfig/ccip/config.go +++ b/integration-tests/testconfig/ccip/config.go @@ -1,9 +1,13 @@ package ccip import ( + "fmt" "strconv" "github.com/AlekSi/pointer" + chainselectors "github.com/smartcontractkit/chain-selectors" + + "github.com/smartcontractkit/chainlink-testing-framework/lib/blockchain" ctfconfig "github.com/smartcontractkit/chainlink-testing-framework/lib/config" @@ -19,11 +23,17 @@ const ( DEFAULT_DB_VERSION = "14.1" ) +var ( + ErrInvalidHomeChainSelector = fmt.Errorf("invalid home chain selector") + ErrInvalidFeedChainSelector = fmt.Errorf("invalid feed chain selector") +) + type Config struct { PrivateEthereumNetworks map[string]*ctfconfig.EthereumNetworkConfig `toml:",omitempty"` CLNode *NodeConfig `toml:",omitempty"` JobDistributorConfig JDConfig `toml:",omitempty"` HomeChainSelector *string `toml:",omitempty"` + FeedChainSelector *string `toml:",omitempty"` } type NodeConfig struct { @@ -94,6 +104,45 @@ func (o *Config) GetJDDBVersion() string { return dbversion } -func (o *Config) GetHomeChainSelector() (uint64, error) { - return strconv.ParseUint(pointer.GetString(o.HomeChainSelector), 10, 64) +func (o *Config) GetHomeChainSelector(evmNetworks []blockchain.EVMNetwork) (uint64, error) { + homeChainSelector, err := strconv.ParseUint(pointer.GetString(o.HomeChainSelector), 10, 64) + if err != nil { + return 0, err + } + isValid, err := IsSelectorValid(homeChainSelector, evmNetworks) + if err != nil { + return 0, err + } + if !isValid { + return 0, ErrInvalidHomeChainSelector + } + return homeChainSelector, nil +} + +func (o *Config) GetFeedChainSelector(evmNetworks []blockchain.EVMNetwork) (uint64, error) { + feedChainSelector, err := strconv.ParseUint(pointer.GetString(o.FeedChainSelector), 10, 64) + if err != nil { + return 0, err + } + isValid, err := IsSelectorValid(feedChainSelector, evmNetworks) + if err != nil { + return 0, err + } + if !isValid { + return 0, ErrInvalidFeedChainSelector + } + return feedChainSelector, nil +} + +func IsSelectorValid(selector uint64, evmNetworks []blockchain.EVMNetwork) (bool, error) { + chainId, err := chainselectors.ChainIdFromSelector(selector) + if err != nil { + return false, err + } + for _, net := range evmNetworks { + if net.ChainID == int64(chainId) { + return true, nil + } + } + return false, nil }