From 9d8d9f48b92cab72de51e4484cc7b0833b1ccf6b Mon Sep 17 00:00:00 2001 From: Anindita Ghosh <88458927+AnieeG@users.noreply.github.com> Date: Tue, 10 Dec 2024 09:14:55 -0800 Subject: [PATCH] Ccip-4333 Handle all test setups with unified interface for memory and docker tests (#15581) * updates * use common ones * update test * go mod * fix rmn test * fix test * fix again * fix test * more fix * comment override * review comments * fix * updates --- .github/e2e-tests.yml | 11 + .../ccip/changeset/accept_ownership_test.go | 12 +- .../changeset/cs_active_candidate_test.go | 13 +- .../ccip/changeset/cs_add_chain_test.go | 11 +- deployment/ccip/changeset/cs_add_lane_test.go | 14 +- .../ccip/changeset/cs_deploy_chain_test.go | 7 +- .../ccip/changeset/cs_initial_add_chain.go | 11 + .../changeset/cs_initial_add_chain_test.go | 30 ++ .../changeset/cs_update_rmn_config_test.go | 8 +- deployment/ccip/changeset/state_test.go | 11 +- deployment/ccip/changeset/test_assertions.go | 3 +- deployment/ccip/changeset/test_environment.go | 443 ++++++++++++++++++ deployment/ccip/changeset/test_helpers.go | 274 +---------- deployment/ccip/changeset/view_test.go | 11 +- deployment/go.mod | 2 +- deployment/helpers.go | 2 +- .../contracts/ccipreader_test.go | 30 +- .../smoke/ccip/ccip_batching_test.go | 19 +- .../smoke/ccip/ccip_fee_boosting_test.go | 21 +- .../smoke/ccip/ccip_fees_test.go | 11 +- .../smoke/ccip/ccip_gas_price_updates_test.go | 11 +- .../ccip/ccip_message_limitations_test.go | 4 +- .../smoke/ccip/ccip_messaging_test.go | 9 +- .../smoke/ccip/ccip_ooo_execution_test.go | 19 +- integration-tests/smoke/ccip/ccip_rmn_test.go | 7 +- .../ccip/ccip_token_price_updates_test.go | 10 +- .../smoke/ccip/ccip_token_transfer_test.go | 14 +- .../smoke/ccip/ccip_usdc_test.go | 19 +- .../testsetups/ccip/test_helpers.go | 310 ++++-------- 29 files changed, 681 insertions(+), 666 deletions(-) create mode 100644 deployment/ccip/changeset/cs_initial_add_chain_test.go create mode 100644 deployment/ccip/changeset/test_environment.go diff --git a/.github/e2e-tests.yml b/.github/e2e-tests.yml index ebe5b62a709..f261cbe107d 100644 --- a/.github/e2e-tests.yml +++ b/.github/e2e-tests.yml @@ -947,6 +947,7 @@ runner-test-matrix: test_env_vars: E2E_TEST_SELECTED_NETWORK: SIMULATED_1,SIMULATED_2 E2E_JD_VERSION: 0.6.0 + CCIP_V16_TEST_ENV: docker - id: smoke/ccip/ccip_token_price_updates_test.go:* path: integration-tests/smoke/ccip/ccip_token_price_updates_test.go @@ -960,6 +961,7 @@ runner-test-matrix: test_env_vars: E2E_TEST_SELECTED_NETWORK: SIMULATED_1,SIMULATED_2 E2E_JD_VERSION: 0.6.0 + CCIP_V16_TEST_ENV: docker - id: smoke/ccip/ccip_gas_price_updates_test.go:* path: integration-tests/smoke/ccip/ccip_gas_price_updates_test.go @@ -973,6 +975,7 @@ runner-test-matrix: test_env_vars: E2E_TEST_SELECTED_NETWORK: SIMULATED_1,SIMULATED_2 E2E_JD_VERSION: 0.6.0 + CCIP_V16_TEST_ENV: docker - id: smoke/ccip/ccip_rmn_test.go:^TestRMN_TwoMessagesOnTwoLanesIncludingBatching$ path: integration-tests/smoke/ccip/ccip_rmn_test.go @@ -988,6 +991,7 @@ runner-test-matrix: E2E_JD_VERSION: 0.6.0 E2E_RMN_RAGEPROXY_VERSION: master-f461a9e E2E_RMN_AFN2PROXY_VERSION: master-f461a9e + CCIP_V16_TEST_ENV: docker - id: smoke/ccip/ccip_rmn_test.go:^TestRMN_MultipleMessagesOnOneLaneNoWaitForExec$ path: integration-tests/smoke/ccip/ccip_rmn_test.go @@ -1003,6 +1007,7 @@ runner-test-matrix: E2E_JD_VERSION: 0.6.0 E2E_RMN_RAGEPROXY_VERSION: master-f461a9e E2E_RMN_AFN2PROXY_VERSION: master-f461a9e + CCIP_V16_TEST_ENV: docker - id: smoke/ccip/ccip_rmn_test.go:^TestRMN_NotEnoughObservers$ path: integration-tests/smoke/ccip/ccip_rmn_test.go @@ -1018,6 +1023,7 @@ runner-test-matrix: E2E_JD_VERSION: 0.6.0 E2E_RMN_RAGEPROXY_VERSION: master-f461a9e E2E_RMN_AFN2PROXY_VERSION: master-f461a9e + CCIP_V16_TEST_ENV: docker - id: smoke/ccip/ccip_rmn_test.go:^TestRMN_DifferentSigners$ path: integration-tests/smoke/ccip/ccip_rmn_test.go @@ -1033,6 +1039,7 @@ runner-test-matrix: E2E_JD_VERSION: 0.6.0 E2E_RMN_RAGEPROXY_VERSION: master-f461a9e E2E_RMN_AFN2PROXY_VERSION: master-f461a9e + CCIP_V16_TEST_ENV: docker - id: smoke/ccip/ccip_rmn_test.go:^TestRMN_NotEnoughSigners$ path: integration-tests/smoke/ccip/ccip_rmn_test.go @@ -1048,6 +1055,7 @@ runner-test-matrix: E2E_JD_VERSION: 0.6.0 E2E_RMN_RAGEPROXY_VERSION: master-f461a9e E2E_RMN_AFN2PROXY_VERSION: master-f461a9e + CCIP_V16_TEST_ENV: docker - id: smoke/ccip/ccip_rmn_test.go:^TestRMN_DifferentRmnNodesForDifferentChains$ path: integration-tests/smoke/ccip/ccip_rmn_test.go @@ -1063,6 +1071,7 @@ runner-test-matrix: E2E_JD_VERSION: 0.6.0 E2E_RMN_RAGEPROXY_VERSION: master-f461a9e E2E_RMN_AFN2PROXY_VERSION: master-f461a9e + CCIP_V16_TEST_ENV: docker - id: smoke/ccip/ccip_rmn_test.go:^TestRMN_TwoMessagesOneSourceChainCursed$ path: integration-tests/smoke/ccip/ccip_rmn_test.go @@ -1078,6 +1087,7 @@ runner-test-matrix: E2E_JD_VERSION: 0.6.0 E2E_RMN_RAGEPROXY_VERSION: master-f461a9e E2E_RMN_AFN2PROXY_VERSION: master-f461a9e + CCIP_V16_TEST_ENV: docker - id: smoke/ccip/ccip_rmn_test.go:^TestRMN_GlobalCurseTwoMessagesOnTwoLanes$ path: integration-tests/smoke/ccip/ccip_rmn_test.go @@ -1093,6 +1103,7 @@ runner-test-matrix: E2E_JD_VERSION: 0.6.0 E2E_RMN_RAGEPROXY_VERSION: master-f461a9e E2E_RMN_AFN2PROXY_VERSION: master-f461a9e + CCIP_V16_TEST_ENV: docker # END: CCIPv1.6 tests diff --git a/deployment/ccip/changeset/accept_ownership_test.go b/deployment/ccip/changeset/accept_ownership_test.go index d3a641a2aaf..5580b31a85a 100644 --- a/deployment/ccip/changeset/accept_ownership_test.go +++ b/deployment/ccip/changeset/accept_ownership_test.go @@ -5,22 +5,14 @@ import ( "github.com/ethereum/go-ethereum/common" - commonchangeset "github.com/smartcontractkit/chainlink/deployment/common/changeset" - "github.com/smartcontractkit/chainlink/deployment/environment/memory" - "github.com/stretchr/testify/require" "golang.org/x/exp/maps" - "github.com/smartcontractkit/chainlink/v2/core/logger" + commonchangeset "github.com/smartcontractkit/chainlink/deployment/common/changeset" ) func Test_NewAcceptOwnershipChangeset(t *testing.T) { - e := NewMemoryEnvironmentWithJobsAndContracts(t, logger.TestLogger(t), memory.MemoryEnvironmentConfig{ - Chains: 2, - NumOfUsersPerChain: 1, - Nodes: 4, - Bootstraps: 1, - }, &TestConfigs{}) + e := NewMemoryEnvironment(t) state, err := LoadOnchainState(e.Env) require.NoError(t, err) diff --git a/deployment/ccip/changeset/cs_active_candidate_test.go b/deployment/ccip/changeset/cs_active_candidate_test.go index 4c8706472fe..e22bc278a61 100644 --- a/deployment/ccip/changeset/cs_active_candidate_test.go +++ b/deployment/ccip/changeset/cs_active_candidate_test.go @@ -12,7 +12,6 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/lib/utils/testcontext" "github.com/smartcontractkit/chainlink/deployment/ccip/changeset/internal" - "github.com/smartcontractkit/chainlink/deployment/environment/memory" cctypes "github.com/smartcontractkit/chainlink/v2/core/capabilities/ccip/types" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/router" @@ -22,20 +21,14 @@ import ( commonchangeset "github.com/smartcontractkit/chainlink/deployment/common/changeset" "github.com/smartcontractkit/chainlink/deployment/common/proposalutils" - - "github.com/smartcontractkit/chainlink/v2/core/logger" ) func TestActiveCandidate(t *testing.T) { t.Skipf("to be enabled after latest cl-ccip is compatible") - lggr := logger.TestLogger(t) - tenv := NewMemoryEnvironmentWithJobsAndContracts(t, lggr, memory.MemoryEnvironmentConfig{ - Chains: 3, - NumOfUsersPerChain: 1, - Nodes: 5, - Bootstraps: 1, - }, nil) + tenv := NewMemoryEnvironment(t, + WithChains(3), + WithNodes(5)) e := tenv.Env state, err := LoadOnchainState(tenv.Env) require.NoError(t, err) diff --git a/deployment/ccip/changeset/cs_add_chain_test.go b/deployment/ccip/changeset/cs_add_chain_test.go index 3a9425dd3a9..84a8ad817e1 100644 --- a/deployment/ccip/changeset/cs_add_chain_test.go +++ b/deployment/ccip/changeset/cs_add_chain_test.go @@ -8,7 +8,6 @@ import ( "github.com/smartcontractkit/chainlink/deployment/ccip/changeset/internal" commonchangeset "github.com/smartcontractkit/chainlink/deployment/common/changeset" commontypes "github.com/smartcontractkit/chainlink/deployment/common/types" - "github.com/smartcontractkit/chainlink/deployment/environment/memory" "github.com/smartcontractkit/chainlink/v2/core/capabilities/ccip/types" "github.com/ethereum/go-ethereum/common" @@ -32,12 +31,10 @@ import ( func TestAddChainInbound(t *testing.T) { // 4 chains where the 4th is added after initial deployment. - e := NewMemoryEnvironmentWithJobs(t, logger.TestLogger(t), memory.MemoryEnvironmentConfig{ - Chains: 4, - NumOfUsersPerChain: 1, - Nodes: 4, - Bootstraps: 1, - }) + e := NewMemoryEnvironment(t, + WithChains(4), + WithJobsOnly(), + ) state, err := LoadOnchainState(e.Env) require.NoError(t, err) // Take first non-home chain as the new chain. diff --git a/deployment/ccip/changeset/cs_add_lane_test.go b/deployment/ccip/changeset/cs_add_lane_test.go index fbceeaa8472..7f1374a1725 100644 --- a/deployment/ccip/changeset/cs_add_lane_test.go +++ b/deployment/ccip/changeset/cs_add_lane_test.go @@ -11,18 +11,12 @@ import ( "github.com/smartcontractkit/chainlink-testing-framework/lib/utils/testcontext" "github.com/smartcontractkit/chainlink/deployment" - "github.com/smartcontractkit/chainlink/deployment/environment/memory" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/offramp" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/router" - "github.com/smartcontractkit/chainlink/v2/core/logger" ) func TestAddLanesWithTestRouter(t *testing.T) { - e := NewMemoryEnvironmentWithJobsAndContracts(t, logger.TestLogger(t), memory.MemoryEnvironmentConfig{ - Chains: 2, - Nodes: 4, - Bootstraps: 1, - }, nil) + e := NewMemoryEnvironment(t) // Here we have CR + nodes set up, but no CCIP contracts deployed. state, err := LoadOnchainState(e.Env) require.NoError(t, err) @@ -72,11 +66,7 @@ func TestAddLane(t *testing.T) { t.Parallel() // We add more chains to the chainlink nodes than the number of chains where CCIP is deployed. - e := NewMemoryEnvironmentWithJobsAndContracts(t, logger.TestLogger(t), memory.MemoryEnvironmentConfig{ - Chains: 2, - Nodes: 4, - Bootstraps: 1, - }, nil) + e := NewMemoryEnvironment(t) // Here we have CR + nodes set up, but no CCIP contracts deployed. state, err := LoadOnchainState(e.Env) require.NoError(t, err) diff --git a/deployment/ccip/changeset/cs_deploy_chain_test.go b/deployment/ccip/changeset/cs_deploy_chain_test.go index 646575dcaa4..fbf9c881138 100644 --- a/deployment/ccip/changeset/cs_deploy_chain_test.go +++ b/deployment/ccip/changeset/cs_deploy_chain_test.go @@ -98,12 +98,7 @@ func TestDeployChainContractsChangeset(t *testing.T) { } func TestDeployCCIPContracts(t *testing.T) { - lggr := logger.TestLogger(t) - e := NewMemoryEnvironmentWithJobsAndContracts(t, lggr, memory.MemoryEnvironmentConfig{ - Chains: 2, - Nodes: 4, - Bootstraps: 1, - }, nil) + e := NewMemoryEnvironment(t) // Deploy all the CCIP contracts. state, err := LoadOnchainState(e.Env) require.NoError(t, err) diff --git a/deployment/ccip/changeset/cs_initial_add_chain.go b/deployment/ccip/changeset/cs_initial_add_chain.go index 13aee106e5a..65c13123537 100644 --- a/deployment/ccip/changeset/cs_initial_add_chain.go +++ b/deployment/ccip/changeset/cs_initial_add_chain.go @@ -10,6 +10,7 @@ import ( "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" + "github.com/imdario/mergo" "github.com/smartcontractkit/ccip-owner-contracts/pkg/proposal/timelock" "github.com/smartcontractkit/chainlink-ccip/chainconfig" @@ -59,6 +60,16 @@ type CCIPOCRParams struct { ExecuteOffChainConfig pluginconfig.ExecuteOffchainConfig } +// Override overrides non-empty dst CCIPOCRParams attributes with non-empty src CCIPOCRParams attributes values +// and returns the updated CCIPOCRParams. +func (c CCIPOCRParams) Override(overrides CCIPOCRParams) (CCIPOCRParams, error) { + err := mergo.Merge(&c, &overrides, mergo.WithOverride) + if err != nil { + return CCIPOCRParams{}, err + } + return c, nil +} + func (c CCIPOCRParams) Validate() error { if err := c.OCRParameters.Validate(); err != nil { return fmt.Errorf("invalid OCR parameters: %w", err) diff --git a/deployment/ccip/changeset/cs_initial_add_chain_test.go b/deployment/ccip/changeset/cs_initial_add_chain_test.go new file mode 100644 index 00000000000..77d9c1a4765 --- /dev/null +++ b/deployment/ccip/changeset/cs_initial_add_chain_test.go @@ -0,0 +1,30 @@ +package changeset + +import ( + "testing" + "time" + + chainselectors "github.com/smartcontractkit/chain-selectors" + "github.com/smartcontractkit/chainlink-ccip/pluginconfig" + "github.com/smartcontractkit/chainlink-common/pkg/config" + "github.com/stretchr/testify/require" +) + +func TestOverrideCCIPParams(t *testing.T) { + params := DefaultOCRParams(chainselectors.ETHEREUM_TESTNET_SEPOLIA.Selector, nil, nil) + overrides := CCIPOCRParams{ + ExecuteOffChainConfig: pluginconfig.ExecuteOffchainConfig{ + RelativeBoostPerWaitHour: 10, + }, + CommitOffChainConfig: pluginconfig.CommitOffchainConfig{ + TokenPriceBatchWriteFrequency: *config.MustNewDuration(1_000_000 * time.Hour), + RemoteGasPriceBatchWriteFrequency: *config.MustNewDuration(1_000_000 * time.Hour), + }, + } + newParams, err := params.Override(overrides) + require.NoError(t, err) + require.Equal(t, overrides.ExecuteOffChainConfig.RelativeBoostPerWaitHour, newParams.ExecuteOffChainConfig.RelativeBoostPerWaitHour) + require.Equal(t, overrides.CommitOffChainConfig.TokenPriceBatchWriteFrequency, newParams.CommitOffChainConfig.TokenPriceBatchWriteFrequency) + require.Equal(t, overrides.CommitOffChainConfig.RemoteGasPriceBatchWriteFrequency, newParams.CommitOffChainConfig.RemoteGasPriceBatchWriteFrequency) + require.Equal(t, params.OCRParameters, newParams.OCRParameters) +} diff --git a/deployment/ccip/changeset/cs_update_rmn_config_test.go b/deployment/ccip/changeset/cs_update_rmn_config_test.go index deae3e2e771..e22b85cdf81 100644 --- a/deployment/ccip/changeset/cs_update_rmn_config_test.go +++ b/deployment/ccip/changeset/cs_update_rmn_config_test.go @@ -8,10 +8,8 @@ import ( "github.com/smartcontractkit/chainlink/deployment" commonchangeset "github.com/smartcontractkit/chainlink/deployment/common/changeset" - "github.com/smartcontractkit/chainlink/deployment/environment/memory" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/rmn_home" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/rmn_remote" - "github.com/smartcontractkit/chainlink/v2/core/logger" ) type updateRMNConfigTestCase struct { @@ -40,11 +38,7 @@ func TestUpdateRMNConfig(t *testing.T) { } func updateRMNConfig(t *testing.T, tc updateRMNConfigTestCase) { - e := NewMemoryEnvironmentWithJobsAndContracts(t, logger.TestLogger(t), memory.MemoryEnvironmentConfig{ - Chains: 2, - Nodes: 4, - Bootstraps: 1, - }, nil) + e := NewMemoryEnvironment(t) state, err := LoadOnchainState(e.Env) require.NoError(t, err) diff --git a/deployment/ccip/changeset/state_test.go b/deployment/ccip/changeset/state_test.go index 6e679c265dc..3587332fff2 100644 --- a/deployment/ccip/changeset/state_test.go +++ b/deployment/ccip/changeset/state_test.go @@ -4,19 +4,10 @@ import ( "testing" "github.com/stretchr/testify/require" - - "github.com/smartcontractkit/chainlink/deployment/environment/memory" - "github.com/smartcontractkit/chainlink/v2/core/logger" ) func TestSmokeState(t *testing.T) { - lggr := logger.TestLogger(t) - tenv := NewMemoryEnvironmentWithJobsAndContracts(t, lggr, memory.MemoryEnvironmentConfig{ - Chains: 3, - Nodes: 4, - Bootstraps: 1, - NumOfUsersPerChain: 1, - }, nil) + tenv := NewMemoryEnvironment(t, WithChains(3)) state, err := LoadOnchainState(tenv.Env) require.NoError(t, err) _, err = state.View(tenv.Env.AllChainSelectors()) diff --git a/deployment/ccip/changeset/test_assertions.go b/deployment/ccip/changeset/test_assertions.go index a7d3ecf61f8..c0b510acc07 100644 --- a/deployment/ccip/changeset/test_assertions.go +++ b/deployment/ccip/changeset/test_assertions.go @@ -16,6 +16,7 @@ import ( "github.com/smartcontractkit/chainlink-ccip/pkg/types/ccipocr3" commonutils "github.com/smartcontractkit/chainlink-common/pkg/utils" "github.com/smartcontractkit/chainlink-common/pkg/utils/tests" + "github.com/smartcontractkit/chainlink/deployment/environment/memory" "github.com/smartcontractkit/chainlink/deployment" @@ -598,7 +599,7 @@ func RequireConsistently(t *testing.T, condition func() bool, duration time.Dura } } -func SeqNumberRageToSlice(seqRanges map[SourceDestPair]ccipocr3.SeqNumRange) map[SourceDestPair][]uint64 { +func SeqNumberRangeToSlice(seqRanges map[SourceDestPair]ccipocr3.SeqNumRange) map[SourceDestPair][]uint64 { flatten := make(map[SourceDestPair][]uint64) for srcDst, seqRange := range seqRanges { diff --git a/deployment/ccip/changeset/test_environment.go b/deployment/ccip/changeset/test_environment.go new file mode 100644 index 00000000000..ab012a56174 --- /dev/null +++ b/deployment/ccip/changeset/test_environment.go @@ -0,0 +1,443 @@ +package changeset + +import ( + "context" + "fmt" + "math/big" + "os" + "testing" + "time" + + "github.com/ethereum/go-ethereum/accounts/abi/bind" + cciptypes "github.com/smartcontractkit/chainlink-ccip/pkg/types/ccipocr3" + "github.com/smartcontractkit/chainlink-ccip/pluginconfig" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" + "github.com/smartcontractkit/chainlink-common/pkg/logger" + jobv1 "github.com/smartcontractkit/chainlink-protos/job-distributor/v1/job" + "github.com/smartcontractkit/chainlink-testing-framework/lib/utils/testcontext" + "github.com/stretchr/testify/require" + "go.uber.org/zap/zapcore" + + "github.com/smartcontractkit/chainlink/deployment" + commonchangeset "github.com/smartcontractkit/chainlink/deployment/common/changeset" + commontypes "github.com/smartcontractkit/chainlink/deployment/common/types" + "github.com/smartcontractkit/chainlink/deployment/environment/memory" +) + +type EnvType string + +const ( + Memory EnvType = "in-memory" + Docker EnvType = "docker" + ENVTESTTYPE = "CCIP_V16_TEST_ENV" +) + +type TestConfigs struct { + Type EnvType + CreateJob bool + CreateJobAndContracts bool + Chains int + NumOfUsersPerChain int + Nodes int + Bootstraps int + IsUSDC bool + IsUSDCAttestationMissing bool + IsMultiCall3 bool + OCRConfigOverride func(CCIPOCRParams) CCIPOCRParams + RMNEnabled bool + NumOfRMNNodes int + LinkPrice *big.Int + WethPrice *big.Int +} + +func (tc *TestConfigs) Validate() error { + if tc.Chains < 2 { + return fmt.Errorf("chains must be at least 2") + } + if tc.Nodes < 4 { + return fmt.Errorf("nodes must be at least 4") + } + if tc.Bootstraps < 1 { + return fmt.Errorf("bootstraps must be at least 1") + } + if tc.Type == Memory && tc.RMNEnabled { + return fmt.Errorf("cannot run RMN tests in memory mode") + } + return nil +} + +func (tc *TestConfigs) MustSetEnvTypeOrDefault(t *testing.T) { + envType := os.Getenv(ENVTESTTYPE) + if envType == "" || envType == string(Memory) { + tc.Type = Memory + } else if envType == string(Docker) { + tc.Type = Docker + } else { + t.Fatalf("env var CCIP_V16_TEST_ENV must be either %s or %s, defaults to %s if unset, got: %s", Memory, Docker, Memory, envType) + } +} + +func DefaultTestConfigs() *TestConfigs { + return &TestConfigs{ + Chains: 2, + NumOfUsersPerChain: 1, + Nodes: 4, + Bootstraps: 1, + LinkPrice: MockLinkPrice, + WethPrice: MockWethPrice, + CreateJobAndContracts: true, + } +} + +type TestOps func(testCfg *TestConfigs) + +func WithMultiCall3() TestOps { + return func(testCfg *TestConfigs) { + testCfg.IsMultiCall3 = true + } +} + +func WithJobsOnly() TestOps { + return func(testCfg *TestConfigs) { + testCfg.CreateJobAndContracts = false + testCfg.CreateJob = true + } +} + +func WithNoJobsAndContracts() TestOps { + return func(testCfg *TestConfigs) { + testCfg.CreateJobAndContracts = false + testCfg.CreateJob = false + } +} + +func WithRMNEnabled(numOfNode int) TestOps { + return func(testCfg *TestConfigs) { + testCfg.RMNEnabled = true + testCfg.NumOfRMNNodes = numOfNode + } +} + +func WithOCRConfigOverride(override func(CCIPOCRParams) CCIPOCRParams) TestOps { + return func(testCfg *TestConfigs) { + testCfg.OCRConfigOverride = override + } +} + +func WithUSDCAttestationMissing() TestOps { + return func(testCfg *TestConfigs) { + testCfg.IsUSDCAttestationMissing = true + } +} + +func WithUSDC() TestOps { + return func(testCfg *TestConfigs) { + testCfg.IsUSDC = true + } +} + +func WithChains(numChains int) TestOps { + return func(testCfg *TestConfigs) { + testCfg.Chains = numChains + } +} + +func WithUsersPerChain(numUsers int) TestOps { + return func(testCfg *TestConfigs) { + testCfg.NumOfUsersPerChain = numUsers + } +} + +func WithNodes(numNodes int) TestOps { + return func(testCfg *TestConfigs) { + testCfg.Nodes = numNodes + } +} + +func WithBootstraps(numBootstraps int) TestOps { + return func(testCfg *TestConfigs) { + testCfg.Bootstraps = numBootstraps + } +} + +type TestEnvironment interface { + SetupJobs(t *testing.T) + StartNodes(t *testing.T, tc *TestConfigs, crConfig deployment.CapabilityRegistryConfig) + StartChains(t *testing.T, tc *TestConfigs) + DeployedEnvironment() DeployedEnv + MockUSDCAttestationServer(t *testing.T, isUSDCAttestationMissing bool) string +} + +type DeployedEnv struct { + Env deployment.Environment + HomeChainSel uint64 + FeedChainSel uint64 + ReplayBlocks map[uint64]uint64 + Users map[uint64][]*bind.TransactOpts +} + +func (d *DeployedEnv) SetupJobs(t *testing.T) { + ctx := testcontext.Get(t) + out, err := CCIPCapabilityJobspec(d.Env, struct{}{}) + require.NoError(t, err) + for nodeID, jobs := range out.JobSpecs { + for _, job := range jobs { + // Note these auto-accept + _, err := d.Env.Offchain.ProposeJob(ctx, + &jobv1.ProposeJobRequest{ + NodeId: nodeID, + Spec: job, + }) + require.NoError(t, err) + } + } + // Wait for plugins to register filters? + // TODO: Investigate how to avoid. + time.Sleep(30 * time.Second) + ReplayLogs(t, d.Env.Offchain, d.ReplayBlocks) +} + +type MemoryEnvironment struct { + DeployedEnv + chains map[uint64]deployment.Chain +} + +func (m *MemoryEnvironment) DeployedEnvironment() DeployedEnv { + return m.DeployedEnv +} + +func (m *MemoryEnvironment) StartChains(t *testing.T, tc *TestConfigs) { + ctx := testcontext.Get(t) + chains, users := memory.NewMemoryChains(t, tc.Chains, tc.NumOfUsersPerChain) + m.chains = chains + homeChainSel, feedSel := allocateCCIPChainSelectors(chains) + replayBlocks, err := LatestBlocksByChain(ctx, chains) + require.NoError(t, err) + m.DeployedEnv = DeployedEnv{ + Env: deployment.Environment{ + Chains: m.chains, + }, + HomeChainSel: homeChainSel, + FeedChainSel: feedSel, + ReplayBlocks: replayBlocks, + Users: users, + } +} + +func (m *MemoryEnvironment) StartNodes(t *testing.T, tc *TestConfigs, crConfig deployment.CapabilityRegistryConfig) { + require.NotNil(t, m.chains, "start chains first, chains are empty") + require.NotNil(t, m.DeployedEnv, "start chains and initiate deployed env first before starting nodes") + nodes := memory.NewNodes(t, zapcore.InfoLevel, m.chains, tc.Nodes, tc.Bootstraps, crConfig) + ctx := testcontext.Get(t) + lggr := logger.Test(t) + for _, node := range nodes { + require.NoError(t, node.App.Start(ctx)) + t.Cleanup(func() { + require.NoError(t, node.App.Stop()) + }) + } + m.DeployedEnv.Env = memory.NewMemoryEnvironmentFromChainsNodes(func() context.Context { return ctx }, lggr, m.chains, nodes) +} + +func (m *MemoryEnvironment) MockUSDCAttestationServer(t *testing.T, isUSDCAttestationMissing bool) string { + server := mockAttestationResponse(isUSDCAttestationMissing) + endpoint := server.URL + t.Cleanup(func() { + server.Close() + }) + return endpoint +} + +// NewMemoryEnvironment creates an in-memory environment based on the testconfig requested +func NewMemoryEnvironment(t *testing.T, opts ...TestOps) DeployedEnv { + testCfg := DefaultTestConfigs() + for _, opt := range opts { + opt(testCfg) + } + require.NoError(t, testCfg.Validate(), "invalid test config") + env := &MemoryEnvironment{} + if testCfg.CreateJobAndContracts { + return NewEnvironmentWithJobsAndContracts(t, testCfg, env) + } + if testCfg.CreateJob { + return NewEnvironmentWithJobs(t, testCfg, env) + } + return NewEnvironment(t, testCfg, env) +} + +func NewEnvironment(t *testing.T, tc *TestConfigs, tEnv TestEnvironment) DeployedEnv { + lggr := logger.Test(t) + tEnv.StartChains(t, tc) + dEnv := tEnv.DeployedEnvironment() + require.NotEmpty(t, dEnv.FeedChainSel) + require.NotEmpty(t, dEnv.HomeChainSel) + require.NotEmpty(t, dEnv.Env.Chains) + ab := deployment.NewMemoryAddressBook() + crConfig := DeployTestContracts(t, lggr, ab, dEnv.HomeChainSel, dEnv.FeedChainSel, dEnv.Env.Chains, tc.LinkPrice, tc.WethPrice) + tEnv.StartNodes(t, tc, crConfig) + dEnv = tEnv.DeployedEnvironment() + envNodes, err := deployment.NodeInfo(dEnv.Env.NodeIDs, dEnv.Env.Offchain) + require.NoError(t, err) + dEnv.Env.ExistingAddresses = ab + _, err = deployHomeChain(lggr, dEnv.Env, dEnv.Env.ExistingAddresses, dEnv.Env.Chains[dEnv.HomeChainSel], + NewTestRMNStaticConfig(), + NewTestRMNDynamicConfig(), + NewTestNodeOperator(dEnv.Env.Chains[dEnv.HomeChainSel].DeployerKey.From), + map[string][][32]byte{ + "NodeOperator": envNodes.NonBootstraps().PeerIDs(), + }, + ) + require.NoError(t, err) + + return dEnv +} + +func NewEnvironmentWithJobsAndContracts(t *testing.T, tc *TestConfigs, tEnv TestEnvironment) DeployedEnv { + var err error + e := NewEnvironment(t, tc, tEnv) + allChains := e.Env.AllChainSelectors() + mcmsCfg := make(map[uint64]commontypes.MCMSWithTimelockConfig) + + for _, c := range e.Env.AllChainSelectors() { + mcmsCfg[c] = commontypes.MCMSWithTimelockConfig{ + Canceller: commonchangeset.SingleGroupMCMS(t), + Bypasser: commonchangeset.SingleGroupMCMS(t), + Proposer: commonchangeset.SingleGroupMCMS(t), + TimelockMinDelay: big.NewInt(0), + } + } + var ( + usdcChains []uint64 + isMulticall3 bool + ) + if tc != nil { + if tc.IsUSDC { + usdcChains = allChains + } + isMulticall3 = tc.IsMultiCall3 + } + // Need to deploy prerequisites first so that we can form the USDC config + // no proposals to be made, timelock can be passed as nil here + e.Env, err = commonchangeset.ApplyChangesets(t, e.Env, nil, []commonchangeset.ChangesetApplication{ + { + Changeset: commonchangeset.WrapChangeSet(commonchangeset.DeployLinkToken), + Config: allChains, + }, + { + Changeset: commonchangeset.WrapChangeSet(DeployPrerequisites), + Config: DeployPrerequisiteConfig{ + ChainSelectors: allChains, + Opts: []PrerequisiteOpt{ + WithUSDCChains(usdcChains), + WithMulticall3(isMulticall3), + }, + }, + }, + { + Changeset: commonchangeset.WrapChangeSet(commonchangeset.DeployMCMSWithTimelock), + Config: mcmsCfg, + }, + { + Changeset: commonchangeset.WrapChangeSet(DeployChainContracts), + Config: DeployChainContractsConfig{ + ChainSelectors: allChains, + HomeChainSelector: e.HomeChainSel, + }, + }, + }) + require.NoError(t, err) + + state, err := LoadOnchainState(e.Env) + require.NoError(t, err) + // Assert USDC set up as expected. + for _, chain := range usdcChains { + require.NotNil(t, state.Chains[chain].MockUSDCTokenMessenger) + require.NotNil(t, state.Chains[chain].MockUSDCTransmitter) + require.NotNil(t, state.Chains[chain].USDCTokenPool) + } + // Assert link present + require.NotNil(t, state.Chains[e.FeedChainSel].LinkToken) + require.NotNil(t, state.Chains[e.FeedChainSel].Weth9) + + tokenConfig := NewTestTokenConfig(state.Chains[e.FeedChainSel].USDFeeds) + var tokenDataProviders []pluginconfig.TokenDataObserverConfig + if len(usdcChains) > 0 { + endpoint := tEnv.MockUSDCAttestationServer(t, tc.IsUSDCAttestationMissing) + cctpContracts := make(map[cciptypes.ChainSelector]pluginconfig.USDCCCTPTokenConfig) + for _, usdcChain := range usdcChains { + cctpContracts[cciptypes.ChainSelector(usdcChain)] = pluginconfig.USDCCCTPTokenConfig{ + SourcePoolAddress: state.Chains[usdcChain].USDCTokenPool.Address().String(), + SourceMessageTransmitterAddr: state.Chains[usdcChain].MockUSDCTransmitter.Address().String(), + } + } + tokenDataProviders = append(tokenDataProviders, pluginconfig.TokenDataObserverConfig{ + Type: pluginconfig.USDCCCTPHandlerType, + Version: "1.0", + USDCCCTPObserverConfig: &pluginconfig.USDCCCTPObserverConfig{ + Tokens: cctpContracts, + AttestationAPI: endpoint, + AttestationAPITimeout: commonconfig.MustNewDuration(time.Second), + AttestationAPIInterval: commonconfig.MustNewDuration(500 * time.Millisecond), + }}) + } + // Build the per chain config. + chainConfigs := make(map[uint64]CCIPOCRParams) + timelockContractsPerChain := make(map[uint64]*commonchangeset.TimelockExecutionContracts) + for _, chain := range allChains { + timelockContractsPerChain[chain] = &commonchangeset.TimelockExecutionContracts{ + Timelock: state.Chains[chain].Timelock, + CallProxy: state.Chains[chain].CallProxy, + } + tokenInfo := tokenConfig.GetTokenInfo(e.Env.Logger, state.Chains[chain].LinkToken, state.Chains[chain].Weth9) + ocrParams := DefaultOCRParams(e.FeedChainSel, tokenInfo, tokenDataProviders) + if tc.OCRConfigOverride != nil { + ocrParams = tc.OCRConfigOverride(ocrParams) + } + chainConfigs[chain] = ocrParams + } + // Deploy second set of changesets to deploy and configure the CCIP contracts. + e.Env, err = commonchangeset.ApplyChangesets(t, e.Env, timelockContractsPerChain, []commonchangeset.ChangesetApplication{ + { + Changeset: commonchangeset.WrapChangeSet(ConfigureNewChains), + Config: NewChainsConfig{ + HomeChainSel: e.HomeChainSel, + FeedChainSel: e.FeedChainSel, + ChainConfigByChain: chainConfigs, + }, + }, + { + Changeset: commonchangeset.WrapChangeSet(CCIPCapabilityJobspec), + }, + }) + require.NoError(t, err) + + ReplayLogs(t, e.Env.Offchain, e.ReplayBlocks) + + state, err = LoadOnchainState(e.Env) + require.NoError(t, err) + require.NotNil(t, state.Chains[e.HomeChainSel].CapabilityRegistry) + require.NotNil(t, state.Chains[e.HomeChainSel].CCIPHome) + require.NotNil(t, state.Chains[e.HomeChainSel].RMNHome) + for _, chain := range allChains { + require.NotNil(t, state.Chains[chain].LinkToken) + require.NotNil(t, state.Chains[chain].Weth9) + require.NotNil(t, state.Chains[chain].TokenAdminRegistry) + require.NotNil(t, state.Chains[chain].RegistryModule) + require.NotNil(t, state.Chains[chain].Router) + require.NotNil(t, state.Chains[chain].RMNRemote) + require.NotNil(t, state.Chains[chain].TestRouter) + require.NotNil(t, state.Chains[chain].NonceManager) + require.NotNil(t, state.Chains[chain].FeeQuoter) + require.NotNil(t, state.Chains[chain].OffRamp) + require.NotNil(t, state.Chains[chain].OnRamp) + } + return e +} + +// NewEnvironmentWithJobs creates a new CCIP environment +// with capreg, fee tokens, feeds, nodes and jobs set up. +func NewEnvironmentWithJobs(t *testing.T, tc *TestConfigs, tEnv TestEnvironment) DeployedEnv { + e := NewEnvironment(t, tc, tEnv) + e.SetupJobs(t) + return e +} diff --git a/deployment/ccip/changeset/test_helpers.go b/deployment/ccip/changeset/test_helpers.go index 921a24741a1..75801d99cff 100644 --- a/deployment/ccip/changeset/test_helpers.go +++ b/deployment/ccip/changeset/test_helpers.go @@ -13,28 +13,19 @@ import ( "golang.org/x/sync/errgroup" - mapset "github.com/deckarep/golang-set/v2" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/core/types" "github.com/pkg/errors" - "github.com/smartcontractkit/chainlink-ccip/pluginconfig" - commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" - - commonchangeset "github.com/smartcontractkit/chainlink/deployment/common/changeset" - commontypes "github.com/smartcontractkit/chainlink/deployment/common/types" "github.com/smartcontractkit/chainlink/v2/core/services/relay" "github.com/ethereum/go-ethereum/common" "github.com/stretchr/testify/require" - "go.uber.org/multierr" - "go.uber.org/zap/zapcore" - chainsel "github.com/smartcontractkit/chain-selectors" + "go.uber.org/multierr" - jobv1 "github.com/smartcontractkit/chainlink-protos/job-distributor/v1/job" "github.com/smartcontractkit/chainlink-testing-framework/lib/utils/testcontext" "github.com/smartcontractkit/chainlink-ccip/pkg/reader" @@ -88,35 +79,6 @@ func Context(tb testing.TB) context.Context { return ctx } -type DeployedEnv struct { - Env deployment.Environment - HomeChainSel uint64 - FeedChainSel uint64 - ReplayBlocks map[uint64]uint64 - Users map[uint64][]*bind.TransactOpts -} - -func (e *DeployedEnv) SetupJobs(t *testing.T) { - ctx := testcontext.Get(t) - out, err := CCIPCapabilityJobspec(e.Env, struct{}{}) - require.NoError(t, err) - for nodeID, jobs := range out.JobSpecs { - for _, job := range jobs { - // Note these auto-accept - _, err := e.Env.Offchain.ProposeJob(ctx, - &jobv1.ProposeJobRequest{ - NodeId: nodeID, - Spec: job, - }) - require.NoError(t, err) - } - } - // Wait for plugins to register filters? - // TODO: Investigate how to avoid. - time.Sleep(30 * time.Second) - ReplayLogs(t, e.Env.Offchain, e.ReplayBlocks) -} - func ReplayLogs(t *testing.T, oc deployment.OffchainClient, replayBlocks map[uint64]uint64) { switch oc := oc.(type) { case *memory.JobClient: @@ -184,62 +146,6 @@ func allocateCCIPChainSelectors(chains map[uint64]deployment.Chain) (homeChainSe return chainSels[HomeChainIndex], chainSels[FeedChainIndex] } -// NewMemoryEnvironment creates a new CCIP environment -// with capreg, fee tokens, feeds and nodes set up. -func NewMemoryEnvironment( - t *testing.T, - lggr logger.Logger, - config memory.MemoryEnvironmentConfig, - linkPrice *big.Int, - wethPrice *big.Int) DeployedEnv { - require.GreaterOrEqual(t, config.Chains, 2, "numChains must be at least 2 for home and feed chains") - require.GreaterOrEqual(t, config.Nodes, 4, "numNodes must be at least 4") - ctx := testcontext.Get(t) - chains, users := memory.NewMemoryChains(t, config.Chains, config.NumOfUsersPerChain) - homeChainSel, feedSel := allocateCCIPChainSelectors(chains) - replayBlocks, err := LatestBlocksByChain(ctx, chains) - require.NoError(t, err) - - ab := deployment.NewMemoryAddressBook() - crConfig := DeployTestContracts(t, lggr, ab, homeChainSel, feedSel, chains, linkPrice, wethPrice) - nodes := memory.NewNodes(t, zapcore.InfoLevel, chains, config.Nodes, config.Bootstraps, crConfig) - for _, node := range nodes { - require.NoError(t, node.App.Start(ctx)) - t.Cleanup(func() { - require.NoError(t, node.App.Stop()) - }) - } - e := memory.NewMemoryEnvironmentFromChainsNodes(func() context.Context { return ctx }, lggr, chains, nodes) - envNodes, err := deployment.NodeInfo(e.NodeIDs, e.Offchain) - require.NoError(t, err) - e.ExistingAddresses = ab - _, err = deployHomeChain(lggr, e, e.ExistingAddresses, chains[homeChainSel], - NewTestRMNStaticConfig(), - NewTestRMNDynamicConfig(), - NewTestNodeOperator(chains[homeChainSel].DeployerKey.From), - map[string][][32]byte{ - "NodeOperator": envNodes.NonBootstraps().PeerIDs(), - }, - ) - require.NoError(t, err) - - return DeployedEnv{ - Env: e, - HomeChainSel: homeChainSel, - FeedChainSel: feedSel, - ReplayBlocks: replayBlocks, - Users: users, - } -} - -// NewMemoryEnvironmentWithJobs creates a new CCIP environment -// with capreg, fee tokens, feeds, nodes and jobs set up. -func NewMemoryEnvironmentWithJobs(t *testing.T, lggr logger.Logger, config memory.MemoryEnvironmentConfig) DeployedEnv { - e := NewMemoryEnvironment(t, lggr, config, MockLinkPrice, MockWethPrice) - e.SetupJobs(t) - return e -} - // mockAttestationResponse mocks the USDC attestation server, it returns random Attestation. // We don't need to return exactly the same attestation, because our Mocked USDC contract doesn't rely on any specific // value, but instead of that it just checks if the attestation is present. Therefore, it makes the test a bit simpler @@ -264,152 +170,6 @@ func mockAttestationResponse(isFaulty bool) *httptest.Server { return server } -type TestConfigs struct { - IsUSDC bool - IsUSDCAttestationMissing bool - IsMultiCall3 bool - OCRConfigOverride func(CCIPOCRParams) CCIPOCRParams -} - -func NewMemoryEnvironmentWithJobsAndContracts(t *testing.T, lggr logger.Logger, config memory.MemoryEnvironmentConfig, tCfg *TestConfigs) DeployedEnv { - var err error - e := NewMemoryEnvironment(t, lggr, config, MockLinkPrice, MockWethPrice) - allChains := e.Env.AllChainSelectors() - mcmsCfg := make(map[uint64]commontypes.MCMSWithTimelockConfig) - for _, c := range e.Env.AllChainSelectors() { - mcmsCfg[c] = commontypes.MCMSWithTimelockConfig{ - Canceller: commonchangeset.SingleGroupMCMS(t), - Bypasser: commonchangeset.SingleGroupMCMS(t), - Proposer: commonchangeset.SingleGroupMCMS(t), - TimelockMinDelay: big.NewInt(0), - } - } - var ( - usdcChains []uint64 - isMulticall3 bool - ) - if tCfg != nil { - if tCfg.IsUSDC { - usdcChains = allChains - } - isMulticall3 = tCfg.IsMultiCall3 - } - // Need to deploy prerequisites first so that we can form the USDC config - // no proposals to be made, timelock can be passed as nil here - e.Env, err = commonchangeset.ApplyChangesets(t, e.Env, nil, []commonchangeset.ChangesetApplication{ - { - Changeset: commonchangeset.WrapChangeSet(commonchangeset.DeployLinkToken), - Config: allChains, - }, - { - Changeset: commonchangeset.WrapChangeSet(DeployPrerequisites), - Config: DeployPrerequisiteConfig{ - ChainSelectors: allChains, - Opts: []PrerequisiteOpt{ - WithUSDCChains(usdcChains), - WithMulticall3(isMulticall3), - }, - }, - }, - { - Changeset: commonchangeset.WrapChangeSet(commonchangeset.DeployMCMSWithTimelock), - Config: mcmsCfg, - }, - { - Changeset: commonchangeset.WrapChangeSet(DeployChainContracts), - Config: DeployChainContractsConfig{ - ChainSelectors: allChains, - HomeChainSelector: e.HomeChainSel, - }, - }, - }) - require.NoError(t, err) - - state, err := LoadOnchainState(e.Env) - require.NoError(t, err) - // Assert USDC set up as expected. - for _, chain := range usdcChains { - require.NotNil(t, state.Chains[chain].MockUSDCTokenMessenger) - require.NotNil(t, state.Chains[chain].MockUSDCTransmitter) - require.NotNil(t, state.Chains[chain].USDCTokenPool) - } - // Assert link present - require.NotNil(t, state.Chains[e.FeedChainSel].LinkToken) - require.NotNil(t, state.Chains[e.FeedChainSel].Weth9) - - tokenConfig := NewTestTokenConfig(state.Chains[e.FeedChainSel].USDFeeds) - var tokenDataProviders []pluginconfig.TokenDataObserverConfig - if len(usdcChains) > 0 { - server := mockAttestationResponse(tCfg.IsUSDCAttestationMissing) - endpoint := server.URL - t.Cleanup(func() { - server.Close() - }) - cctpContracts := make(map[cciptypes.ChainSelector]pluginconfig.USDCCCTPTokenConfig) - for _, usdcChain := range usdcChains { - cctpContracts[cciptypes.ChainSelector(usdcChain)] = pluginconfig.USDCCCTPTokenConfig{ - SourcePoolAddress: state.Chains[usdcChain].USDCTokenPool.Address().String(), - SourceMessageTransmitterAddr: state.Chains[usdcChain].MockUSDCTransmitter.Address().String(), - } - } - tokenDataProviders = append(tokenDataProviders, pluginconfig.TokenDataObserverConfig{ - Type: pluginconfig.USDCCCTPHandlerType, - Version: "1.0", - USDCCCTPObserverConfig: &pluginconfig.USDCCCTPObserverConfig{ - Tokens: cctpContracts, - AttestationAPI: endpoint, - AttestationAPITimeout: commonconfig.MustNewDuration(time.Second), - AttestationAPIInterval: commonconfig.MustNewDuration(500 * time.Millisecond), - }}) - } - // Build the per chain config. - chainConfigs := make(map[uint64]CCIPOCRParams) - timelockContractsPerChain := make(map[uint64]*commonchangeset.TimelockExecutionContracts) - for _, chain := range allChains { - timelockContractsPerChain[chain] = &commonchangeset.TimelockExecutionContracts{ - Timelock: state.Chains[chain].Timelock, - CallProxy: state.Chains[chain].CallProxy, - } - tokenInfo := tokenConfig.GetTokenInfo(e.Env.Logger, state.Chains[chain].LinkToken, state.Chains[chain].Weth9) - chainConfigs[chain] = DefaultOCRParams(e.FeedChainSel, tokenInfo, tokenDataProviders) - } - // Deploy second set of changesets to deploy and configure the CCIP contracts. - e.Env, err = commonchangeset.ApplyChangesets(t, e.Env, timelockContractsPerChain, []commonchangeset.ChangesetApplication{ - { - Changeset: commonchangeset.WrapChangeSet(ConfigureNewChains), - Config: NewChainsConfig{ - HomeChainSel: e.HomeChainSel, - FeedChainSel: e.FeedChainSel, - ChainConfigByChain: chainConfigs, - }, - }, - { - Changeset: commonchangeset.WrapChangeSet(CCIPCapabilityJobspec), - }, - }) - require.NoError(t, err) - - state, err = LoadOnchainState(e.Env) - require.NoError(t, err) - require.NotNil(t, state.Chains[e.HomeChainSel].CapabilityRegistry) - require.NotNil(t, state.Chains[e.HomeChainSel].CCIPHome) - require.NotNil(t, state.Chains[e.HomeChainSel].RMNHome) - for _, chain := range allChains { - require.NotNil(t, state.Chains[chain].LinkToken) - require.NotNil(t, state.Chains[chain].Weth9) - require.NotNil(t, state.Chains[chain].TokenAdminRegistry) - require.NotNil(t, state.Chains[chain].RegistryModule) - require.NotNil(t, state.Chains[chain].Router) - require.NotNil(t, state.Chains[chain].RMNRemote) - require.NotNil(t, state.Chains[chain].TestRouter) - require.NotNil(t, state.Chains[chain].NonceManager) - require.NotNil(t, state.Chains[chain].FeeQuoter) - require.NotNil(t, state.Chains[chain].OffRamp) - require.NotNil(t, state.Chains[chain].OnRamp) - } - return e -} - func CCIPSendRequest( e deployment.Environment, state CCIPOnChainState, @@ -806,38 +566,6 @@ func ConfirmRequestOnSourceAndDest(t *testing.T, env deployment.Environment, sta return nil } -// TODO: Remove this to replace with ApplyChangeset -func ProcessChangeset(t *testing.T, e deployment.Environment, c deployment.ChangesetOutput) { - - // TODO: Add support for jobspecs as well - - // sign and execute all proposals provided - if len(c.Proposals) != 0 { - state, err := LoadOnchainState(e) - require.NoError(t, err) - for _, prop := range c.Proposals { - chains := mapset.NewSet[uint64]() - for _, op := range prop.Transactions { - chains.Add(uint64(op.ChainIdentifier)) - } - - signed := commonchangeset.SignProposal(t, e, &prop) - for _, sel := range chains.ToSlice() { - commonchangeset.ExecuteProposal(t, e, signed, &commonchangeset.TimelockExecutionContracts{ - Timelock: state.Chains[sel].Timelock, - CallProxy: state.Chains[sel].CallProxy, - }, sel) - } - } - } - - // merge address books - if c.AddressBook != nil { - err := e.ExistingAddresses.Merge(c.AddressBook) - require.NoError(t, err) - } -} - func DeployTransferableToken( lggr logger.Logger, chains map[uint64]deployment.Chain, diff --git a/deployment/ccip/changeset/view_test.go b/deployment/ccip/changeset/view_test.go index 934b937f7b5..11430bfbddf 100644 --- a/deployment/ccip/changeset/view_test.go +++ b/deployment/ccip/changeset/view_test.go @@ -4,19 +4,10 @@ import ( "testing" "github.com/stretchr/testify/require" - - "github.com/smartcontractkit/chainlink/deployment/environment/memory" - "github.com/smartcontractkit/chainlink/v2/core/logger" ) func TestSmokeView(t *testing.T) { - lggr := logger.TestLogger(t) - tenv := NewMemoryEnvironmentWithJobsAndContracts(t, lggr, memory.MemoryEnvironmentConfig{ - Chains: 3, - Nodes: 4, - Bootstraps: 1, - NumOfUsersPerChain: 1, - }, nil) + tenv := NewMemoryEnvironment(t, WithChains(3)) _, err := ViewCCIP(tenv.Env) require.NoError(t, err) } diff --git a/deployment/go.mod b/deployment/go.mod index 2c5e9b9e0b6..4cafe4308d4 100644 --- a/deployment/go.mod +++ b/deployment/go.mod @@ -18,6 +18,7 @@ require ( github.com/google/uuid v1.6.0 github.com/hashicorp/consul/sdk v0.16.1 github.com/hashicorp/go-multierror v1.1.1 + github.com/imdario/mergo v0.3.16 github.com/pelletier/go-toml/v2 v2.2.3 github.com/pkg/errors v0.9.1 github.com/rs/zerolog v1.33.0 @@ -290,7 +291,6 @@ require ( github.com/huandu/xstrings v1.4.0 // indirect github.com/huin/goupnp v1.3.0 // indirect github.com/iancoleman/strcase v0.3.0 // indirect - github.com/imdario/mergo v0.3.16 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/invopop/jsonschema v0.12.0 // indirect github.com/jackc/chunkreader/v2 v2.0.1 // indirect diff --git a/deployment/helpers.go b/deployment/helpers.go index 50f4c404b09..dfbbccc2698 100644 --- a/deployment/helpers.go +++ b/deployment/helpers.go @@ -146,7 +146,7 @@ func DeployContract[C any]( lggr.Errorw("Failed to confirm deployment", "chain", chain.String(), "Contract", contractDeploy.Tv.String(), "err", err) return nil, err } - lggr.Infow("Deployed contract", "Contract", contractDeploy.Tv.String(), "addr", contractDeploy.Address, "chain", chain.Selector) + lggr.Infow("Deployed contract", "Contract", contractDeploy.Tv.String(), "addr", contractDeploy.Address, "chain", chain.String()) err = addressBook.Save(chain.Selector, contractDeploy.Address.String(), contractDeploy.Tv) if err != nil { lggr.Errorw("Failed to save contract address", "Contract", contractDeploy.Tv.String(), "addr", contractDeploy.Address, "chain", chain.String(), "err", err) diff --git a/integration-tests/contracts/ccipreader_test.go b/integration-tests/contracts/ccipreader_test.go index 3028f4707a4..07e10f722b9 100644 --- a/integration-tests/contracts/ccipreader_test.go +++ b/integration-tests/contracts/ccipreader_test.go @@ -473,11 +473,7 @@ func TestCCIPReader_GetExpectedNextSequenceNumber(t *testing.T) { t.Parallel() ctx := tests.Context(t) //env := NewMemoryEnvironmentContractsOnly(t, logger.TestLogger(t), 2, 4, nil) - env := changeset.NewMemoryEnvironmentWithJobsAndContracts(t, logger.TestLogger(t), memory.MemoryEnvironmentConfig{ - Chains: 2, - Nodes: 4, - Bootstraps: 1, - }, nil) + env := changeset.NewMemoryEnvironment(t) state, err := changeset.LoadOnchainState(env.Env) require.NoError(t, err) @@ -587,11 +583,7 @@ func TestCCIPReader_Nonces(t *testing.T) { func Test_GetChainFeePriceUpdates(t *testing.T) { t.Parallel() ctx := tests.Context(t) - env := changeset.NewMemoryEnvironmentWithJobsAndContracts(t, logger.TestLogger(t), memory.MemoryEnvironmentConfig{ - Chains: 2, - Nodes: 4, - Bootstraps: 1, - }, nil) + env := changeset.NewMemoryEnvironment(t) state, err := changeset.LoadOnchainState(env.Env) require.NoError(t, err) @@ -647,11 +639,7 @@ func Test_GetChainFeePriceUpdates(t *testing.T) { func Test_LinkPriceUSD(t *testing.T) { t.Parallel() ctx := tests.Context(t) - env := changeset.NewMemoryEnvironmentWithJobsAndContracts(t, logger.TestLogger(t), memory.MemoryEnvironmentConfig{ - Chains: 2, - Nodes: 4, - Bootstraps: 1, - }, nil) + env := changeset.NewMemoryEnvironment(t) state, err := changeset.LoadOnchainState(env.Env) require.NoError(t, err) @@ -686,11 +674,7 @@ func Test_LinkPriceUSD(t *testing.T) { func Test_GetMedianDataAvailabilityGasConfig(t *testing.T) { t.Parallel() ctx := tests.Context(t) - env := changeset.NewMemoryEnvironmentWithJobsAndContracts(t, logger.TestLogger(t), memory.MemoryEnvironmentConfig{ - Chains: 4, - Nodes: 4, - Bootstraps: 1, - }, nil) + env := changeset.NewMemoryEnvironment(t, changeset.WithChains(4)) state, err := changeset.LoadOnchainState(env.Env) require.NoError(t, err) @@ -749,11 +733,7 @@ func Test_GetMedianDataAvailabilityGasConfig(t *testing.T) { func Test_GetWrappedNativeTokenPriceUSD(t *testing.T) { t.Parallel() ctx := tests.Context(t) - env := changeset.NewMemoryEnvironmentWithJobsAndContracts(t, logger.TestLogger(t), memory.MemoryEnvironmentConfig{ - Chains: 2, - Nodes: 4, - Bootstraps: 1, - }, nil) + env := changeset.NewMemoryEnvironment(t) state, err := changeset.LoadOnchainState(env.Env) require.NoError(t, err) diff --git a/integration-tests/smoke/ccip/ccip_batching_test.go b/integration-tests/smoke/ccip/ccip_batching_test.go index 8c3615fbb20..58f4e922ac5 100644 --- a/integration-tests/smoke/ccip/ccip_batching_test.go +++ b/integration-tests/smoke/ccip/ccip_batching_test.go @@ -14,7 +14,8 @@ import ( "github.com/smartcontractkit/chainlink-ccip/pkg/types/ccipocr3" "github.com/smartcontractkit/chainlink-common/pkg/merklemulti" - "github.com/smartcontractkit/chainlink/deployment/environment/memory" + + testsetups "github.com/smartcontractkit/chainlink/integration-tests/testsetups/ccip" "github.com/smartcontractkit/chainlink/deployment" "github.com/smartcontractkit/chainlink/deployment/ccip/changeset" @@ -22,7 +23,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/onramp" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/router" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/shared/generated/multicall3" - "github.com/smartcontractkit/chainlink/v2/core/logger" ) const ( @@ -39,18 +39,11 @@ type batchTestSetup struct { func newBatchTestSetup(t *testing.T) batchTestSetup { // Setup 3 chains, with 2 lanes going to the dest. - e := changeset.NewMemoryEnvironmentWithJobsAndContracts( + e, _ := testsetups.NewIntegrationEnvironment( t, - logger.TestLogger(t), - memory.MemoryEnvironmentConfig{ - Chains: 3, - Nodes: 4, - Bootstraps: 1, - NumOfUsersPerChain: 2, - }, - &changeset.TestConfigs{ - IsMultiCall3: true, - }, + changeset.WithMultiCall3(), + changeset.WithChains(3), + changeset.WithUsersPerChain(2), ) state, err := changeset.LoadOnchainState(e.Env) diff --git a/integration-tests/smoke/ccip/ccip_fee_boosting_test.go b/integration-tests/smoke/ccip/ccip_fee_boosting_test.go index 1fe9d5817c9..48d9061ec63 100644 --- a/integration-tests/smoke/ccip/ccip_fee_boosting_test.go +++ b/integration-tests/smoke/ccip/ccip_fee_boosting_test.go @@ -9,8 +9,8 @@ import ( "github.com/pkg/errors" - "github.com/smartcontractkit/chainlink-common/pkg/config" commonchangeset "github.com/smartcontractkit/chainlink/deployment/common/changeset" + testsetups "github.com/smartcontractkit/chainlink/integration-tests/testsetups/ccip" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" @@ -20,7 +20,6 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/utils/tests" "github.com/smartcontractkit/chainlink-testing-framework/lib/utils/testcontext" - "github.com/smartcontractkit/chainlink/deployment/environment/memory" "github.com/smartcontractkit/chainlink/v2/core/capabilities/ccip/ccipevm" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/fee_quoter" @@ -30,7 +29,6 @@ import ( "github.com/smartcontractkit/chainlink/deployment/ccip/changeset" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/onramp" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/router" - "github.com/smartcontractkit/chainlink/v2/core/logger" ) var ( @@ -39,13 +37,10 @@ var ( ) func Test_CCIPFeeBoosting(t *testing.T) { - e := changeset.NewMemoryEnvironmentWithJobsAndContracts(t, logger.TestLogger(t), - memory.MemoryEnvironmentConfig{ - Chains: 2, - Nodes: 4, - Bootstraps: 1, - }, &changeset.TestConfigs{ - OCRConfigOverride: func(params changeset.CCIPOCRParams) changeset.CCIPOCRParams { + e, _ := testsetups.NewIntegrationEnvironment( + t, + // TODO check if test should use these overrides + /* changeset.WithOCRConfigOverride(func(params changeset.CCIPOCRParams) changeset.CCIPOCRParams { // Only 1 boost (=OCR round) is enough to cover the fee params.ExecuteOffChainConfig.RelativeBoostPerWaitHour = 10 // Disable token price updates @@ -55,8 +50,10 @@ func Test_CCIPFeeBoosting(t *testing.T) { // Disable token price updates params.CommitOffChainConfig.TokenInfo = nil return params - }, - }) + }), + + */ + ) state, err := changeset.LoadOnchainState(e.Env) require.NoError(t, err) diff --git a/integration-tests/smoke/ccip/ccip_fees_test.go b/integration-tests/smoke/ccip/ccip_fees_test.go index 791ba8f2619..55788a4aa5f 100644 --- a/integration-tests/smoke/ccip/ccip_fees_test.go +++ b/integration-tests/smoke/ccip/ccip_fees_test.go @@ -14,7 +14,7 @@ import ( "github.com/smartcontractkit/chainlink/deployment" "github.com/smartcontractkit/chainlink/deployment/ccip/changeset" - "github.com/smartcontractkit/chainlink/deployment/environment/memory" + testsetups "github.com/smartcontractkit/chainlink/integration-tests/testsetups/ccip" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/router" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/generated/weth9_wrapper" @@ -101,11 +101,10 @@ func setupTokens( func Test_CCIPFees(t *testing.T) { t.Parallel() - tenv := changeset.NewMemoryEnvironmentWithJobsAndContracts(t, logger.TestLogger(t), memory.MemoryEnvironmentConfig{ - Chains: 2, - Nodes: 4, - Bootstraps: 1, - }, nil) + tenv, _ := testsetups.NewIntegrationEnvironment( + t, + changeset.WithMultiCall3(), + ) e := tenv.Env allChains := tenv.Env.AllChainSelectors() diff --git a/integration-tests/smoke/ccip/ccip_gas_price_updates_test.go b/integration-tests/smoke/ccip/ccip_gas_price_updates_test.go index 221d35bd992..d11e4304366 100644 --- a/integration-tests/smoke/ccip/ccip_gas_price_updates_test.go +++ b/integration-tests/smoke/ccip/ccip_gas_price_updates_test.go @@ -12,27 +12,26 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink-common/pkg/utils/tests" + "github.com/smartcontractkit/chainlink/deployment" "github.com/smartcontractkit/chainlink/deployment/ccip/changeset" testsetups "github.com/smartcontractkit/chainlink/integration-tests/testsetups/ccip" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/fee_quoter" - "github.com/smartcontractkit/chainlink/v2/core/logger" ) // Test_CCIPGasPriceUpdates tests that chain fee price updates are propagated correctly when // price reaches some deviation threshold or when the price has expired. func Test_CCIPGasPriceUpdates(t *testing.T) { - lggr := logger.TestLogger(t) ctx := changeset.Context(t) callOpts := &bind.CallOpts{Context: ctx} var gasPriceExpiry = 5 * time.Second - e, _, _ := testsetups.NewLocalDevEnvironmentWithDefaultPrice(t, lggr, &changeset.TestConfigs{ - OCRConfigOverride: func(params changeset.CCIPOCRParams) changeset.CCIPOCRParams { + e, _ := testsetups.NewIntegrationEnvironment(t, + changeset.WithOCRConfigOverride(func(params changeset.CCIPOCRParams) changeset.CCIPOCRParams { params.CommitOffChainConfig.RemoteGasPriceBatchWriteFrequency = *config.MustNewDuration(gasPriceExpiry) return params - }, - }) + }), + ) state, err := changeset.LoadOnchainState(e.Env) require.NoError(t, err) require.NoError(t, changeset.AddLanesForAll(e.Env, state)) diff --git a/integration-tests/smoke/ccip/ccip_message_limitations_test.go b/integration-tests/smoke/ccip/ccip_message_limitations_test.go index 902d07aec5c..9398fd9f932 100644 --- a/integration-tests/smoke/ccip/ccip_message_limitations_test.go +++ b/integration-tests/smoke/ccip/ccip_message_limitations_test.go @@ -17,15 +17,13 @@ import ( "github.com/smartcontractkit/chainlink/deployment/ccip/changeset" testsetups "github.com/smartcontractkit/chainlink/integration-tests/testsetups/ccip" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/router" - "github.com/smartcontractkit/chainlink/v2/core/logger" ) func Test_CCIPMessageLimitations(t *testing.T) { - lggr := logger.TestLogger(t) ctx := testcontext.Get(t) callOpts := &bind.CallOpts{Context: ctx} - testEnv, _, _ := testsetups.NewLocalDevEnvironmentWithDefaultPrice(t, lggr, &changeset.TestConfigs{}) + testEnv, _ := testsetups.NewIntegrationEnvironment(t) chains := maps.Keys(testEnv.Env.Chains) onChainState, err := changeset.LoadOnchainState(testEnv.Env) diff --git a/integration-tests/smoke/ccip/ccip_messaging_test.go b/integration-tests/smoke/ccip/ccip_messaging_test.go index 07e237451c8..13f14fcda16 100644 --- a/integration-tests/smoke/ccip/ccip_messaging_test.go +++ b/integration-tests/smoke/ccip/ccip_messaging_test.go @@ -18,11 +18,10 @@ import ( "github.com/smartcontractkit/chainlink/deployment" "github.com/smartcontractkit/chainlink/deployment/ccip/changeset" - "github.com/smartcontractkit/chainlink/deployment/environment/memory" + testsetups "github.com/smartcontractkit/chainlink/integration-tests/testsetups/ccip" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/offramp" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/onramp" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/router" - "github.com/smartcontractkit/chainlink/v2/core/logger" ) type testCaseSetup struct { @@ -48,11 +47,7 @@ type messagingTestCaseOutput struct { func Test_CCIPMessaging(t *testing.T) { // Setup 2 chains and a single lane. ctx := changeset.Context(t) - e := changeset.NewMemoryEnvironmentWithJobsAndContracts(t, logger.TestLogger(t), memory.MemoryEnvironmentConfig{ - Chains: 2, - Nodes: 4, - Bootstraps: 1, - }, nil) + e, _ := testsetups.NewIntegrationEnvironment(t) state, err := changeset.LoadOnchainState(e.Env) require.NoError(t, err) diff --git a/integration-tests/smoke/ccip/ccip_ooo_execution_test.go b/integration-tests/smoke/ccip/ccip_ooo_execution_test.go index 86ddd07ec85..19c36c6e021 100644 --- a/integration-tests/smoke/ccip/ccip_ooo_execution_test.go +++ b/integration-tests/smoke/ccip/ccip_ooo_execution_test.go @@ -12,9 +12,10 @@ import ( "github.com/smartcontractkit/chainlink-ccip/pkg/types/ccipocr3" "github.com/smartcontractkit/chainlink-common/pkg/utils/tests" + "github.com/smartcontractkit/chainlink/deployment" "github.com/smartcontractkit/chainlink/deployment/ccip/changeset" - "github.com/smartcontractkit/chainlink/deployment/environment/memory" + testsetups "github.com/smartcontractkit/chainlink/integration-tests/testsetups/ccip" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/router" "github.com/smartcontractkit/chainlink/v2/core/logger" @@ -32,16 +33,12 @@ import ( func Test_OutOfOrderExecution(t *testing.T) { lggr := logger.TestLogger(t) ctx := tests.Context(t) - config := &changeset.TestConfigs{ - IsUSDC: true, - IsUSDCAttestationMissing: true, - } - tenv := changeset.NewMemoryEnvironmentWithJobsAndContracts(t, logger.TestLogger(t), memory.MemoryEnvironmentConfig{ - Chains: 2, - Nodes: 4, - Bootstraps: 1, - NumOfUsersPerChain: 2, - }, config) + tenv, _ := testsetups.NewIntegrationEnvironment( + t, + changeset.WithUSDC(), + changeset.WithUSDCAttestationMissing(), + changeset.WithUsersPerChain(2), + ) e := tenv.Env state, err := changeset.LoadOnchainState(e) diff --git a/integration-tests/smoke/ccip/ccip_rmn_test.go b/integration-tests/smoke/ccip/ccip_rmn_test.go index 6cd6bd9d63f..adf07be290f 100644 --- a/integration-tests/smoke/ccip/ccip_rmn_test.go +++ b/integration-tests/smoke/ccip/ccip_rmn_test.go @@ -22,9 +22,9 @@ import ( "github.com/smartcontractkit/chainlink-protos/job-distributor/v1/node" "github.com/smartcontractkit/chainlink-testing-framework/lib/utils/osutil" "github.com/smartcontractkit/chainlink-testing-framework/lib/utils/testcontext" - "github.com/smartcontractkit/chainlink/deployment/environment/devenv" "github.com/smartcontractkit/chainlink/deployment/ccip/changeset" + "github.com/smartcontractkit/chainlink/deployment/environment/devenv" "github.com/smartcontractkit/chainlink/deployment" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/rmn_home" @@ -32,7 +32,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/router" testsetups "github.com/smartcontractkit/chainlink/integration-tests/testsetups/ccip" - "github.com/smartcontractkit/chainlink/v2/core/logger" ) func TestRMN_TwoMessagesOnTwoLanesIncludingBatching(t *testing.T) { @@ -244,7 +243,9 @@ func runRmnTestCase(t *testing.T, tc rmnTestCase) { ctx := testcontext.Get(t) t.Logf("Running RMN test case: %s", tc.name) - envWithRMN, rmnCluster := testsetups.NewLocalDevEnvironmentWithRMN(t, logger.TestLogger(t), len(tc.rmnNodes)) + envWithRMN, rmnCluster := testsetups.NewIntegrationEnvironment(t, + changeset.WithRMNEnabled(len(tc.rmnNodes)), + ) t.Logf("envWithRmn: %#v", envWithRMN) tc.populateFields(t, envWithRMN, rmnCluster) diff --git a/integration-tests/smoke/ccip/ccip_token_price_updates_test.go b/integration-tests/smoke/ccip/ccip_token_price_updates_test.go index 6a193397d7e..e3496b6f407 100644 --- a/integration-tests/smoke/ccip/ccip_token_price_updates_test.go +++ b/integration-tests/smoke/ccip/ccip_token_price_updates_test.go @@ -16,25 +16,23 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink-common/pkg/utils/tests" "github.com/smartcontractkit/chainlink-protos/job-distributor/v1/node" + "github.com/smartcontractkit/chainlink/deployment" "github.com/smartcontractkit/chainlink/deployment/ccip/changeset" testsetups "github.com/smartcontractkit/chainlink/integration-tests/testsetups/ccip" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/fee_quoter" - "github.com/smartcontractkit/chainlink/v2/core/logger" ) func Test_CCIPTokenPriceUpdates(t *testing.T) { - lggr := logger.TestLogger(t) ctx := changeset.Context(t) callOpts := &bind.CallOpts{Context: ctx} var tokenPriceExpiry = 5 * time.Second - e, _, _ := testsetups.NewLocalDevEnvironmentWithDefaultPrice(t, lggr, &changeset.TestConfigs{ - OCRConfigOverride: func(params changeset.CCIPOCRParams) changeset.CCIPOCRParams { + e, _ := testsetups.NewIntegrationEnvironment(t, + changeset.WithOCRConfigOverride(func(params changeset.CCIPOCRParams) changeset.CCIPOCRParams { params.CommitOffChainConfig.TokenPriceBatchWriteFrequency = *config.MustNewDuration(tokenPriceExpiry) return params - }, - }) + })) state, err := changeset.LoadOnchainState(e.Env) require.NoError(t, err) require.NoError(t, changeset.AddLanesForAll(e.Env, state)) diff --git a/integration-tests/smoke/ccip/ccip_token_transfer_test.go b/integration-tests/smoke/ccip/ccip_token_transfer_test.go index 13abe33fe7c..2088960639e 100644 --- a/integration-tests/smoke/ccip/ccip_token_transfer_test.go +++ b/integration-tests/smoke/ccip/ccip_token_transfer_test.go @@ -10,8 +10,9 @@ import ( "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink-common/pkg/utils/tests" + "github.com/smartcontractkit/chainlink/deployment/ccip/changeset" - "github.com/smartcontractkit/chainlink/deployment/environment/memory" + testsetups "github.com/smartcontractkit/chainlink/integration-tests/testsetups/ccip" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/router" "github.com/smartcontractkit/chainlink/v2/core/logger" @@ -20,14 +21,9 @@ import ( func TestTokenTransfer(t *testing.T) { lggr := logger.TestLogger(t) ctx := tests.Context(t) - config := &changeset.TestConfigs{} - tenv := changeset.NewMemoryEnvironmentWithJobsAndContracts(t, logger.TestLogger(t), memory.MemoryEnvironmentConfig{ - Chains: 2, - Nodes: 4, - Bootstraps: 1, - NumOfUsersPerChain: 3, - }, config) + tenv, _ := testsetups.NewIntegrationEnvironment(t, + changeset.WithUsersPerChain(3)) e := tenv.Env state, err := changeset.LoadOnchainState(e) @@ -214,7 +210,7 @@ func TestTokenTransfer(t *testing.T) { t, e, state, - changeset.SeqNumberRageToSlice(expectedSeqNums), + changeset.SeqNumberRangeToSlice(expectedSeqNums), startBlocks, ) require.Equal(t, expectedExecutionStates, execStates) diff --git a/integration-tests/smoke/ccip/ccip_usdc_test.go b/integration-tests/smoke/ccip/ccip_usdc_test.go index 2dae3f3c48e..174ab941387 100644 --- a/integration-tests/smoke/ccip/ccip_usdc_test.go +++ b/integration-tests/smoke/ccip/ccip_usdc_test.go @@ -11,9 +11,10 @@ import ( "golang.org/x/sync/errgroup" "github.com/smartcontractkit/chainlink-common/pkg/utils/tests" + "github.com/smartcontractkit/chainlink/deployment" "github.com/smartcontractkit/chainlink/deployment/ccip/changeset" - "github.com/smartcontractkit/chainlink/deployment/environment/memory" + testsetups "github.com/smartcontractkit/chainlink/integration-tests/testsetups/ccip" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/router" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/shared/generated/burn_mint_erc677" @@ -31,15 +32,11 @@ import ( func TestUSDCTokenTransfer(t *testing.T) { lggr := logger.TestLogger(t) ctx := tests.Context(t) - config := &changeset.TestConfigs{ - IsUSDC: true, - } - tenv := changeset.NewMemoryEnvironmentWithJobsAndContracts(t, lggr, memory.MemoryEnvironmentConfig{ - Chains: 3, - NumOfUsersPerChain: 3, - Nodes: 4, - Bootstraps: 1, - }, config) + tenv, _ := testsetups.NewIntegrationEnvironment(t, + changeset.WithUsersPerChain(3), + changeset.WithChains(3), + changeset.WithUSDC(), + ) e := tenv.Env state, err := changeset.LoadOnchainState(e) @@ -228,7 +225,7 @@ func TestUSDCTokenTransfer(t *testing.T) { t, e, state, - changeset.SeqNumberRageToSlice(expectedSeqNums), + changeset.SeqNumberRangeToSlice(expectedSeqNums), startBlocks, ) require.Equal(t, expectedExecutionStates, execStates) diff --git a/integration-tests/testsetups/ccip/test_helpers.go b/integration-tests/testsetups/ccip/test_helpers.go index f26a9d3c672..aafc1325da7 100644 --- a/integration-tests/testsetups/ccip/test_helpers.go +++ b/integration-tests/testsetups/ccip/test_helpers.go @@ -8,13 +8,10 @@ import ( "os" "strconv" "testing" - "time" "github.com/ethereum/go-ethereum/accounts/abi/bind" chainsel "github.com/smartcontractkit/chain-selectors" - cciptypes "github.com/smartcontractkit/chainlink-ccip/pkg/types/ccipocr3" - "github.com/smartcontractkit/chainlink-ccip/pluginconfig" commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink-testing-framework/lib/blockchain" ctfconfig "github.com/smartcontractkit/chainlink-testing-framework/lib/config" @@ -28,8 +25,6 @@ import ( "github.com/smartcontractkit/chainlink/deployment" "github.com/smartcontractkit/chainlink/deployment/ccip/changeset" - commonchangeset "github.com/smartcontractkit/chainlink/deployment/common/changeset" - commontypes "github.com/smartcontractkit/chainlink/deployment/common/types" integrationnodes "github.com/smartcontractkit/chainlink/integration-tests/types/config/node" evmcfg "github.com/smartcontractkit/chainlink/v2/core/chains/evm/config/toml" corechainlink "github.com/smartcontractkit/chainlink/v2/core/services/chainlink" @@ -56,237 +51,140 @@ import ( // DeployedLocalDevEnvironment is a helper struct for setting up a local dev environment with docker type DeployedLocalDevEnvironment struct { changeset.DeployedEnv - testEnv *test_env.CLClusterTestEnv - DON *devenv.DON + testEnv *test_env.CLClusterTestEnv + DON *devenv.DON + devEnvTestCfg tc.TestConfig + devEnvCfg *devenv.EnvironmentConfig } -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 (l *DeployedLocalDevEnvironment) DeployedEnvironment() changeset.DeployedEnv { + return l.DeployedEnv } -func NewLocalDevEnvironmentWithDefaultPrice(t *testing.T, lggr logger.Logger, tCfg *changeset.TestConfigs) (changeset.DeployedEnv, *test_env.CLClusterTestEnv, tc.TestConfig) { - return NewLocalDevEnvironment(t, lggr, changeset.MockLinkPrice, changeset.MockWethPrice, tCfg) -} - -func NewLocalDevEnvironment( - t *testing.T, - lggr logger.Logger, - linkPrice, wethPrice *big.Int, - tCfg *changeset.TestConfigs, -) (changeset.DeployedEnv, *test_env.CLClusterTestEnv, tc.TestConfig) { - if tCfg == nil { - // set to the default constructed value - tCfg = &changeset.TestConfigs{} - } - +func (l *DeployedLocalDevEnvironment) StartChains(t *testing.T, _ *changeset.TestConfigs) { + lggr := logger.TestLogger(t) ctx := testcontext.Get(t) - // create a local docker environment with simulated chains and job-distributor - // we cannot create the chainlink nodes yet as we need to deploy the capability registry first envConfig, testEnv, cfg := CreateDockerEnv(t) - require.NotNil(t, envConfig) - require.NotEmpty(t, envConfig.Chains, "chainConfigs should not be empty") - require.NotEmpty(t, envConfig.JDConfig, "jdUrl should not be empty") + l.devEnvTestCfg = cfg + l.testEnv = testEnv + l.devEnvCfg = envConfig users := make(map[uint64][]*bind.TransactOpts) for _, chain := range envConfig.Chains { - sel, err := chainsel.SelectorFromChainId(chain.ChainID) - require.NoError(t, err) - users[sel] = chain.Users + details, found := chainsel.ChainByEvmChainID(chain.ChainID) + require.Truef(t, found, "chain not found") + users[details.Selector] = chain.Users } - chains, err := devenv.NewChains(lggr, envConfig.Chains) - require.NoError(t, err) - // locate the home chain - homeChainSel := cfg.CCIP.GetHomeChainSelector() + homeChainSel := l.devEnvTestCfg.CCIP.GetHomeChainSelector() require.NotEmpty(t, homeChainSel, "homeChainSel should not be empty") - feedSel := cfg.CCIP.GetFeedChainSelector() + feedSel := l.devEnvTestCfg.CCIP.GetFeedChainSelector() require.NotEmpty(t, feedSel, "feedSel should not be empty") + chains, err := devenv.NewChains(lggr, envConfig.Chains) + require.NoError(t, err) replayBlocks, err := changeset.LatestBlocksByChain(ctx, chains) require.NoError(t, err) + l.DeployedEnv.Users = users + l.DeployedEnv.Env.Chains = chains + l.DeployedEnv.FeedChainSel = feedSel + l.DeployedEnv.HomeChainSel = homeChainSel + l.DeployedEnv.ReplayBlocks = replayBlocks +} - ab := deployment.NewMemoryAddressBook() - crConfig := changeset.DeployTestContracts(t, lggr, ab, homeChainSel, feedSel, chains, linkPrice, wethPrice) - - // start the chainlink nodes with the CR address - err = StartChainlinkNodes(t, envConfig, +func (l *DeployedLocalDevEnvironment) StartNodes(t *testing.T, _ *changeset.TestConfigs, crConfig deployment.CapabilityRegistryConfig) { + require.NotNil(t, l.testEnv, "docker env is empty, start chains first") + require.NotEmpty(t, l.devEnvTestCfg, "integration test config is empty, start chains first") + require.NotNil(t, l.devEnvCfg, "dev environment config is empty, start chains first") + err := StartChainlinkNodes(t, l.devEnvCfg, crConfig, - testEnv, cfg) + l.testEnv, l.devEnvTestCfg) require.NoError(t, err) - - e, don, err := devenv.NewEnvironment(func() context.Context { return ctx }, lggr, *envConfig) + ctx := testcontext.Get(t) + lggr := logger.TestLogger(t) + e, don, err := devenv.NewEnvironment(func() context.Context { return ctx }, lggr, *l.devEnvCfg) require.NoError(t, err) require.NotNil(t, e) - e.ExistingAddresses = ab + l.DON = don + l.DeployedEnv.Env = *e // fund the nodes zeroLogLggr := logging.GetTestLogger(t) - FundNodes(t, zeroLogLggr, testEnv, cfg, don.PluginNodes()) + FundNodes(t, zeroLogLggr, l.testEnv, l.devEnvTestCfg, don.PluginNodes()) +} - env := *e - envNodes, err := deployment.NodeInfo(env.NodeIDs, env.Offchain) - require.NoError(t, err) - allChains := env.AllChainSelectors() - var usdcChains []uint64 - if tCfg.IsUSDC { - usdcChains = allChains - } - mcmsCfg := make(map[uint64]commontypes.MCMSWithTimelockConfig) - for _, c := range env.AllChainSelectors() { - mcmsCfg[c] = commontypes.MCMSWithTimelockConfig{ - Canceller: commonchangeset.SingleGroupMCMS(t), - Bypasser: commonchangeset.SingleGroupMCMS(t), - Proposer: commonchangeset.SingleGroupMCMS(t), - TimelockMinDelay: big.NewInt(0), - } - } - // Need to deploy prerequisites first so that we can form the USDC config - // no proposals to be made, timelock can be passed as nil here - env, err = commonchangeset.ApplyChangesets(t, env, nil, []commonchangeset.ChangesetApplication{ - { - Changeset: commonchangeset.WrapChangeSet(changeset.DeployHomeChain), - Config: changeset.DeployHomeChainConfig{ - HomeChainSel: homeChainSel, - RMNStaticConfig: changeset.NewTestRMNStaticConfig(), - RMNDynamicConfig: changeset.NewTestRMNDynamicConfig(), - NodeOperators: changeset.NewTestNodeOperator(chains[homeChainSel].DeployerKey.From), - NodeP2PIDsPerNodeOpAdmin: map[string][][32]byte{ - "NodeOperator": envNodes.NonBootstraps().PeerIDs(), - }, - }, - }, - { - Changeset: commonchangeset.WrapChangeSet(commonchangeset.DeployLinkToken), - Config: allChains, - }, - { - Changeset: commonchangeset.WrapChangeSet(changeset.DeployPrerequisites), - Config: changeset.DeployPrerequisiteConfig{ - ChainSelectors: allChains, - Opts: []changeset.PrerequisiteOpt{ - changeset.WithUSDCChains(usdcChains), - changeset.WithMulticall3(tCfg.IsMultiCall3), - }, - }, - }, - { - Changeset: commonchangeset.WrapChangeSet(commonchangeset.DeployMCMSWithTimelock), - Config: mcmsCfg, - }, - { - Changeset: commonchangeset.WrapChangeSet(changeset.DeployChainContracts), - Config: changeset.DeployChainContractsConfig{ - ChainSelectors: allChains, - HomeChainSelector: homeChainSel, - }, - }, - }) - require.NoError(t, err) - state, err := changeset.LoadOnchainState(env) +func (l *DeployedLocalDevEnvironment) MockUSDCAttestationServer(t *testing.T, isUSDCAttestationMissing bool) string { + err := ccipactions.SetMockServerWithUSDCAttestation(l.testEnv.MockAdapter, nil, isUSDCAttestationMissing) require.NoError(t, err) + return l.testEnv.MockAdapter.InternalEndpoint +} - var tokenDataProviders []pluginconfig.TokenDataObserverConfig - if len(usdcChains) > 0 { - var endpoint string - err = ccipactions.SetMockServerWithUSDCAttestation(testEnv.MockAdapter, nil, tCfg.IsUSDCAttestationMissing) - require.NoError(t, err) - endpoint = testEnv.MockAdapter.InternalEndpoint - cctpContracts := make(map[cciptypes.ChainSelector]pluginconfig.USDCCCTPTokenConfig) - for _, usdcChain := range usdcChains { - cctpContracts[cciptypes.ChainSelector(usdcChain)] = pluginconfig.USDCCCTPTokenConfig{ - SourcePoolAddress: state.Chains[usdcChain].USDCTokenPool.Address().String(), - SourceMessageTransmitterAddr: state.Chains[usdcChain].MockUSDCTransmitter.Address().String(), +func (l *DeployedLocalDevEnvironment) RestartChainlinkNodes(t *testing.T) error { + errGrp := errgroup.Group{} + for _, n := range l.testEnv.ClCluster.Nodes { + n := n + errGrp.Go(func() error { + if err := n.Container.Terminate(testcontext.Get(t)); err != nil { + return err } - } - tokenDataProviders = append(tokenDataProviders, pluginconfig.TokenDataObserverConfig{ - Type: pluginconfig.USDCCCTPHandlerType, - Version: "1.0", - USDCCCTPObserverConfig: &pluginconfig.USDCCCTPObserverConfig{ - Tokens: cctpContracts, - AttestationAPI: endpoint, - AttestationAPITimeout: commonconfig.MustNewDuration(time.Second), - AttestationAPIInterval: commonconfig.MustNewDuration(500 * time.Millisecond), - }}) + err := n.RestartContainer() + if err != nil { + return err + } + return nil + }) + } + return errGrp.Wait() +} - // Build the per chain config. - tokenConfig := changeset.NewTestTokenConfig(state.Chains[feedSel].USDFeeds) - chainConfigs := make(map[uint64]changeset.CCIPOCRParams) - timelockContractsPerChain := make(map[uint64]*commonchangeset.TimelockExecutionContracts) - for _, chain := range allChains { - timelockContractsPerChain[chain] = &commonchangeset.TimelockExecutionContracts{ - Timelock: state.Chains[chain].Timelock, - CallProxy: state.Chains[chain].CallProxy, +func NewIntegrationEnvironment(t *testing.T, opts ...changeset.TestOps) (changeset.DeployedEnv, devenv.RMNCluster) { + testCfg := changeset.DefaultTestConfigs() + for _, opt := range opts { + opt(testCfg) + } + // check for EnvType env var + testCfg.MustSetEnvTypeOrDefault(t) + require.NoError(t, testCfg.Validate(), "invalid test config") + switch testCfg.Type { + case changeset.Memory: + memEnv := changeset.NewMemoryEnvironment(t, opts...) + return memEnv, devenv.RMNCluster{} + case changeset.Docker: + dockerEnv := &DeployedLocalDevEnvironment{} + if testCfg.RMNEnabled { + deployedEnv := changeset.NewEnvironmentWithJobsAndContracts(t, testCfg, dockerEnv) + l := logging.GetTestLogger(t) + require.NotNil(t, dockerEnv.testEnv, "empty docker environment") + config := GenerateTestRMNConfig(t, testCfg.NumOfRMNNodes, deployedEnv, MustNetworksToRPCMap(dockerEnv.testEnv.EVMNetworks)) + require.NotNil(t, dockerEnv.devEnvTestCfg.CCIP) + rmnCluster, err := devenv.NewRMNCluster( + t, l, + []string{dockerEnv.testEnv.DockerNetwork.ID}, + config, + dockerEnv.devEnvTestCfg.CCIP.RMNConfig.GetProxyImage(), + dockerEnv.devEnvTestCfg.CCIP.RMNConfig.GetProxyVersion(), + dockerEnv.devEnvTestCfg.CCIP.RMNConfig.GetAFN2ProxyImage(), + dockerEnv.devEnvTestCfg.CCIP.RMNConfig.GetAFN2ProxyVersion(), + dockerEnv.testEnv.LogStream, + ) + require.NoError(t, err) + return deployedEnv, *rmnCluster } - tokenInfo := tokenConfig.GetTokenInfo(e.Logger, state.Chains[chain].LinkToken, state.Chains[chain].Weth9) - ocrParams := changeset.DefaultOCRParams(feedSel, tokenInfo, tokenDataProviders) - if tCfg.OCRConfigOverride != nil { - ocrParams = tCfg.OCRConfigOverride(ocrParams) + if testCfg.CreateJobAndContracts { + deployedEnv := changeset.NewEnvironmentWithJobsAndContracts(t, testCfg, dockerEnv) + require.NotNil(t, dockerEnv.testEnv, "empty docker environment") + return deployedEnv, devenv.RMNCluster{} } - chainConfigs[chain] = ocrParams + if testCfg.CreateJob { + deployedEnv := changeset.NewEnvironmentWithJobs(t, testCfg, dockerEnv) + require.NotNil(t, dockerEnv.testEnv, "empty docker environment") + return deployedEnv, devenv.RMNCluster{} + } + deployedEnv := changeset.NewEnvironment(t, testCfg, dockerEnv) + require.NotNil(t, dockerEnv.testEnv, "empty docker environment") + return deployedEnv, devenv.RMNCluster{} + default: + require.Failf(t, "Type %s not supported in integration tests choose between %s and %s", string(testCfg.Type), changeset.Memory, changeset.Docker) } - - // Deploy second set of changesets to deploy and configure the CCIP contracts. - env, err = commonchangeset.ApplyChangesets(t, env, timelockContractsPerChain, []commonchangeset.ChangesetApplication{ - { - Changeset: commonchangeset.WrapChangeSet(changeset.ConfigureNewChains), - Config: changeset.NewChainsConfig{ - HomeChainSel: homeChainSel, - FeedChainSel: feedSel, - ChainConfigByChain: chainConfigs, - }, - }, - { - Changeset: commonchangeset.WrapChangeSet(changeset.CCIPCapabilityJobspec), - }, - }) - require.NoError(t, err) - - // Ensure capreg logs are up to date. - changeset.ReplayLogs(t, e.Offchain, replayBlocks) - - return changeset.DeployedEnv{ - Env: env, - HomeChainSel: homeChainSel, - FeedChainSel: feedSel, - ReplayBlocks: replayBlocks, - Users: users, - }, testEnv, cfg -} - -func NewLocalDevEnvironmentWithRMN( - t *testing.T, - lggr logger.Logger, - numRmnNodes int, -) (changeset.DeployedEnv, devenv.RMNCluster) { - tenv, dockerenv, testCfg := NewLocalDevEnvironmentWithDefaultPrice(t, lggr, nil) - l := logging.GetTestLogger(t) - config := GenerateTestRMNConfig(t, numRmnNodes, tenv, MustNetworksToRPCMap(dockerenv.EVMNetworks)) - require.NotNil(t, testCfg.CCIP) - rmnCluster, err := devenv.NewRMNCluster( - t, l, - []string{dockerenv.DockerNetwork.ID}, - config, - testCfg.CCIP.RMNConfig.GetProxyImage(), - testCfg.CCIP.RMNConfig.GetProxyVersion(), - testCfg.CCIP.RMNConfig.GetAFN2ProxyImage(), - testCfg.CCIP.RMNConfig.GetAFN2ProxyVersion(), - dockerenv.LogStream, - ) - require.NoError(t, err) - return tenv, *rmnCluster + return changeset.DeployedEnv{}, devenv.RMNCluster{} } func MustNetworksToRPCMap(evmNetworks []*blockchain.EVMNetwork) map[uint64]string {