From a8e009fe8a74c505a244bb879dba1704c4d14637 Mon Sep 17 00:00:00 2001 From: "Abdelrahman Soliman (Boda)" <2677789+asoliman92@users.noreply.github.com> Date: Wed, 3 Jul 2024 23:05:15 +0400 Subject: [PATCH] Moving common integration test functions into helpers (#1138) Moving common integration test functions into helpers and making some tweaks to be reused and be more generic. --- .../launcher/integration_test.go | 312 ++---------------- .../ccipcapability/launcher/launcher.go | 9 +- .../types/mocks/home_chain_reader.go | 54 ++- core/services/ccipcapability/types/types.go | 8 - .../home_chain/home_chain_test.go | 193 ++--------- .../integration_helpers.go | 280 ++++++++++++++-- 6 files changed, 358 insertions(+), 498 deletions(-) diff --git a/core/services/ccipcapability/launcher/integration_test.go b/core/services/ccipcapability/launcher/integration_test.go index 5c6adc4308..da04ef4cbc 100644 --- a/core/services/ccipcapability/launcher/integration_test.go +++ b/core/services/ccipcapability/launcher/integration_test.go @@ -1,304 +1,47 @@ package launcher import ( - "context" - "encoding/json" - "fmt" - "math/big" "testing" "time" - "github.com/ethereum/go-ethereum/accounts/abi/bind" - "github.com/ethereum/go-ethereum/accounts/abi/bind/backends" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core" "github.com/onsi/gomega" "github.com/stretchr/testify/require" - ccipreader "github.com/smartcontractkit/chainlink-ccip/pkg/reader" - "github.com/smartcontractkit/chainlink-common/pkg/types" - - "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" - "github.com/smartcontractkit/chainlink/v2/core/chains/evm/client" - "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/ccip_config" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/ocr3_config_encoder" - kcr "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/keystone/generated/capabilities_registry" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" - "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" cctypes "github.com/smartcontractkit/chainlink/v2/core/services/ccipcapability/types" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/p2pkey" + it "github.com/smartcontractkit/chainlink/v2/core/services/ocr3/plugins/ccip_integration_tests" "github.com/smartcontractkit/chainlink/v2/core/services/registrysyncer" - "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm" - evmrelaytypes "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/types" ) -const ( - chainA uint64 = 1 - fChainA uint8 = 1 - - chainB uint64 = 2 - fChainB uint8 = 2 - - chainC uint64 = 3 - fChainC uint8 = 3 - - ccipCapabilityLabelledName = "ccip" - ccipCapabilityVersion = "v1.0" -) - -type testUniverse struct { - transactor *bind.TransactOpts - backend *backends.SimulatedBackend - capReg *kcr.CapabilitiesRegistry - cc *ccip_config.CCIPConfig - testingT *testing.T - lp logpoller.LogPoller - simClient client.Client -} - -func newTestUniverse(t *testing.T) testUniverse { - transactor := testutils.MustNewSimTransactor(t) - backend := backends.NewSimulatedBackend(core.GenesisAlloc{ - transactor.From: {Balance: assets.Ether(1000).ToInt()}, - }, 30e6) - - crAddress, _, _, err := kcr.DeployCapabilitiesRegistry(transactor, backend) - require.NoError(t, err) - backend.Commit() - - capReg, err := kcr.NewCapabilitiesRegistry(crAddress, backend) - require.NoError(t, err) - - ccAddress, _, _, err := ccip_config.DeployCCIPConfig(transactor, backend, crAddress) - require.NoError(t, err) - backend.Commit() - - cc, err := ccip_config.NewCCIPConfig(ccAddress, backend) - require.NoError(t, err) - - return testUniverse{ - transactor: transactor, - backend: backend, - capReg: capReg, - cc: cc, - testingT: t, - } -} - -func (t testUniverse) NewContractReader(ctx context.Context, cfg []byte) (types.ContractReader, error) { - var config evmrelaytypes.ChainReaderConfig - err := json.Unmarshal(cfg, &config) - require.NoError(t.testingT, err) - return evm.NewChainReaderService(ctx, logger.TestLogger(t.testingT), t.lp, t.simClient, config) -} - -func addCapabilities( - t *testing.T, - backend *backends.SimulatedBackend, - transactor *bind.TransactOpts, - capReg *kcr.CapabilitiesRegistry, - capConfAddress common.Address) [][32]byte { - // add the CCIP capability to the registry - _, err := capReg.AddCapabilities(transactor, []kcr.CapabilitiesRegistryCapability{ - { - LabelledName: ccipCapabilityLabelledName, - Version: ccipCapabilityVersion, - CapabilityType: 0, - ResponseType: 0, - ConfigurationContract: capConfAddress, - }, - }) - require.NoError(t, err, "failed to add capability to registry") - backend.Commit() - - ccipCapabilityID, err := capReg.GetHashedCapabilityId(nil, ccipCapabilityLabelledName, ccipCapabilityVersion) - require.NoError(t, err) - - // Add the p2p ids of the ccip nodes - var p2pIDs [][32]byte - for i := 0; i < 4; i++ { - p2pID := p2pkey.MustNewV2XXXTestingOnly(big.NewInt(int64(i + 1))).PeerID() - p2pIDs = append(p2pIDs, p2pID) - _, err = capReg.AddNodeOperators(transactor, []kcr.CapabilitiesRegistryNodeOperator{ - { - Admin: transactor.From, - Name: fmt.Sprintf("nop-%d", i), - }, - }) - require.NoError(t, err) - backend.Commit() - - // get the node operator id from the event - it, err := capReg.FilterNodeOperatorAdded(nil, nil, nil) - require.NoError(t, err) - var nodeOperatorID uint32 - for it.Next() { - if it.Event.Name == fmt.Sprintf("nop-%d", i) { - nodeOperatorID = it.Event.NodeOperatorId - break - } - } - require.NotZero(t, nodeOperatorID) - - _, err = capReg.AddNodes(transactor, []kcr.CapabilitiesRegistryNodeParams{ - { - NodeOperatorId: nodeOperatorID, - Signer: testutils.Random32Byte(), - P2pId: p2pID, - HashedCapabilityIds: [][32]byte{ccipCapabilityID}, - }, - }) - require.NoError(t, err) - backend.Commit() - - // verify that the node was added successfully - nodeInfo, err := capReg.GetNode(nil, p2pID) - require.NoError(t, err) - - require.Equal(t, nodeOperatorID, nodeInfo.NodeOperatorId) - require.Equal(t, p2pID[:], nodeInfo.P2pId[:]) - } - return p2pIDs -} - -func setupConfigInfo(chainSelector uint64, readers [][32]byte, fChain uint8, cfg []byte) ccip_config.CCIPConfigTypesChainConfigInfo { - return ccip_config.CCIPConfigTypesChainConfigInfo{ - ChainSelector: chainSelector, - ChainConfig: ccip_config.CCIPConfigTypesChainConfig{ - Readers: readers, - FChain: fChain, - Config: cfg, - }, - } -} - -func newHomeChainReader(t *testing.T, logPoller logpoller.LogPoller, client client.Client, ccAddress common.Address) cctypes.HomeChainReader { - cfg := evmrelaytypes.ChainReaderConfig{ - Contracts: map[string]evmrelaytypes.ChainContractReader{ - "CCIPConfig": { - ContractABI: ccip_config.CCIPConfigMetaData.ABI, - Configs: map[string]*evmrelaytypes.ChainReaderDefinition{ - "getAllChainConfigs": { - ChainSpecificName: "getAllChainConfigs", - }, - "getOCRConfig": { - ChainSpecificName: "getOCRConfig", - }, - }, - }, - }, - } - cr, err := evm.NewChainReaderService(testutils.Context(t), logger.TestLogger(t), logPoller, client, cfg) - require.NoError(t, err) - - err = cr.Bind(testutils.Context(t), []types.BoundContract{ - { - Address: ccAddress.String(), - Name: "CCIPConfig", - }, - }) - require.NoError(t, err) - require.NoError(t, cr.Start(testutils.Context(t))) - - hcr := ccipreader.NewHomeChainReader(cr, logger.TestLogger(t), time.Second) - require.NoError(t, hcr.Start(testutils.Context(t))) - - return hcr -} - -func addDONToRegistry(t *testing.T, - transactor *bind.TransactOpts, - ccipCapabilityID [32]byte, - chainSelector uint64, - f uint8, - capReg *kcr.CapabilitiesRegistry, - backend *backends.SimulatedBackend, - bootstrapP2PID [32]byte, - p2pIDs [][32]byte, -) { - tabi, err := ocr3_config_encoder.IOCR3ConfigEncoderMetaData.GetAbi() - require.NoError(t, err) - - var ( - signers [][]byte - transmitters [][]byte - ) - for range p2pIDs { - signers = append(signers, testutils.NewAddress().Bytes()) - transmitters = append(transmitters, testutils.NewAddress().Bytes()) - } - - var ocr3Configs []ocr3_config_encoder.CCIPConfigTypesOCR3Config - for _, pluginType := range []cctypes.PluginType{cctypes.PluginTypeCCIPCommit, cctypes.PluginTypeCCIPExec} { - ocr3Configs = append(ocr3Configs, ocr3_config_encoder.CCIPConfigTypesOCR3Config{ - PluginType: uint8(pluginType), - ChainSelector: chainSelector, - F: f, - OffchainConfigVersion: 30, - OfframpAddress: testutils.NewAddress().Bytes(), - BootstrapP2PIds: [][32]byte{bootstrapP2PID}, - P2pIds: p2pIDs, - Signers: signers, - Transmitters: transmitters, - OffchainConfig: []byte("offchain config"), - }) - } - - encodedCall, err := tabi.Pack("exposeOCR3Config", ocr3Configs) - require.NoError(t, err) - - // Trim first four bytes to remove function selector. - encodedConfigs := encodedCall[4:] - - _, err = capReg.AddDON(transactor, p2pIDs, []kcr.CapabilitiesRegistryCapabilityConfiguration{ - { - CapabilityId: ccipCapabilityID, - Config: encodedConfigs, - }, - }, false, false, f) - require.NoError(t, err) - backend.Commit() -} - func TestIntegration_Launcher(t *testing.T) { ctx := testutils.Context(t) lggr := logger.TestLogger(t) - uni := newTestUniverse(t) - - db := pgtest.NewSqlxDB(t) - lpOpts := logpoller.Opts{ - PollPeriod: time.Millisecond, - FinalityDepth: 0, - BackfillBatchSize: 10, - RpcBatchSize: 10, - KeepFinalizedBlocksDepth: 100000, + uni := it.NewTestUniverse(ctx, t, lggr) + // We need 3*f + 1 p2pIDs to have enough nodes to bootstrap + var arr []int64 + n := int(it.FChainA*3 + 1) + for i := 0; i <= n; i++ { + arr = append(arr, int64(i)) } - cl := client.NewSimulatedBackendClient(t, uni.backend, big.NewInt(1337)) - lp := logpoller.NewLogPoller(logpoller.NewORM(big.NewInt(1337), db, lggr), cl, logger.NullLogger, lpOpts) - require.NoError(t, lp.Start(ctx)) - t.Cleanup(func() { require.NoError(t, lp.Close()) }) - - uni.lp = lp - uni.simClient = cl + p2pIDs := it.P2pIDsFromInts(arr) + uni.AddCapability(p2pIDs) - p2pIDs := addCapabilities(t, uni.backend, uni.transactor, uni.capReg, uni.cc.Address()) - - regSyncer, err := registrysyncer.New(lggr, uni, uni.capReg.Address().String()) + regSyncer, err := registrysyncer.New(lggr, uni, uni.CapReg.Address().String()) require.NoError(t, err) - hcr := newHomeChainReader(t, lp, cl, uni.cc.Address()) + hcr := uni.HomeChainReader launcher := New( - ccipCapabilityVersion, - ccipCapabilityLabelledName, + it.CcipCapabilityVersion, + it.CcipCapabilityLabelledName, p2pIDs[0], logger.TestLogger(t), hcr, &oracleCreatorPrints{ t: t, }, - 3*time.Second, + 1*time.Second, ) regSyncer.AddLauncher(launcher) @@ -307,32 +50,27 @@ func TestIntegration_Launcher(t *testing.T) { t.Cleanup(func() { require.NoError(t, regSyncer.Close()) }) t.Cleanup(func() { require.NoError(t, launcher.Close()) }) - chainAConf := setupConfigInfo(chainA, p2pIDs, fChainA, []byte("chainA")) - chainBConf := setupConfigInfo(chainB, p2pIDs[1:], fChainB, []byte("chainB")) - chainCConf := setupConfigInfo(chainC, p2pIDs[2:], fChainC, []byte("chainC")) + chainAConf := it.SetupConfigInfo(it.ChainA, p2pIDs, it.FChainA, []byte("ChainA")) + chainBConf := it.SetupConfigInfo(it.ChainB, p2pIDs[1:], it.FChainB, []byte("ChainB")) + chainCConf := it.SetupConfigInfo(it.ChainC, p2pIDs[2:], it.FChainC, []byte("ChainC")) inputConfig := []ccip_config.CCIPConfigTypesChainConfigInfo{ chainAConf, chainBConf, chainCConf, } - _, err = uni.cc.ApplyChainConfigUpdates(uni.transactor, nil, inputConfig) + _, err = uni.CcipCfg.ApplyChainConfigUpdates(uni.Transactor, nil, inputConfig) require.NoError(t, err) - uni.backend.Commit() + uni.Backend.Commit() - ccipCapabilityID, err := uni.capReg.GetHashedCapabilityId(nil, ccipCapabilityLabelledName, ccipCapabilityVersion) + ccipCapabilityID, err := uni.CapReg.GetHashedCapabilityId(nil, it.CcipCapabilityLabelledName, it.CcipCapabilityVersion) require.NoError(t, err) - addDONToRegistry( - t, - uni.transactor, + uni.AddDONToRegistry( ccipCapabilityID, - chainA, - fChainA, - uni.capReg, - uni.backend, - p2pIDs[1], // we're not bootstrapping - p2pIDs, - ) + it.ChainA, + it.FChainA, + p2pIDs[1], + p2pIDs) gomega.NewWithT(t).Eventually(func() bool { return len(launcher.runningDONIDs()) == 1 diff --git a/core/services/ccipcapability/launcher/launcher.go b/core/services/ccipcapability/launcher/launcher.go index fb46fe40c0..66aaef8cc0 100644 --- a/core/services/ccipcapability/launcher/launcher.go +++ b/core/services/ccipcapability/launcher/launcher.go @@ -13,6 +13,7 @@ import ( ccipreaderpkg "github.com/smartcontractkit/chainlink-ccip/pkg/reader" "github.com/smartcontractkit/chainlink-common/pkg/services" + ccipreader "github.com/smartcontractkit/chainlink-ccip/pkg/reader" kcr "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/keystone/generated/capabilities_registry" "github.com/smartcontractkit/chainlink/v2/core/logger" cctypes "github.com/smartcontractkit/chainlink/v2/core/services/ccipcapability/types" @@ -31,7 +32,7 @@ func New( capabilityLabelledName string, p2pID ragep2ptypes.PeerID, lggr logger.Logger, - homeChainReader cctypes.HomeChainReader, + homeChainReader ccipreader.HomeChain, oracleCreator cctypes.OracleCreator, tickInterval time.Duration, ) *launcher { @@ -60,7 +61,7 @@ type launcher struct { capabilityLabelledName string p2pID ragep2ptypes.PeerID lggr logger.Logger - homeChainReader cctypes.HomeChainReader + homeChainReader ccipreader.HomeChain stopChan chan struct{} // latestState is the latest capability registry state received from the syncer. latestState registrysyncer.State @@ -284,7 +285,7 @@ func (l *launcher) processRemoved(removed map[registrysyncer.DonID]kcr.Capabilit func updateDON( lggr logger.Logger, p2pID ragep2ptypes.PeerID, - homeChainReader cctypes.HomeChainReader, + homeChainReader ccipreader.HomeChain, oracleCreator cctypes.OracleCreator, prevDeployment ccipDeployment, don kcr.CapabilitiesRegistryDONInfo, @@ -358,7 +359,7 @@ func createFutureBlueGreenDeployment( func createDON( lggr logger.Logger, p2pID ragep2ptypes.PeerID, - homeChainReader cctypes.HomeChainReader, + homeChainReader ccipreader.HomeChain, oracleCreator cctypes.OracleCreator, don kcr.CapabilitiesRegistryDONInfo, ) (*ccipDeployment, error) { diff --git a/core/services/ccipcapability/types/mocks/home_chain_reader.go b/core/services/ccipcapability/types/mocks/home_chain_reader.go index b2576324c8..a5a581a1d2 100644 --- a/core/services/ccipcapability/types/mocks/home_chain_reader.go +++ b/core/services/ccipcapability/types/mocks/home_chain_reader.go @@ -3,19 +3,67 @@ package mocks import ( "context" - mock "github.com/stretchr/testify/mock" + mapset "github.com/deckarep/golang-set/v2" + "github.com/stretchr/testify/mock" ccipreaderpkg "github.com/smartcontractkit/chainlink-ccip/pkg/reader" - cctypes "github.com/smartcontractkit/chainlink/v2/core/services/ccipcapability/types" + cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccipocr3" + + "github.com/smartcontractkit/libocr/ragep2p/types" ) -var _ cctypes.HomeChainReader = (*HomeChainReader)(nil) +var _ ccipreaderpkg.HomeChain = (*HomeChainReader)(nil) type HomeChainReader struct { mock.Mock } +func (_m *HomeChainReader) GetChainConfig(chainSelector cciptypes.ChainSelector) (ccipreaderpkg.ChainConfig, error) { + //TODO implement me + panic("implement me") +} + +func (_m *HomeChainReader) GetAllChainConfigs() (map[cciptypes.ChainSelector]ccipreaderpkg.ChainConfig, error) { + //TODO implement me + panic("implement me") +} + +func (_m *HomeChainReader) GetSupportedChainsForPeer(id types.PeerID) (mapset.Set[cciptypes.ChainSelector], error) { + //TODO implement me + panic("implement me") +} + +func (_m *HomeChainReader) GetKnownCCIPChains() (mapset.Set[cciptypes.ChainSelector], error) { + //TODO implement me + panic("implement me") +} + +func (_m *HomeChainReader) GetFChain() (map[cciptypes.ChainSelector]int, error) { + //TODO implement me + panic("implement me") +} + +func (_m *HomeChainReader) Start(ctx context.Context) error { + //TODO implement me + panic("implement me") +} + +func (_m *HomeChainReader) Close() error { + //TODO implement me + panic("implement me") +} + +func (_m *HomeChainReader) HealthReport() map[string]error { + //TODO implement me + panic("implement me") +} + +func (_m *HomeChainReader) Name() string { + //TODO implement me + panic("implement me") +} + // GetOCRConfigs provides a mock function with given fields: ctx, donID, pluginType func (_m *HomeChainReader) GetOCRConfigs(ctx context.Context, donID uint32, pluginType uint8) ([]ccipreaderpkg.OCR3ConfigWithMeta, error) { ret := _m.Called(ctx, donID, pluginType) diff --git a/core/services/ccipcapability/types/types.go b/core/services/ccipcapability/types/types.go index da99785896..50e4fb19f4 100644 --- a/core/services/ccipcapability/types/types.go +++ b/core/services/ccipcapability/types/types.go @@ -1,20 +1,12 @@ package types import ( - "context" - ccipreaderpkg "github.com/smartcontractkit/chainlink-ccip/pkg/reader" ) // OCR3ConfigWithMeta is a type alias in order to generate correct mocks for the OracleCreator interface. type OCR3ConfigWithMeta ccipreaderpkg.OCR3ConfigWithMeta -type HomeChainReader interface { - // GetOCRConfigs Gets the OCR3Configs for a given donID and pluginType - GetOCRConfigs(ctx context.Context, donID uint32, pluginType uint8) ([]ccipreaderpkg.OCR3ConfigWithMeta, error) - Ready() error -} - // PluginType represents the type of CCIP plugin. // It mirrors the OCRPluginType in Internal.sol. type PluginType uint8 diff --git a/core/services/ocr3/plugins/ccip_integration_tests/home_chain/home_chain_test.go b/core/services/ocr3/plugins/ccip_integration_tests/home_chain/home_chain_test.go index a84786328c..ab8629f8c1 100644 --- a/core/services/ocr3/plugins/ccip_integration_tests/home_chain/home_chain_test.go +++ b/core/services/ocr3/plugins/ccip_integration_tests/home_chain/home_chain_test.go @@ -1,92 +1,52 @@ package home_chain import ( - "fmt" - "math/big" "testing" "time" mapset "github.com/deckarep/golang-set/v2" - "github.com/ethereum/go-ethereum/accounts/abi/bind" - "github.com/ethereum/go-ethereum/accounts/abi/bind/backends" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/core" "github.com/onsi/gomega" libocrtypes "github.com/smartcontractkit/libocr/ragep2p/types" ccipreader "github.com/smartcontractkit/chainlink-ccip/pkg/reader" cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccipocr3" - "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" capcfg "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/ccip_config" - "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/keystone/generated/capabilities_registry" "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/logger" - "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/p2pkey" - helpers "github.com/smartcontractkit/chainlink/v2/core/services/ocr3/plugins/ccip_integration_tests" + it "github.com/smartcontractkit/chainlink/v2/core/services/ocr3/plugins/ccip_integration_tests" "github.com/stretchr/testify/require" - - evmtypes "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/types" -) - -const ( - chainA uint64 = 1 - fChainA uint8 = 1 - - chainB uint64 = 2 - fChainB uint8 = 2 - - chainC uint64 = 3 - fChainC uint8 = 3 ) func TestHomeChainReader(t *testing.T) { - // Initialize chainReader - cfg := evmtypes.ChainReaderConfig{ - Contracts: map[string]evmtypes.ChainContractReader{ - "CCIPConfig": { - ContractABI: capcfg.CCIPConfigMetaData.ABI, - Configs: map[string]*evmtypes.ChainReaderDefinition{ - "getAllChainConfigs": { - ChainSpecificName: "getAllChainConfigs", - }, - }, - }, - }, + ctx := testutils.Context(t) + lggr := logger.TestLogger(t) + uni := it.NewTestUniverse(ctx, t, lggr) + // We need 3*f + 1 p2pIDs to have enough nodes to bootstrap + var arr []int64 + n := int(it.FChainA*3 + 1) + for i := 0; i <= n; i++ { + arr = append(arr, int64(i)) } - //============================Setup Backend=================================== - transactor := testutils.MustNewSimTransactor(t) - backend := backends.NewSimulatedBackend(core.GenesisAlloc{ - transactor.From: {Balance: assets.Ether(1000).ToInt()}, - }, 30e6) - //==============================Setup Contracts - Add capabilities================================= - capRegAddress, capRegContract, err := prepareCapabilityRegistry(t, backend, transactor) - require.NoError(t, err) - capConfAddress, capConfContract, err := prepareCCIPCapabilityConfig(t, backend, transactor, capRegAddress) - require.NoError(t, err) - p2pIDS := addCapabilities(t, backend, transactor, capRegContract, capConfAddress) + p2pIDs := it.P2pIDsFromInts(arr) + uni.AddCapability(p2pIDs) //==============================Apply configs to Capability Contract================================= - chainAConf := setupConfigInfo(chainA, p2pIDS, fChainA, []byte("chainA")) - chainBConf := setupConfigInfo(chainB, p2pIDS[1:], fChainB, []byte("chainB")) - chainCConf := setupConfigInfo(chainC, p2pIDS[2:], fChainC, []byte("chainC")) + chainAConf := it.SetupConfigInfo(it.ChainA, p2pIDs, it.FChainA, []byte("ChainA")) + chainBConf := it.SetupConfigInfo(it.ChainB, p2pIDs[1:], it.FChainB, []byte("ChainB")) + chainCConf := it.SetupConfigInfo(it.ChainC, p2pIDs[2:], it.FChainC, []byte("ChainC")) inputConfig := []capcfg.CCIPConfigTypesChainConfigInfo{ chainAConf, chainBConf, chainCConf, } - _, err = capConfContract.ApplyChainConfigUpdates(transactor, nil, inputConfig) + _, err := uni.CcipCfg.ApplyChainConfigUpdates(uni.Transactor, nil, inputConfig) require.NoError(t, err) - backend.Commit() + uni.Backend.Commit() //================================Setup HomeChainReader=============================== - ctx := testutils.Context(t) - testData := helpers.SetupReaderTestData(ctx, t, backend, capConfAddress, cfg, "CCIPConfig") - chainReader := testData.ChainReader - logPoller := testData.LogPoller - require.NoError(t, err) - pollDuration := 5 * time.Millisecond - homeChain := ccipreader.NewHomeChainReader(chainReader, logger.TestLogger(t), pollDuration) - require.NoError(t, homeChain.Start(ctx)) + + pollDuration := time.Second + homeChain := uni.HomeChainReader gomega.NewWithT(t).Eventually(func() bool { configs, _ := homeChain.GetAllChainConfigs() @@ -106,18 +66,17 @@ func TestHomeChainReader(t *testing.T) { require.NoError(t, err) require.Equal(t, expectedChainConfigs, configs) //=================================Remove ChainC from OnChainConfig========================================= - _, err = capConfContract.ApplyChainConfigUpdates(transactor, []uint64{chainC}, nil) + _, err = uni.CcipCfg.ApplyChainConfigUpdates(uni.Transactor, []uint64{it.ChainC}, nil) require.NoError(t, err) - backend.Commit() + uni.Backend.Commit() time.Sleep(pollDuration * 5) // Wait for the chain reader to update configs, err = homeChain.GetAllChainConfigs() require.NoError(t, err) - delete(expectedChainConfigs, cciptypes.ChainSelector(chainC)) + delete(expectedChainConfigs, cciptypes.ChainSelector(it.ChainC)) require.Equal(t, expectedChainConfigs, configs) //================================Close HomeChain Reader=============================== - require.NoError(t, homeChain.Close()) - require.NoError(t, logPoller.Close()) - require.NoError(t, chainReader.Close()) + //require.NoError(t, homeChain.Close()) + //require.NoError(t, uni.LogPoller.Close()) t.Logf("homchain reader successfully closed") } @@ -128,107 +87,3 @@ func toPeerIDs(readers [][32]byte) mapset.Set[libocrtypes.PeerID] { } return peerIDs } - -func setupConfigInfo(chainSelector uint64, readers [][32]byte, fChain uint8, cfg []byte) capcfg.CCIPConfigTypesChainConfigInfo { - return capcfg.CCIPConfigTypesChainConfigInfo{ - ChainSelector: chainSelector, - ChainConfig: capcfg.CCIPConfigTypesChainConfig{ - Readers: readers, - FChain: fChain, - Config: cfg, - }, - } -} - -func prepareCCIPCapabilityConfig(t *testing.T, backend *backends.SimulatedBackend, transactor *bind.TransactOpts, capRegAddress common.Address) (common.Address, *capcfg.CCIPConfig, error) { - ccAddress, _, _, err := capcfg.DeployCCIPConfig(transactor, backend, capRegAddress) - require.NoError(t, err) - backend.Commit() - - contract, err := capcfg.NewCCIPConfig(ccAddress, backend) - require.NoError(t, err) - backend.Commit() - - return ccAddress, contract, nil -} - -func prepareCapabilityRegistry(t *testing.T, backend *backends.SimulatedBackend, transactor *bind.TransactOpts) (common.Address, *capabilities_registry.CapabilitiesRegistry, error) { - crAddress, _, _, err := capabilities_registry.DeployCapabilitiesRegistry(transactor, backend) - require.NoError(t, err) - backend.Commit() - - capReg, err := capabilities_registry.NewCapabilitiesRegistry(crAddress, backend) - require.NoError(t, err) - backend.Commit() - - return crAddress, capReg, nil -} - -func addCapabilities( - t *testing.T, - backend *backends.SimulatedBackend, - transactor *bind.TransactOpts, - capReg *capabilities_registry.CapabilitiesRegistry, - capConfAddress common.Address) [][32]byte { - // add the CCIP capability to the registry - _, err := capReg.AddCapabilities(transactor, []capabilities_registry.CapabilitiesRegistryCapability{ - { - LabelledName: "ccip", - Version: "v1.0", - CapabilityType: 0, - ResponseType: 0, - ConfigurationContract: capConfAddress, - }, - }) - require.NoError(t, err, "failed to add capability to registry") - backend.Commit() - - ccipCapabilityID, err := capReg.GetHashedCapabilityId(nil, "ccip", "v1.0") - require.NoError(t, err) - - // Add the p2p ids of the ccip nodes - var p2pIDs [][32]byte - for i := 0; i < 4; i++ { - p2pID := p2pkey.MustNewV2XXXTestingOnly(big.NewInt(int64(i + 1))).PeerID() - p2pIDs = append(p2pIDs, p2pID) - _, err = capReg.AddNodeOperators(transactor, []capabilities_registry.CapabilitiesRegistryNodeOperator{ - { - Admin: transactor.From, - Name: fmt.Sprintf("nop-%d", i), - }, - }) - require.NoError(t, err) - backend.Commit() - - // get the node operator id from the event - it, err := capReg.FilterNodeOperatorAdded(nil, nil, nil) - require.NoError(t, err) - var nodeOperatorID uint32 - for it.Next() { - if it.Event.Name == fmt.Sprintf("nop-%d", i) { - nodeOperatorID = it.Event.NodeOperatorId - break - } - } - require.NotZero(t, nodeOperatorID) - - _, err = capReg.AddNodes(transactor, []capabilities_registry.CapabilitiesRegistryNodeParams{ - { - NodeOperatorId: nodeOperatorID, - Signer: testutils.Random32Byte(), - P2pId: p2pID, - HashedCapabilityIds: [][32]byte{ccipCapabilityID}, - }, - }) - require.NoError(t, err) - backend.Commit() - - // verify that the node was added successfully - nodeInfo, err := capReg.GetNode(nil, p2pID) - require.NoError(t, err) - - require.Equal(t, nodeOperatorID, nodeInfo.NodeOperatorId) - require.Equal(t, p2pID[:], nodeInfo.P2pId[:]) - } - return p2pIDs -} diff --git a/core/services/ocr3/plugins/ccip_integration_tests/integration_helpers.go b/core/services/ocr3/plugins/ccip_integration_tests/integration_helpers.go index 9a30a7469f..b7e81cd2c9 100644 --- a/core/services/ocr3/plugins/ccip_integration_tests/integration_helpers.go +++ b/core/services/ocr3/plugins/ccip_integration_tests/integration_helpers.go @@ -2,14 +2,27 @@ package ccip_integration_tests import ( "context" + "encoding/json" + "fmt" "math/big" "testing" "time" + "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/accounts/abi/bind/backends" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core" - types2 "github.com/smartcontractkit/chainlink-common/pkg/types" + ccipreader "github.com/smartcontractkit/chainlink-ccip/pkg/reader" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/assets" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/ccip_config" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/ocr3_config_encoder" + kcr "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/keystone/generated/capabilities_registry" + "github.com/smartcontractkit/chainlink/v2/core/internal/testutils" + cctypes "github.com/smartcontractkit/chainlink/v2/core/services/ccipcapability/types" + "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/p2pkey" + + "github.com/smartcontractkit/chainlink-common/pkg/types" "github.com/stretchr/testify/require" @@ -18,33 +31,15 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm" - evmtypes "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/types" + evmrelaytypes "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/types" ) const chainID = 1337 -type TestSetupData struct { - LogPoller logpoller.LogPoller - ChainReader evm.ChainReaderService -} - -func SetupReaderTestData(ctx context.Context, t *testing.T, simulatedBackend *backends.SimulatedBackend, address common.Address, chainReaderConfig evmtypes.ChainReaderConfig, contractName string) TestSetupData { - lggr := logger.TestLogger(t) - db := pgtest.NewSqlxDB(t) - lpOpts := logpoller.Opts{ - PollPeriod: time.Millisecond, - FinalityDepth: 1, - BackfillBatchSize: 1, - RpcBatchSize: 1, - KeepFinalizedBlocksDepth: 10000, - } - cl := client.NewSimulatedBackendClient(t, simulatedBackend, big.NewInt(chainID)) - lp := logpoller.NewLogPoller(logpoller.NewORM(big.NewInt(chainID), db, lggr), cl, lggr, lpOpts) - require.NoError(t, lp.Start(ctx)) - - cr, err := evm.NewChainReaderService(ctx, lggr, lp, cl, chainReaderConfig) +func NewReader(t *testing.T, logPoller logpoller.LogPoller, client client.Client, address common.Address, chainReaderConfig evmrelaytypes.ChainReaderConfig, contractName string) types.ContractReader { + cr, err := evm.NewChainReaderService(testutils.Context(t), logger.TestLogger(t), logPoller, client, chainReaderConfig) require.NoError(t, err) - err = cr.Bind(ctx, []types2.BoundContract{ + err = cr.Bind(testutils.Context(t), []types.BoundContract{ { Address: address.String(), Name: contractName, @@ -52,14 +47,245 @@ func SetupReaderTestData(ctx context.Context, t *testing.T, simulatedBackend *ba }, }) require.NoError(t, err) - require.NoError(t, cr.Start(ctx)) + require.NoError(t, cr.Start(testutils.Context(t))) for { if err := cr.Ready(); err == nil { break } } - return TestSetupData{ - LogPoller: lp, - ChainReader: cr, + + return cr +} + +const ( + ChainA uint64 = 1 + FChainA uint8 = 1 + + ChainB uint64 = 2 + FChainB uint8 = 2 + + ChainC uint64 = 3 + FChainC uint8 = 3 + + CcipCapabilityLabelledName = "ccip" + CcipCapabilityVersion = "v1.0" +) + +type TestUniverse struct { + Transactor *bind.TransactOpts + Backend *backends.SimulatedBackend + CapReg *kcr.CapabilitiesRegistry + CcipCfg *ccip_config.CCIPConfig + TestingT *testing.T + LogPoller logpoller.LogPoller + SimClient client.Client + HomeChainReader ccipreader.HomeChain +} + +func NewTestUniverse(ctx context.Context, t *testing.T, lggr logger.Logger) TestUniverse { + transactor := testutils.MustNewSimTransactor(t) + backend := backends.NewSimulatedBackend(core.GenesisAlloc{ + transactor.From: {Balance: assets.Ether(1000).ToInt()}, + }, 30e6) + + crAddress, _, _, err := kcr.DeployCapabilitiesRegistry(transactor, backend) + require.NoError(t, err) + backend.Commit() + + capReg, err := kcr.NewCapabilitiesRegistry(crAddress, backend) + require.NoError(t, err) + + ccAddress, _, _, err := ccip_config.DeployCCIPConfig(transactor, backend, crAddress) + require.NoError(t, err) + backend.Commit() + + cc, err := ccip_config.NewCCIPConfig(ccAddress, backend) + require.NoError(t, err) + + db := pgtest.NewSqlxDB(t) + lpOpts := logpoller.Opts{ + PollPeriod: time.Millisecond, + FinalityDepth: 0, + BackfillBatchSize: 10, + RpcBatchSize: 10, + KeepFinalizedBlocksDepth: 100000, + } + cl := client.NewSimulatedBackendClient(t, backend, big.NewInt(chainID)) + lp := logpoller.NewLogPoller(logpoller.NewORM(big.NewInt(chainID), db, lggr), cl, logger.NullLogger, lpOpts) + require.NoError(t, lp.Start(ctx)) + t.Cleanup(func() { require.NoError(t, lp.Close()) }) + + hcr := NewHomeChainReader(t, lp, cl, ccAddress) + return TestUniverse{ + Transactor: transactor, + Backend: backend, + CapReg: capReg, + CcipCfg: cc, + TestingT: t, + SimClient: cl, + LogPoller: lp, + HomeChainReader: hcr, + } +} + +func (t TestUniverse) NewContractReader(ctx context.Context, cfg []byte) (types.ContractReader, error) { + var config evmrelaytypes.ChainReaderConfig + err := json.Unmarshal(cfg, &config) + require.NoError(t.TestingT, err) + return evm.NewChainReaderService(ctx, logger.TestLogger(t.TestingT), t.LogPoller, t.SimClient, config) +} + +func P2pIDsFromInts(ints []int64) [][32]byte { + var p2pIDs [][32]byte + for _, i := range ints { + p2pID := p2pkey.MustNewV2XXXTestingOnly(big.NewInt(i)).PeerID() + p2pIDs = append(p2pIDs, p2pID) + } + return p2pIDs +} + +func (t *TestUniverse) AddCapability(p2pIDs [][32]byte) { + _, err := t.CapReg.AddCapabilities(t.Transactor, []kcr.CapabilitiesRegistryCapability{ + { + LabelledName: CcipCapabilityLabelledName, + Version: CcipCapabilityVersion, + CapabilityType: 0, + ResponseType: 0, + ConfigurationContract: t.CcipCfg.Address(), + }, + }) + require.NoError(t.TestingT, err, "failed to add capability to registry") + t.Backend.Commit() + + ccipCapabilityID, err := t.CapReg.GetHashedCapabilityId(nil, CcipCapabilityLabelledName, CcipCapabilityVersion) + require.NoError(t.TestingT, err) + + for i := 0; i < len(p2pIDs); i++ { + _, err = t.CapReg.AddNodeOperators(t.Transactor, []kcr.CapabilitiesRegistryNodeOperator{ + { + Admin: t.Transactor.From, + Name: fmt.Sprintf("nop-%d", i), + }, + }) + require.NoError(t.TestingT, err) + t.Backend.Commit() + + // get the node operator id from the event + it, err := t.CapReg.FilterNodeOperatorAdded(nil, nil, nil) + require.NoError(t.TestingT, err) + var nodeOperatorID uint32 + for it.Next() { + if it.Event.Name == fmt.Sprintf("nop-%d", i) { + nodeOperatorID = it.Event.NodeOperatorId + break + } + } + require.NotZero(t.TestingT, nodeOperatorID) + + _, err = t.CapReg.AddNodes(t.Transactor, []kcr.CapabilitiesRegistryNodeParams{ + { + NodeOperatorId: nodeOperatorID, + Signer: testutils.Random32Byte(), + P2pId: p2pIDs[i], + HashedCapabilityIds: [][32]byte{ccipCapabilityID}, + }, + }) + require.NoError(t.TestingT, err) + t.Backend.Commit() + + // verify that the node was added successfully + nodeInfo, err := t.CapReg.GetNode(nil, p2pIDs[i]) + require.NoError(t.TestingT, err) + + require.Equal(t.TestingT, nodeOperatorID, nodeInfo.NodeOperatorId) + require.Equal(t.TestingT, p2pIDs[i][:], nodeInfo.P2pId[:]) + } +} + +func NewHomeChainReader(t *testing.T, logPoller logpoller.LogPoller, client client.Client, ccAddress common.Address) ccipreader.HomeChain { + cfg := evmrelaytypes.ChainReaderConfig{ + Contracts: map[string]evmrelaytypes.ChainContractReader{ + "CCIPConfig": { + ContractABI: ccip_config.CCIPConfigMetaData.ABI, + Configs: map[string]*evmrelaytypes.ChainReaderDefinition{ + "getAllChainConfigs": { + ChainSpecificName: "getAllChainConfigs", + }, + "getOCRConfig": { + ChainSpecificName: "getOCRConfig", + }, + }, + }, + }, + } + + cr := NewReader(t, logPoller, client, ccAddress, cfg, "CCIPConfig") + + hcr := ccipreader.NewHomeChainReader(cr, logger.TestLogger(t), 500*time.Millisecond) + require.NoError(t, hcr.Start(testutils.Context(t))) + t.Cleanup(func() { require.NoError(t, hcr.Close()) }) + + return hcr +} + +func (t *TestUniverse) AddDONToRegistry( + ccipCapabilityID [32]byte, + chainSelector uint64, + f uint8, + bootstrapP2PID [32]byte, + p2pIDs [][32]byte, +) { + tabi, err := ocr3_config_encoder.IOCR3ConfigEncoderMetaData.GetAbi() + require.NoError(t.TestingT, err) + + var ( + signers [][]byte + transmitters [][]byte + ) + for range p2pIDs { + signers = append(signers, testutils.NewAddress().Bytes()) + transmitters = append(transmitters, testutils.NewAddress().Bytes()) + } + + var ocr3Configs []ocr3_config_encoder.CCIPConfigTypesOCR3Config + for _, pluginType := range []cctypes.PluginType{cctypes.PluginTypeCCIPCommit, cctypes.PluginTypeCCIPExec} { + ocr3Configs = append(ocr3Configs, ocr3_config_encoder.CCIPConfigTypesOCR3Config{ + PluginType: uint8(pluginType), + ChainSelector: chainSelector, + F: f, + OffchainConfigVersion: 30, + OfframpAddress: testutils.NewAddress().Bytes(), + BootstrapP2PIds: [][32]byte{bootstrapP2PID}, + P2pIds: p2pIDs, + Signers: signers, + Transmitters: transmitters, + OffchainConfig: []byte("offchain config"), + }) + } + + encodedCall, err := tabi.Pack("exposeOCR3Config", ocr3Configs) + require.NoError(t.TestingT, err) + + // Trim first four bytes to remove function selector. + encodedConfigs := encodedCall[4:] + + _, err = t.CapReg.AddDON(t.Transactor, p2pIDs, []kcr.CapabilitiesRegistryCapabilityConfiguration{ + { + CapabilityId: ccipCapabilityID, + Config: encodedConfigs, + }, + }, false, false, f) + require.NoError(t.TestingT, err) + t.Backend.Commit() +} + +func SetupConfigInfo(chainSelector uint64, readers [][32]byte, fChain uint8, cfg []byte) ccip_config.CCIPConfigTypesChainConfigInfo { + return ccip_config.CCIPConfigTypesChainConfigInfo{ + ChainSelector: chainSelector, + ChainConfig: ccip_config.CCIPConfigTypesChainConfig{ + Readers: readers, + FChain: fChain, + Config: cfg, + }, } }