diff --git a/.changeset/odd-hats-repeat.md b/.changeset/odd-hats-repeat.md new file mode 100644 index 00000000000..ce80b45caff --- /dev/null +++ b/.changeset/odd-hats-repeat.md @@ -0,0 +1,5 @@ +--- +"chainlink": patch +--- + +#internal fix the mock trigger to ensure events are sent diff --git a/.mockery.yaml b/.mockery.yaml index 8fab61a5b9d..abb3105b136 100644 --- a/.mockery.yaml +++ b/.mockery.yaml @@ -43,6 +43,10 @@ packages: github.com/smartcontractkit/chainlink/v2/core/bridges: interfaces: ORM: + github.com/smartcontractkit/chainlink/v2/core/capabilities/ccip/types: + interfaces: + CCIPOracle: + OracleCreator: github.com/smartcontractkit/chainlink/v2/core/capabilities/remote/types: interfaces: Dispatcher: diff --git a/LICENSE b/LICENSE index 4a10bfc38b0..3af9faa6c6f 100644 --- a/LICENSE +++ b/LICENSE @@ -24,7 +24,7 @@ THE SOFTWARE. *All content residing under (1) “/contracts/src/v0.8/ccip”; (2) -“/core/gethwrappers/ccip”; (3) “/core/services/ocr2/plugins/ccip” are licensed +“/core/gethwrappers/ccip”; (3) “/core/services/ocr2/plugins/ccip”; (4) "/core/capabilities/ccip" are licensed under “Business Source License 1.1” with a Change Date of May 23, 2027 and Change License to “MIT License” diff --git a/core/capabilities/ccip/ccip_integration_tests/helpers.go b/core/capabilities/ccip/ccip_integration_tests/helpers.go index 057e48b3e7b..7606c8bbebc 100644 --- a/core/capabilities/ccip/ccip_integration_tests/helpers.go +++ b/core/capabilities/ccip/ccip_integration_tests/helpers.go @@ -5,10 +5,13 @@ import ( "encoding/hex" "math/big" "sort" - "strconv" "testing" "time" + "github.com/smartcontractkit/chainlink-ccip/chainconfig" + "github.com/smartcontractkit/chainlink-ccip/pluginconfig" + commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" + "github.com/smartcontractkit/chainlink-common/pkg/types/ccipocr3" "github.com/smartcontractkit/chainlink/v2/core/capabilities/ccip/ccip_integration_tests/integrationhelpers" cctypes "github.com/smartcontractkit/chainlink/v2/core/capabilities/ccip/types" @@ -53,9 +56,27 @@ const ( CapabilityLabelledName = "ccip" CapabilityVersion = "v1.0.0" NodeOperatorID = 1 - // TODO: this is 8 hours now to match what is hardcoded in the exec plugin. - // Eventually this should drive what is set in the exec plugin. - FirstBlockAge = 8 * time.Hour + + // These constants drive what is set in the plugin offchain configs. + FirstBlockAge = 8 * time.Hour + RemoteGasPriceBatchWriteFrequency = 30 * time.Minute + BatchGasLimit = 6_500_000 + RelativeBoostPerWaitHour = 1.5 + InflightCacheExpiry = 10 * time.Minute + RootSnoozeTime = 30 * time.Minute + BatchingStrategyID = 0 + DeltaProgress = 30 * time.Second + DeltaResend = 10 * time.Second + DeltaInitial = 20 * time.Second + DeltaRound = 2 * time.Second + DeltaGrace = 2 * time.Second + DeltaCertifiedCommitRequest = 10 * time.Second + DeltaStage = 10 * time.Second + Rmax = 3 + MaxDurationQuery = 50 * time.Millisecond + MaxDurationObservation = 5 * time.Second + MaxDurationShouldAcceptAttestedReport = 10 * time.Second + MaxDurationShouldTransmitAcceptedReport = 10 * time.Second ) func e18Mult(amount uint64) *big.Int { @@ -412,11 +433,18 @@ func AddChainConfig( // Need to sort, otherwise _checkIsValidUniqueSubset onChain will fail sortP2PIDS(p2pIDs) // First Add ChainConfig that includes all p2pIDs as readers - chainConfig := integrationhelpers.SetupConfigInfo(chainSelector, p2pIDs, f, []byte(strconv.FormatUint(chainSelector, 10))) + encodedExtraChainConfig, err := chainconfig.EncodeChainConfig(chainconfig.ChainConfig{ + GasPriceDeviationPPB: ccipocr3.NewBigIntFromInt64(1000), + DAGasPriceDeviationPPB: ccipocr3.NewBigIntFromInt64(0), + FinalityDepth: 10, + OptimisticConfirmations: 1, + }) + require.NoError(t, err) + chainConfig := integrationhelpers.SetupConfigInfo(chainSelector, p2pIDs, f, encodedExtraChainConfig) inputConfig := []ccip_config.CCIPConfigTypesChainConfigInfo{ chainConfig, } - _, err := h.ccipConfig.ApplyChainConfigUpdates(h.owner, nil, inputConfig) + _, err = h.ccipConfig.ApplyChainConfigUpdates(h.owner, nil, inputConfig) require.NoError(t, err) h.backend.Commit() return chainConfig @@ -437,49 +465,71 @@ func (h *homeChain) AddDON( for range oracles { schedule = append(schedule, 1) } - signers, transmitters, f, _, offchainConfigVersion, offchainConfig, err := ocr3confighelper.ContractSetConfigArgsForTests( - 30*time.Second, // deltaProgress - 10*time.Second, // deltaResend - 20*time.Second, // deltaInitial - 2*time.Second, // deltaRound - 2*time.Second, // deltaGrace - 10*time.Second, // deltaCertifiedCommitRequest TODO: whats a good value for this? - 10*time.Second, // deltaStage - 3, // rmax - schedule, - oracles, - []byte{}, // empty offchain config - 50*time.Millisecond, // maxDurationQuery - 5*time.Second, // maxDurationObservation - 10*time.Second, // maxDurationShouldAcceptAttestedReport - 10*time.Second, // maxDurationShouldTransmitAcceptedReport - int(f), - []byte{}) // empty OnChainConfig - require.NoError(t, err, "failed to create contract config") tabi, err := ocr3_config_encoder.IOCR3ConfigEncoderMetaData.GetAbi() require.NoError(t, err) - signersBytes := make([][]byte, len(signers)) - for i, signer := range signers { - signersBytes[i] = signer - } - - transmittersBytes := make([][]byte, len(transmitters)) - for i, transmitter := range transmitters { - // anotherErr because linting doesn't want to shadow err - parsed, anotherErr := common.ParseHexOrString(string(transmitter)) - require.NoError(t, anotherErr) - transmittersBytes[i] = parsed - } - // Add DON on capability registry contract var ocr3Configs []ocr3_config_encoder.CCIPConfigTypesOCR3Config for _, pluginType := range []cctypes.PluginType{cctypes.PluginTypeCCIPCommit, cctypes.PluginTypeCCIPExec} { + var encodedOffchainConfig []byte + var err2 error + if pluginType == cctypes.PluginTypeCCIPCommit { + encodedOffchainConfig, err2 = pluginconfig.EncodeCommitOffchainConfig(pluginconfig.CommitOffchainConfig{ + RemoteGasPriceBatchWriteFrequency: *commonconfig.MustNewDuration(RemoteGasPriceBatchWriteFrequency), + // TODO: implement token price writes + // TokenPriceBatchWriteFrequency: *commonconfig.MustNewDuration(tokenPriceBatchWriteFrequency), + }) + require.NoError(t, err2) + } else { + encodedOffchainConfig, err2 = pluginconfig.EncodeExecuteOffchainConfig(pluginconfig.ExecuteOffchainConfig{ + BatchGasLimit: BatchGasLimit, + RelativeBoostPerWaitHour: RelativeBoostPerWaitHour, + MessageVisibilityInterval: *commonconfig.MustNewDuration(FirstBlockAge), + InflightCacheExpiry: *commonconfig.MustNewDuration(InflightCacheExpiry), + RootSnoozeTime: *commonconfig.MustNewDuration(RootSnoozeTime), + BatchingStrategyID: BatchingStrategyID, + }) + require.NoError(t, err2) + } + signers, transmitters, configF, _, offchainConfigVersion, offchainConfig, err2 := ocr3confighelper.ContractSetConfigArgsForTests( + DeltaProgress, + DeltaResend, + DeltaInitial, + DeltaRound, + DeltaGrace, + DeltaCertifiedCommitRequest, + DeltaStage, + Rmax, + schedule, + oracles, + encodedOffchainConfig, + MaxDurationQuery, + MaxDurationObservation, + MaxDurationShouldAcceptAttestedReport, + MaxDurationShouldTransmitAcceptedReport, + int(f), + []byte{}, // empty OnChainConfig + ) + require.NoError(t, err2, "failed to create contract config") + + signersBytes := make([][]byte, len(signers)) + for i, signer := range signers { + signersBytes[i] = signer + } + + transmittersBytes := make([][]byte, len(transmitters)) + for i, transmitter := range transmitters { + // anotherErr because linting doesn't want to shadow err + parsed, anotherErr := common.ParseHexOrString(string(transmitter)) + require.NoError(t, anotherErr) + transmittersBytes[i] = parsed + } + ocr3Configs = append(ocr3Configs, ocr3_config_encoder.CCIPConfigTypesOCR3Config{ PluginType: uint8(pluginType), ChainSelector: chainSelector, - F: f, + F: configF, OffchainConfigVersion: offchainConfigVersion, OfframpAddress: uni.offramp.Address().Bytes(), BootstrapP2PIds: [][32]byte{bootstrapP2PID}, @@ -522,13 +572,13 @@ func (h *homeChain) AddDON( require.NotZero(t, donID, "failed to get donID from config set event") var signerAddresses []common.Address - for _, signer := range signers { - signerAddresses = append(signerAddresses, common.BytesToAddress(signer)) + for _, oracle := range oracles { + signerAddresses = append(signerAddresses, common.BytesToAddress(oracle.OnchainPublicKey)) } var transmitterAddresses []common.Address - for _, transmitter := range transmitters { - transmitterAddresses = append(transmitterAddresses, common.HexToAddress(string(transmitter))) + for _, oracle := range oracles { + transmitterAddresses = append(transmitterAddresses, common.HexToAddress(string(oracle.TransmitAccount))) } // get the config digest from the ccip config contract and set config on the offramp. diff --git a/core/capabilities/ccip/ccip_integration_tests/home_chain_test.go b/core/capabilities/ccip/ccip_integration_tests/home_chain_test.go index 2188e9ea75d..c78fd37b809 100644 --- a/core/capabilities/ccip/ccip_integration_tests/home_chain_test.go +++ b/core/capabilities/ccip/ccip_integration_tests/home_chain_test.go @@ -11,6 +11,7 @@ import ( libocrtypes "github.com/smartcontractkit/libocr/ragep2p/types" + "github.com/smartcontractkit/chainlink-ccip/chainconfig" ccipreader "github.com/smartcontractkit/chainlink-ccip/pkg/reader" cciptypes "github.com/smartcontractkit/chainlink-common/pkg/types/ccipocr3" @@ -35,15 +36,22 @@ func TestHomeChainReader(t *testing.T) { p2pIDs := integrationhelpers.P2pIDsFromInts(arr) uni.AddCapability(p2pIDs) //==============================Apply configs to Capability Contract================================= - chainAConf := integrationhelpers.SetupConfigInfo(integrationhelpers.ChainA, p2pIDs, integrationhelpers.FChainA, []byte("ChainA")) - chainBConf := integrationhelpers.SetupConfigInfo(integrationhelpers.ChainB, p2pIDs[1:], integrationhelpers.FChainB, []byte("ChainB")) - chainCConf := integrationhelpers.SetupConfigInfo(integrationhelpers.ChainC, p2pIDs[2:], integrationhelpers.FChainC, []byte("ChainC")) + encodedChainConfig, err := chainconfig.EncodeChainConfig(chainconfig.ChainConfig{ + GasPriceDeviationPPB: cciptypes.NewBigIntFromInt64(1000), + DAGasPriceDeviationPPB: cciptypes.NewBigIntFromInt64(1_000_000), + FinalityDepth: -1, + OptimisticConfirmations: 1, + }) + require.NoError(t, err) + chainAConf := integrationhelpers.SetupConfigInfo(integrationhelpers.ChainA, p2pIDs, integrationhelpers.FChainA, encodedChainConfig) + chainBConf := integrationhelpers.SetupConfigInfo(integrationhelpers.ChainB, p2pIDs[1:], integrationhelpers.FChainB, encodedChainConfig) + chainCConf := integrationhelpers.SetupConfigInfo(integrationhelpers.ChainC, p2pIDs[2:], integrationhelpers.FChainC, encodedChainConfig) inputConfig := []capcfg.CCIPConfigTypesChainConfigInfo{ chainAConf, chainBConf, chainCConf, } - _, err := uni.CcipCfg.ApplyChainConfigUpdates(uni.Transactor, nil, inputConfig) + _, err = uni.CcipCfg.ApplyChainConfigUpdates(uni.Transactor, nil, inputConfig) require.NoError(t, err) uni.Backend.Commit() //================================Setup HomeChainReader=============================== @@ -63,6 +71,7 @@ func TestHomeChainReader(t *testing.T) { expectedChainConfigs[cciptypes.ChainSelector(c.ChainSelector)] = ccipreader.ChainConfig{ FChain: int(c.ChainConfig.FChain), SupportedNodes: toPeerIDs(c.ChainConfig.Readers), + Config: mustDecodeChainConfig(t, c.ChainConfig.Config), } } configs, err := homeChain.GetAllChainConfigs() @@ -86,3 +95,9 @@ func toPeerIDs(readers [][32]byte) mapset.Set[libocrtypes.PeerID] { } return peerIDs } + +func mustDecodeChainConfig(t *testing.T, encodedChainConfig []byte) chainconfig.ChainConfig { + chainConfig, err := chainconfig.DecodeChainConfig(encodedChainConfig) + require.NoError(t, err) + return chainConfig +} diff --git a/core/capabilities/ccip/ccip_integration_tests/integrationhelpers/integration_helpers.go b/core/capabilities/ccip/ccip_integration_tests/integrationhelpers/integration_helpers.go index c23cd214035..7520b126336 100644 --- a/core/capabilities/ccip/ccip_integration_tests/integrationhelpers/integration_helpers.go +++ b/core/capabilities/ccip/ccip_integration_tests/integrationhelpers/integration_helpers.go @@ -82,6 +82,8 @@ const ( CcipCapabilityVersion = "v1.0" ) +var CapabilityID = fmt.Sprintf("%s@%s", CcipCapabilityLabelledName, CcipCapabilityVersion) + type TestUniverse struct { Transactor *bind.TransactOpts Backend *backends.SimulatedBackend diff --git a/core/capabilities/ccip/ccip_integration_tests/ocr_node_helper.go b/core/capabilities/ccip/ccip_integration_tests/ocr_node_helper.go index ec35621bf8c..75b0e0ee947 100644 --- a/core/capabilities/ccip/ccip_integration_tests/ocr_node_helper.go +++ b/core/capabilities/ccip/ccip_integration_tests/ocr_node_helper.go @@ -10,6 +10,7 @@ import ( "testing" "time" + coretypes "github.com/smartcontractkit/chainlink-common/pkg/types/core/mocks" "github.com/smartcontractkit/chainlink/v2/core/capabilities/ccip/validate" "github.com/ethereum/go-ethereum/accounts/abi/bind" @@ -131,9 +132,10 @@ func setupNodeOCR3( CSAETHKeystore: kStore, } relayerFactory := chainlink.RelayerFactory{ - Logger: lggr, - LoopRegistry: plugins.NewLoopRegistry(lggr.Named("LoopRegistry"), cfg.Tracing()), - GRPCOpts: loop.GRPCOpts{}, + Logger: lggr, + LoopRegistry: plugins.NewLoopRegistry(lggr.Named("LoopRegistry"), cfg.Tracing()), + GRPCOpts: loop.GRPCOpts{}, + CapabilitiesRegistry: coretypes.NewCapabilitiesRegistry(t), } initOps := []chainlink.CoreRelayerChainInitFunc{chainlink.InitEVM(testutils.Context(t), relayerFactory, evmOpts)} rci, err := chainlink.NewCoreRelayerChainInteroperators(initOps...) diff --git a/core/capabilities/ccip/configs/evm/chain_writer.go b/core/capabilities/ccip/configs/evm/chain_writer.go index b112681c645..6d3b73c6f5c 100644 --- a/core/capabilities/ccip/configs/evm/chain_writer.go +++ b/core/capabilities/ccip/configs/evm/chain_writer.go @@ -20,8 +20,13 @@ var ( offrampABI = evmtypes.MustGetABI(evm_2_evm_multi_offramp.EVM2EVMMultiOffRampABI) ) -func MustChainWriterConfig(fromAddress common.Address, maxGasPrice *assets.Wei) []byte { - rawConfig := ChainWriterConfigRaw(fromAddress, maxGasPrice) +func MustChainWriterConfig( + fromAddress common.Address, + maxGasPrice *assets.Wei, + commitGasLimit, + execBatchGasLimit uint64, +) []byte { + rawConfig := ChainWriterConfigRaw(fromAddress, maxGasPrice, commitGasLimit, execBatchGasLimit) encoded, err := json.Marshal(rawConfig) if err != nil { panic(fmt.Errorf("failed to marshal ChainWriterConfig: %w", err)) @@ -31,7 +36,12 @@ func MustChainWriterConfig(fromAddress common.Address, maxGasPrice *assets.Wei) } // ChainWriterConfigRaw returns a ChainWriterConfig that can be used to transmit commit and execute reports. -func ChainWriterConfigRaw(fromAddress common.Address, maxGasPrice *assets.Wei) evmrelaytypes.ChainWriterConfig { +func ChainWriterConfigRaw( + fromAddress common.Address, + maxGasPrice *assets.Wei, + commitGasLimit, + execBatchGasLimit uint64, +) evmrelaytypes.ChainWriterConfig { return evmrelaytypes.ChainWriterConfig{ Contracts: map[string]*evmrelaytypes.ContractConfig{ consts.ContractNameOffRamp: { @@ -40,14 +50,12 @@ func ChainWriterConfigRaw(fromAddress common.Address, maxGasPrice *assets.Wei) e consts.MethodCommit: { ChainSpecificName: mustGetMethodName("commit", offrampABI), FromAddress: fromAddress, - // TODO: inject this into the method, should be fetched from the OCR config. - GasLimit: 500_000, + GasLimit: commitGasLimit, }, consts.MethodExecute: { ChainSpecificName: mustGetMethodName("execute", offrampABI), FromAddress: fromAddress, - // TODO: inject this into the method, should be fetched from the OCR config. - GasLimit: 6_500_000, + GasLimit: execBatchGasLimit, }, }, }, diff --git a/core/capabilities/ccip/delegate.go b/core/capabilities/ccip/delegate.go index 1b4b9e25aed..c9974d62e99 100644 --- a/core/capabilities/ccip/delegate.go +++ b/core/capabilities/ccip/delegate.go @@ -5,10 +5,14 @@ import ( "fmt" "time" + "github.com/smartcontractkit/chainlink-common/pkg/loop" "github.com/smartcontractkit/chainlink/v2/core/capabilities/ccip/common" configsevm "github.com/smartcontractkit/chainlink/v2/core/capabilities/ccip/configs/evm" "github.com/smartcontractkit/chainlink/v2/core/capabilities/ccip/launcher" "github.com/smartcontractkit/chainlink/v2/core/capabilities/ccip/oraclecreator" + "github.com/smartcontractkit/chainlink/v2/core/services/ocrcommon" + p2ptypes "github.com/smartcontractkit/chainlink/v2/core/services/p2p/types" + "github.com/smartcontractkit/chainlink/v2/core/services/registrysyncer" ragep2ptypes "github.com/smartcontractkit/libocr/ragep2p/types" @@ -27,25 +31,28 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/ocr2key" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/p2pkey" "github.com/smartcontractkit/chainlink/v2/core/services/ocr2" - "github.com/smartcontractkit/chainlink/v2/core/services/ocrcommon" "github.com/smartcontractkit/chainlink/v2/core/services/pipeline" - "github.com/smartcontractkit/chainlink/v2/core/services/registrysyncer" "github.com/smartcontractkit/chainlink/v2/core/services/relay" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm" "github.com/smartcontractkit/chainlink/v2/core/services/telemetry" "github.com/smartcontractkit/chainlink/v2/plugins" ) +type RelayGetter interface { + Get(types.RelayID) (loop.Relayer, error) + GetIDToRelayerMap() (map[types.RelayID]loop.Relayer, error) +} + type Delegate struct { lggr logger.Logger registrarConfig plugins.RegistrarConfig pipelineRunner pipeline.Runner chains legacyevm.LegacyChainContainer + relayers RelayGetter keystore keystore.Master ds sqlutil.DataSource peerWrapper *ocrcommon.SingletonPeerWrapper monitoringEndpointGen telemetry.MonitoringEndpointGenerator - registrySyncer registrysyncer.Syncer capabilityConfig config.Capabilities isNewlyCreatedJob bool @@ -56,7 +63,7 @@ func NewDelegate( registrarConfig plugins.RegistrarConfig, pipelineRunner pipeline.Runner, chains legacyevm.LegacyChainContainer, - registrySyncer registrysyncer.Syncer, + relayers RelayGetter, keystore keystore.Master, ds sqlutil.DataSource, peerWrapper *ocrcommon.SingletonPeerWrapper, @@ -68,7 +75,7 @@ func NewDelegate( registrarConfig: registrarConfig, pipelineRunner: pipelineRunner, chains: chains, - registrySyncer: registrySyncer, + relayers: relayers, ds: ds, keystore: keystore, peerWrapper: peerWrapper, @@ -99,6 +106,24 @@ func (d *Delegate) ServicesForSpec(ctx context.Context, spec job.Job) (services return nil, fmt.Errorf("failed to get all p2p keys: %w", err) } + cfg := d.capabilityConfig + rid := cfg.ExternalRegistry().RelayID() + relayer, err := d.relayers.Get(rid) + if err != nil { + return nil, fmt.Errorf("could not fetch relayer %s configured for capabilities registry: %w", rid, err) + } + registrySyncer, err := registrysyncer.New( + d.lggr, + func() (p2ptypes.PeerID, error) { + return p2ptypes.PeerID(p2pID.PeerID()), nil + }, + relayer, + cfg.ExternalRegistry().Address(), + ) + if err != nil { + return nil, fmt.Errorf("could not configure syncer: %w", err) + } + ocrKeys, err := d.getOCRKeys(spec.CCIPSpec.OCRKeyBundleIDs) if err != nil { return nil, err @@ -149,9 +174,9 @@ func (d *Delegate) ServicesForSpec(ctx context.Context, spec job.Job) (services hcr, ) + capabilityID := fmt.Sprintf("%s@%s", spec.CCIPSpec.CapabilityLabelledName, spec.CCIPSpec.CapabilityVersion) capLauncher := launcher.New( - spec.CCIPSpec.CapabilityVersion, - spec.CCIPSpec.CapabilityLabelledName, + capabilityID, ragep2ptypes.PeerID(p2pID.PeerID()), d.lggr, hcr, @@ -160,9 +185,10 @@ func (d *Delegate) ServicesForSpec(ctx context.Context, spec job.Job) (services ) // register the capability launcher with the registry syncer - d.registrySyncer.AddLauncher(capLauncher) + registrySyncer.AddLauncher(capLauncher) return []job.ServiceCtx{ + registrySyncer, hcr, capLauncher, }, nil diff --git a/core/capabilities/ccip/launcher/diff.go b/core/capabilities/ccip/launcher/diff.go index e44b5478ed1..e631ea9fc78 100644 --- a/core/capabilities/ccip/launcher/diff.go +++ b/core/capabilities/ccip/launcher/diff.go @@ -3,30 +3,26 @@ package launcher import ( "fmt" - "github.com/smartcontractkit/chainlink/v2/core/capabilities/ccip/common" - ragep2ptypes "github.com/smartcontractkit/libocr/ragep2p/types" - kcr "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/keystone/generated/capabilities_registry" "github.com/smartcontractkit/chainlink/v2/core/services/registrysyncer" ) // diffResult contains the added, removed and updated CCIP DONs. // It is determined by using the `diff` function below. type diffResult struct { - added map[registrysyncer.DonID]kcr.CapabilitiesRegistryDONInfo - removed map[registrysyncer.DonID]kcr.CapabilitiesRegistryDONInfo - updated map[registrysyncer.DonID]kcr.CapabilitiesRegistryDONInfo + added map[registrysyncer.DonID]registrysyncer.DON + removed map[registrysyncer.DonID]registrysyncer.DON + updated map[registrysyncer.DonID]registrysyncer.DON } // diff compares the old and new state and returns the added, removed and updated CCIP DONs. func diff( - capabilityVersion, - capabilityLabelledName string, + capabilityID string, oldState, - newState registrysyncer.State, + newState registrysyncer.LocalRegistry, ) (diffResult, error) { - ccipCapability, err := checkCapabilityPresence(capabilityVersion, capabilityLabelledName, newState) + ccipCapability, err := checkCapabilityPresence(capabilityID, newState) if err != nil { return diffResult{}, fmt.Errorf("failed to check capability presence: %w", err) } @@ -53,14 +49,14 @@ func diff( // compareDONs compares the current and new CCIP DONs and returns the added, removed and updated DONs. func compareDONs( currCCIPDONs, - newCCIPDONs map[registrysyncer.DonID]kcr.CapabilitiesRegistryDONInfo, + newCCIPDONs map[registrysyncer.DonID]registrysyncer.DON, ) ( dr diffResult, err error, ) { - added := make(map[registrysyncer.DonID]kcr.CapabilitiesRegistryDONInfo) - removed := make(map[registrysyncer.DonID]kcr.CapabilitiesRegistryDONInfo) - updated := make(map[registrysyncer.DonID]kcr.CapabilitiesRegistryDONInfo) + added := make(map[registrysyncer.DonID]registrysyncer.DON) + removed := make(map[registrysyncer.DonID]registrysyncer.DON) + updated := make(map[registrysyncer.DonID]registrysyncer.DON) for id, don := range newCCIPDONs { if currDONState, ok := currCCIPDONs[id]; !ok { @@ -69,7 +65,7 @@ func compareDONs( } else { // If its in the current state and the config count for the DON has changed, mark as updated. // Since the registry returns the full state we need to compare the config count. - if don.ConfigCount > currDONState.ConfigCount { + if don.ConfigVersion > currDONState.ConfigVersion { updated[id] = don } } @@ -91,50 +87,39 @@ func compareDONs( // filterCCIPDONs filters the CCIP DONs from the given state. func filterCCIPDONs( - ccipCapability kcr.CapabilitiesRegistryCapabilityInfo, - state registrysyncer.State, -) (map[registrysyncer.DonID]kcr.CapabilitiesRegistryDONInfo, error) { - ccipDONs := make(map[registrysyncer.DonID]kcr.CapabilitiesRegistryDONInfo) + ccipCapability registrysyncer.Capability, + state registrysyncer.LocalRegistry, +) (map[registrysyncer.DonID]registrysyncer.DON, error) { + ccipDONs := make(map[registrysyncer.DonID]registrysyncer.DON) for _, don := range state.IDsToDONs { - for _, donCapabilities := range don.CapabilityConfigurations { - hid, err := common.HashedCapabilityID(ccipCapability.LabelledName, ccipCapability.Version) - if err != nil { - return nil, fmt.Errorf("failed to hash capability id: %w", err) - } - if donCapabilities.CapabilityId == hid { - ccipDONs[registrysyncer.DonID(don.Id)] = don - } + _, ok := don.CapabilityConfigurations[ccipCapability.ID] + if ok { + ccipDONs[registrysyncer.DonID(don.ID)] = don } } return ccipDONs, nil } -// checkCapabilityPresence checks if the capability with the given version and -// labelled name is present in the given capability registry state. +// checkCapabilityPresence checks if the capability with the given capabilityID +// is present in the given capability registry state. func checkCapabilityPresence( - capabilityVersion, - capabilityLabelledName string, - state registrysyncer.State, -) (kcr.CapabilitiesRegistryCapabilityInfo, error) { + capabilityID string, + state registrysyncer.LocalRegistry, +) (registrysyncer.Capability, error) { // Sanity check to make sure the capability registry has the capability we are looking for. - hid, err := common.HashedCapabilityID(capabilityLabelledName, capabilityVersion) - if err != nil { - return kcr.CapabilitiesRegistryCapabilityInfo{}, fmt.Errorf("failed to hash capability id: %w", err) - } - ccipCapability, ok := state.IDsToCapabilities[hid] + ccipCapability, ok := state.IDsToCapabilities[capabilityID] if !ok { - return kcr.CapabilitiesRegistryCapabilityInfo{}, - fmt.Errorf("failed to find capability with name %s and version %s in capability registry state", - capabilityLabelledName, capabilityVersion) + return registrysyncer.Capability{}, + fmt.Errorf("failed to find capability with capabilityID %s in capability registry state", capabilityID) } return ccipCapability, nil } // isMemberOfDON returns true if and only if the given p2pID is a member of the given DON. -func isMemberOfDON(don kcr.CapabilitiesRegistryDONInfo, p2pID ragep2ptypes.PeerID) bool { - for _, node := range don.NodeP2PIds { +func isMemberOfDON(don registrysyncer.DON, p2pID ragep2ptypes.PeerID) bool { + for _, node := range don.Members { if node == p2pID { return true } diff --git a/core/capabilities/ccip/launcher/diff_test.go b/core/capabilities/ccip/launcher/diff_test.go index 37371945abc..f3dd327fe91 100644 --- a/core/capabilities/ccip/launcher/diff_test.go +++ b/core/capabilities/ccip/launcher/diff_test.go @@ -1,14 +1,12 @@ package launcher import ( - "fmt" "math/big" "reflect" "testing" - capcommon "github.com/smartcontractkit/chainlink/v2/core/capabilities/ccip/common" - ragep2ptypes "github.com/smartcontractkit/libocr/ragep2p/types" + "github.com/stretchr/testify/require" kcr "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/keystone/generated/capabilities_registry" @@ -17,18 +15,11 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/registrysyncer" ) -const ( - ccipCapVersion = "v1.0.0" - ccipCapNewVersion = "v1.1.0" - ccipCapName = "ccip" -) - func Test_diff(t *testing.T) { type args struct { - capabilityVersion string - capabilityLabelledName string - oldState registrysyncer.State - newState registrysyncer.State + capabilityID string + oldState registrysyncer.LocalRegistry + newState registrysyncer.LocalRegistry } tests := []struct { name string @@ -37,75 +28,46 @@ func Test_diff(t *testing.T) { wantErr bool }{ { - "no diff", - args{ - capabilityVersion: ccipCapVersion, - capabilityLabelledName: ccipCapName, - oldState: registrysyncer.State{ - IDsToCapabilities: map[registrysyncer.HashedCapabilityID]kcr.CapabilitiesRegistryCapabilityInfo{ - mustHashedCapabilityID(ccipCapName, ccipCapVersion): { - LabelledName: ccipCapName, - Version: ccipCapVersion, - }, + name: "no diff", + args: args{ + capabilityID: defaultCapability.ID, + oldState: registrysyncer.LocalRegistry{ + IDsToCapabilities: map[string]registrysyncer.Capability{ + defaultCapability.ID: defaultCapability, }, - IDsToDONs: map[registrysyncer.DonID]kcr.CapabilitiesRegistryDONInfo{ - 1: { - Id: 1, - CapabilityConfigurations: []kcr.CapabilitiesRegistryCapabilityConfiguration{ - { - CapabilityId: mustHashedCapabilityID(ccipCapName, ccipCapVersion), - }, - }, - }, + IDsToDONs: map[registrysyncer.DonID]registrysyncer.DON{ + 1: defaultRegistryDon, }, IDsToNodes: map[types.PeerID]kcr.CapabilitiesRegistryNodeInfo{}, }, - newState: registrysyncer.State{ - IDsToCapabilities: map[registrysyncer.HashedCapabilityID]kcr.CapabilitiesRegistryCapabilityInfo{ - mustHashedCapabilityID(ccipCapName, ccipCapVersion): { - LabelledName: ccipCapName, - Version: ccipCapVersion, - }, + newState: registrysyncer.LocalRegistry{ + IDsToCapabilities: map[string]registrysyncer.Capability{ + defaultCapability.ID: defaultCapability, }, - IDsToDONs: map[registrysyncer.DonID]kcr.CapabilitiesRegistryDONInfo{ - 1: { - Id: 1, - CapabilityConfigurations: []kcr.CapabilitiesRegistryCapabilityConfiguration{ - { - CapabilityId: mustHashedCapabilityID(ccipCapName, ccipCapVersion), - }, - }, - }, + IDsToDONs: map[registrysyncer.DonID]registrysyncer.DON{ + 1: defaultRegistryDon, }, IDsToNodes: map[types.PeerID]kcr.CapabilitiesRegistryNodeInfo{}, }, }, - diffResult{ - added: map[registrysyncer.DonID]kcr.CapabilitiesRegistryDONInfo{}, - removed: map[registrysyncer.DonID]kcr.CapabilitiesRegistryDONInfo{}, - updated: map[registrysyncer.DonID]kcr.CapabilitiesRegistryDONInfo{}, + want: diffResult{ + added: map[registrysyncer.DonID]registrysyncer.DON{}, + removed: map[registrysyncer.DonID]registrysyncer.DON{}, + updated: map[registrysyncer.DonID]registrysyncer.DON{}, }, - false, }, { "capability not present", args{ - capabilityVersion: ccipCapVersion, - capabilityLabelledName: ccipCapName, - oldState: registrysyncer.State{ - IDsToCapabilities: map[registrysyncer.HashedCapabilityID]kcr.CapabilitiesRegistryCapabilityInfo{ - mustHashedCapabilityID(ccipCapName, ccipCapNewVersion): { - LabelledName: ccipCapName, - Version: ccipCapNewVersion, - }, + capabilityID: defaultCapability.ID, + oldState: registrysyncer.LocalRegistry{ + IDsToCapabilities: map[string]registrysyncer.Capability{ + newCapability.ID: newCapability, }, }, - newState: registrysyncer.State{ - IDsToCapabilities: map[registrysyncer.HashedCapabilityID]kcr.CapabilitiesRegistryCapabilityInfo{ - mustHashedCapabilityID(ccipCapName, ccipCapNewVersion): { - LabelledName: ccipCapName, - Version: ccipCapNewVersion, - }, + newState: registrysyncer.LocalRegistry{ + IDsToCapabilities: map[string]registrysyncer.Capability{ + newCapability.ID: newCapability, }, }, }, @@ -115,56 +77,35 @@ func Test_diff(t *testing.T) { { "diff present, new don", args{ - capabilityVersion: ccipCapVersion, - capabilityLabelledName: ccipCapName, - oldState: registrysyncer.State{ - IDsToCapabilities: map[registrysyncer.HashedCapabilityID]kcr.CapabilitiesRegistryCapabilityInfo{ - mustHashedCapabilityID(ccipCapName, ccipCapVersion): { - LabelledName: ccipCapName, - Version: ccipCapVersion, - }, + capabilityID: defaultCapability.ID, + oldState: registrysyncer.LocalRegistry{ + IDsToCapabilities: map[string]registrysyncer.Capability{ + defaultCapability.ID: defaultCapability, }, - IDsToDONs: map[registrysyncer.DonID]kcr.CapabilitiesRegistryDONInfo{}, + IDsToDONs: map[registrysyncer.DonID]registrysyncer.DON{}, }, - newState: registrysyncer.State{ - IDsToCapabilities: map[registrysyncer.HashedCapabilityID]kcr.CapabilitiesRegistryCapabilityInfo{ - mustHashedCapabilityID(ccipCapName, ccipCapVersion): { - LabelledName: ccipCapName, - Version: ccipCapVersion, - }, + newState: registrysyncer.LocalRegistry{ + IDsToCapabilities: map[string]registrysyncer.Capability{ + defaultCapability.ID: defaultCapability, }, - IDsToDONs: map[registrysyncer.DonID]kcr.CapabilitiesRegistryDONInfo{ - 1: { - Id: 1, - CapabilityConfigurations: []kcr.CapabilitiesRegistryCapabilityConfiguration{ - { - CapabilityId: mustHashedCapabilityID(ccipCapName, ccipCapVersion), - }, - }, - }, + IDsToDONs: map[registrysyncer.DonID]registrysyncer.DON{ + 1: defaultRegistryDon, }, }, }, diffResult{ - added: map[registrysyncer.DonID]kcr.CapabilitiesRegistryDONInfo{ - 1: { - Id: 1, - CapabilityConfigurations: []kcr.CapabilitiesRegistryCapabilityConfiguration{ - { - CapabilityId: mustHashedCapabilityID(ccipCapName, ccipCapVersion), - }, - }, - }, + added: map[registrysyncer.DonID]registrysyncer.DON{ + 1: defaultRegistryDon, }, - removed: map[registrysyncer.DonID]kcr.CapabilitiesRegistryDONInfo{}, - updated: map[registrysyncer.DonID]kcr.CapabilitiesRegistryDONInfo{}, + removed: map[registrysyncer.DonID]registrysyncer.DON{}, + updated: map[registrysyncer.DonID]registrysyncer.DON{}, }, false, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - got, err := diff(tt.args.capabilityVersion, tt.args.capabilityLabelledName, tt.args.oldState, tt.args.newState) + got, err := diff(tt.args.capabilityID, tt.args.oldState, tt.args.newState) if tt.wantErr { require.Error(t, err) } else { @@ -177,77 +118,66 @@ func Test_diff(t *testing.T) { func Test_compareDONs(t *testing.T) { type args struct { - currCCIPDONs map[registrysyncer.DonID]kcr.CapabilitiesRegistryDONInfo - newCCIPDONs map[registrysyncer.DonID]kcr.CapabilitiesRegistryDONInfo + currCCIPDONs map[registrysyncer.DonID]registrysyncer.DON + newCCIPDONs map[registrysyncer.DonID]registrysyncer.DON } tests := []struct { name string args args - wantAdded map[registrysyncer.DonID]kcr.CapabilitiesRegistryDONInfo - wantRemoved map[registrysyncer.DonID]kcr.CapabilitiesRegistryDONInfo - wantUpdated map[registrysyncer.DonID]kcr.CapabilitiesRegistryDONInfo + wantAdded map[registrysyncer.DonID]registrysyncer.DON + wantRemoved map[registrysyncer.DonID]registrysyncer.DON + wantUpdated map[registrysyncer.DonID]registrysyncer.DON wantErr bool }{ { "added dons", args{ - currCCIPDONs: map[registrysyncer.DonID]kcr.CapabilitiesRegistryDONInfo{}, - newCCIPDONs: map[registrysyncer.DonID]kcr.CapabilitiesRegistryDONInfo{ - 1: { - Id: 1, - }, + currCCIPDONs: map[registrysyncer.DonID]registrysyncer.DON{}, + newCCIPDONs: map[registrysyncer.DonID]registrysyncer.DON{ + 1: defaultRegistryDon, }, }, - map[registrysyncer.DonID]kcr.CapabilitiesRegistryDONInfo{ - 1: { - Id: 1, - }, + map[registrysyncer.DonID]registrysyncer.DON{ + 1: defaultRegistryDon, }, - map[registrysyncer.DonID]kcr.CapabilitiesRegistryDONInfo{}, - map[registrysyncer.DonID]kcr.CapabilitiesRegistryDONInfo{}, + map[registrysyncer.DonID]registrysyncer.DON{}, + map[registrysyncer.DonID]registrysyncer.DON{}, false, }, { "removed dons", args{ - currCCIPDONs: map[registrysyncer.DonID]kcr.CapabilitiesRegistryDONInfo{ - 1: { - Id: 1, - }, + currCCIPDONs: map[registrysyncer.DonID]registrysyncer.DON{ + 1: defaultRegistryDon, }, - newCCIPDONs: map[registrysyncer.DonID]kcr.CapabilitiesRegistryDONInfo{}, + newCCIPDONs: map[registrysyncer.DonID]registrysyncer.DON{}, }, - map[registrysyncer.DonID]kcr.CapabilitiesRegistryDONInfo{}, - map[registrysyncer.DonID]kcr.CapabilitiesRegistryDONInfo{ - 1: { - Id: 1, - }, + map[registrysyncer.DonID]registrysyncer.DON{}, + map[registrysyncer.DonID]registrysyncer.DON{ + 1: defaultRegistryDon, }, - map[registrysyncer.DonID]kcr.CapabilitiesRegistryDONInfo{}, + map[registrysyncer.DonID]registrysyncer.DON{}, false, }, { "updated dons", args{ - currCCIPDONs: map[registrysyncer.DonID]kcr.CapabilitiesRegistryDONInfo{ - 1: { - Id: 1, - ConfigCount: 1, - }, + currCCIPDONs: map[registrysyncer.DonID]registrysyncer.DON{ + 1: defaultRegistryDon, }, - newCCIPDONs: map[registrysyncer.DonID]kcr.CapabilitiesRegistryDONInfo{ + newCCIPDONs: map[registrysyncer.DonID]registrysyncer.DON{ 1: { - Id: 1, - ConfigCount: 2, + DON: getDON(defaultRegistryDon.ID, defaultRegistryDon.Members, defaultRegistryDon.ConfigVersion+1), + CapabilityConfigurations: defaultCapCfgs, }, }, }, - map[registrysyncer.DonID]kcr.CapabilitiesRegistryDONInfo{}, - map[registrysyncer.DonID]kcr.CapabilitiesRegistryDONInfo{}, - map[registrysyncer.DonID]kcr.CapabilitiesRegistryDONInfo{ + map[registrysyncer.DonID]registrysyncer.DON{}, + map[registrysyncer.DonID]registrysyncer.DON{}, + map[registrysyncer.DonID]registrysyncer.DON{ 1: { - Id: 1, - ConfigCount: 2, + DON: getDON(defaultRegistryDon.ID, defaultRegistryDon.Members, defaultRegistryDon.ConfigVersion+1), + CapabilityConfigurations: defaultCapCfgs, }, }, false, @@ -270,103 +200,65 @@ func Test_compareDONs(t *testing.T) { func Test_filterCCIPDONs(t *testing.T) { type args struct { - ccipCapability kcr.CapabilitiesRegistryCapabilityInfo - state registrysyncer.State + ccipCapability registrysyncer.Capability + state registrysyncer.LocalRegistry } tests := []struct { name string args args - want map[registrysyncer.DonID]kcr.CapabilitiesRegistryDONInfo + want map[registrysyncer.DonID]registrysyncer.DON wantErr bool }{ { "one ccip don", args{ - ccipCapability: kcr.CapabilitiesRegistryCapabilityInfo{ - LabelledName: ccipCapName, - Version: ccipCapVersion, - }, - state: registrysyncer.State{ - IDsToDONs: map[registrysyncer.DonID]kcr.CapabilitiesRegistryDONInfo{ - 1: { - Id: 1, - CapabilityConfigurations: []kcr.CapabilitiesRegistryCapabilityConfiguration{ - { - CapabilityId: mustHashedCapabilityID(ccipCapName, ccipCapVersion), - }, - }, - }, + ccipCapability: defaultCapability, + state: registrysyncer.LocalRegistry{ + IDsToDONs: map[registrysyncer.DonID]registrysyncer.DON{ + 1: defaultRegistryDon, }, }, }, - map[registrysyncer.DonID]kcr.CapabilitiesRegistryDONInfo{ - 1: { - Id: 1, - CapabilityConfigurations: []kcr.CapabilitiesRegistryCapabilityConfiguration{ - { - CapabilityId: mustHashedCapabilityID(ccipCapName, ccipCapVersion), - }, - }, - }, + map[registrysyncer.DonID]registrysyncer.DON{ + 1: defaultRegistryDon, }, false, }, { - "no ccip dons", + "no ccip dons - different capability", args{ - ccipCapability: kcr.CapabilitiesRegistryCapabilityInfo{ - LabelledName: ccipCapName, - Version: ccipCapVersion, - }, - state: registrysyncer.State{ - IDsToDONs: map[registrysyncer.DonID]kcr.CapabilitiesRegistryDONInfo{ - 1: { - Id: 1, - CapabilityConfigurations: []kcr.CapabilitiesRegistryCapabilityConfiguration{ - { - CapabilityId: mustHashedCapabilityID(ccipCapName, ccipCapNewVersion), - }, - }, - }, + ccipCapability: newCapability, + state: registrysyncer.LocalRegistry{ + IDsToDONs: map[registrysyncer.DonID]registrysyncer.DON{ + 1: defaultRegistryDon, }, }, }, - map[registrysyncer.DonID]kcr.CapabilitiesRegistryDONInfo{}, + map[registrysyncer.DonID]registrysyncer.DON{}, false, }, { "don with multiple capabilities, one of them ccip", args{ - ccipCapability: kcr.CapabilitiesRegistryCapabilityInfo{ - LabelledName: ccipCapName, - Version: ccipCapVersion, - }, - state: registrysyncer.State{ - IDsToDONs: map[registrysyncer.DonID]kcr.CapabilitiesRegistryDONInfo{ + ccipCapability: defaultCapability, + state: registrysyncer.LocalRegistry{ + IDsToDONs: map[registrysyncer.DonID]registrysyncer.DON{ 1: { - Id: 1, - CapabilityConfigurations: []kcr.CapabilitiesRegistryCapabilityConfiguration{ - { - CapabilityId: mustHashedCapabilityID(ccipCapName, ccipCapVersion), - }, - { - CapabilityId: mustHashedCapabilityID(ccipCapName, ccipCapNewVersion), - }, + DON: getDON(1, []ragep2ptypes.PeerID{p2pID1}, 0), + CapabilityConfigurations: map[string]registrysyncer.CapabilityConfiguration{ + defaultCapability.ID: {}, + newCapability.ID: {}, }, }, }, }, }, - map[registrysyncer.DonID]kcr.CapabilitiesRegistryDONInfo{ + map[registrysyncer.DonID]registrysyncer.DON{ 1: { - Id: 1, - CapabilityConfigurations: []kcr.CapabilitiesRegistryCapabilityConfiguration{ - { - CapabilityId: mustHashedCapabilityID(ccipCapName, ccipCapVersion), - }, - { - CapabilityId: mustHashedCapabilityID(ccipCapName, ccipCapNewVersion), - }, + DON: getDON(1, []ragep2ptypes.PeerID{p2pID1}, 0), + CapabilityConfigurations: map[string]registrysyncer.CapabilityConfiguration{ + defaultCapability.ID: {}, + newCapability.ID: {}, }, }, }, @@ -388,61 +280,45 @@ func Test_filterCCIPDONs(t *testing.T) { func Test_checkCapabilityPresence(t *testing.T) { type args struct { - capabilityVersion string - capabilityLabelledName string - state registrysyncer.State + capabilityID string + state registrysyncer.LocalRegistry } tests := []struct { name string args args - want kcr.CapabilitiesRegistryCapabilityInfo + want registrysyncer.Capability wantErr bool }{ { "in registry state", args{ - capabilityVersion: ccipCapVersion, - capabilityLabelledName: ccipCapName, - state: registrysyncer.State{ - IDsToCapabilities: map[registrysyncer.HashedCapabilityID]kcr.CapabilitiesRegistryCapabilityInfo{ - mustHashedCapabilityID(ccipCapName, ccipCapVersion): { - LabelledName: ccipCapName, - Version: ccipCapVersion, - }, - mustHashedCapabilityID(ccipCapName, ccipCapNewVersion): { - LabelledName: ccipCapName, - Version: ccipCapNewVersion, - }, + capabilityID: defaultCapability.ID, + state: registrysyncer.LocalRegistry{ + IDsToCapabilities: map[string]registrysyncer.Capability{ + defaultCapability.ID: defaultCapability, }, }, }, - kcr.CapabilitiesRegistryCapabilityInfo{ - LabelledName: ccipCapName, - Version: ccipCapVersion, - }, + defaultCapability, false, }, { "not in registry state", args{ - capabilityVersion: ccipCapVersion, - capabilityLabelledName: ccipCapName, - state: registrysyncer.State{ - IDsToCapabilities: map[registrysyncer.HashedCapabilityID]kcr.CapabilitiesRegistryCapabilityInfo{ - mustHashedCapabilityID(ccipCapName, ccipCapNewVersion): { - LabelledName: ccipCapName, - Version: ccipCapNewVersion, - }, + capabilityID: defaultCapability.ID, + state: registrysyncer.LocalRegistry{ + IDsToCapabilities: map[string]registrysyncer.Capability{ + newCapability.ID: newCapability, }, }, }, - kcr.CapabilitiesRegistryCapabilityInfo{}, + registrysyncer.Capability{}, true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - got, err := checkCapabilityPresence(tt.args.capabilityVersion, tt.args.capabilityLabelledName, tt.args.state) + got, err := checkCapabilityPresence(tt.args.capabilityID, tt.args.state) if (err != nil) != tt.wantErr { t.Errorf("checkCapabilityPresence() error = %v, wantErr %v", err, tt.wantErr) return @@ -455,13 +331,12 @@ func Test_checkCapabilityPresence(t *testing.T) { } func Test_isMemberOfDON(t *testing.T) { - var p2pIDs [][32]byte + var p2pIDs []ragep2ptypes.PeerID for i := range [4]struct{}{} { - p2pIDs = append(p2pIDs, p2pkey.MustNewV2XXXTestingOnly(big.NewInt(int64(i+1))).PeerID()) + p2pIDs = append(p2pIDs, ragep2ptypes.PeerID(p2pkey.MustNewV2XXXTestingOnly(big.NewInt(int64(i+1))).PeerID())) } - don := kcr.CapabilitiesRegistryDONInfo{ - Id: 1, - NodeP2PIds: p2pIDs, + don := registrysyncer.DON{ + DON: getDON(1, p2pIDs, 0), } require.True(t, isMemberOfDON(don, ragep2ptypes.PeerID(p2pkey.MustNewV2XXXTestingOnly(big.NewInt(1)).PeerID()))) require.False(t, isMemberOfDON(don, ragep2ptypes.PeerID(p2pkey.MustNewV2XXXTestingOnly(big.NewInt(5)).PeerID()))) @@ -472,14 +347,6 @@ func Test_isMemberOfBootstrapSubcommittee(t *testing.T) { for i := range [4]struct{}{} { bootstrapKeys = append(bootstrapKeys, p2pkey.MustNewV2XXXTestingOnly(big.NewInt(int64(i+1))).PeerID()) } - require.True(t, isMemberOfBootstrapSubcommittee(bootstrapKeys, ragep2ptypes.PeerID(p2pkey.MustNewV2XXXTestingOnly(big.NewInt(1)).PeerID()))) - require.False(t, isMemberOfBootstrapSubcommittee(bootstrapKeys, ragep2ptypes.PeerID(p2pkey.MustNewV2XXXTestingOnly(big.NewInt(5)).PeerID()))) -} - -func mustHashedCapabilityID(capabilityLabelledName, capabilityVersion string) [32]byte { - r, err := capcommon.HashedCapabilityID(capabilityLabelledName, capabilityVersion) - if err != nil { - panic(fmt.Errorf("failed to hash capability id (labelled name: %s, version: %s): %w", capabilityLabelledName, capabilityVersion, err)) - } - return r + require.True(t, isMemberOfBootstrapSubcommittee(bootstrapKeys, p2pID1)) + require.False(t, isMemberOfBootstrapSubcommittee(bootstrapKeys, getP2PID(5))) } diff --git a/core/capabilities/ccip/launcher/integration_test.go b/core/capabilities/ccip/launcher/integration_test.go index 58b6a5d6a2e..db3daf4d9b9 100644 --- a/core/capabilities/ccip/launcher/integration_test.go +++ b/core/capabilities/ccip/launcher/integration_test.go @@ -6,6 +6,7 @@ import ( it "github.com/smartcontractkit/chainlink/v2/core/capabilities/ccip/ccip_integration_tests/integrationhelpers" cctypes "github.com/smartcontractkit/chainlink/v2/core/capabilities/ccip/types" + p2ptypes "github.com/smartcontractkit/chainlink/v2/core/services/p2p/types" "github.com/onsi/gomega" "github.com/stretchr/testify/require" @@ -29,13 +30,19 @@ func TestIntegration_Launcher(t *testing.T) { p2pIDs := it.P2pIDsFromInts(arr) uni.AddCapability(p2pIDs) - regSyncer, err := registrysyncer.New(lggr, uni, uni.CapReg.Address().String()) + regSyncer, err := registrysyncer.New(lggr, + func() (p2ptypes.PeerID, error) { + return p2pIDs[0], nil + }, + uni, + uni.CapReg.Address().String(), + ) require.NoError(t, err) hcr := uni.HomeChainReader + launcher := New( - it.CcipCapabilityVersion, - it.CcipCapabilityLabelledName, + it.CapabilityID, p2pIDs[0], logger.TestLogger(t), hcr, diff --git a/core/capabilities/ccip/launcher/launcher.go b/core/capabilities/ccip/launcher/launcher.go index 9acfebfa9ae..2dc1a1954f5 100644 --- a/core/capabilities/ccip/launcher/launcher.go +++ b/core/capabilities/ccip/launcher/launcher.go @@ -7,20 +7,20 @@ import ( "time" cctypes "github.com/smartcontractkit/chainlink/v2/core/capabilities/ccip/types" + "github.com/smartcontractkit/chainlink/v2/core/logger" + "github.com/smartcontractkit/chainlink/v2/core/services/job" + p2ptypes "github.com/smartcontractkit/chainlink/v2/core/services/p2p/types" + "github.com/smartcontractkit/chainlink/v2/core/services/registrysyncer" "go.uber.org/multierr" ragep2ptypes "github.com/smartcontractkit/libocr/ragep2p/types" - ccipreaderpkg "github.com/smartcontractkit/chainlink-ccip/pkg/reader" + ccipreader "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" - "github.com/smartcontractkit/chainlink/v2/core/services/job" - p2ptypes "github.com/smartcontractkit/chainlink/v2/core/services/p2p/types" - "github.com/smartcontractkit/chainlink/v2/core/services/registrysyncer" ) var ( @@ -29,8 +29,7 @@ var ( ) func New( - capabilityVersion, - capabilityLabelledName string, + capabilityID string, p2pID ragep2ptypes.PeerID, lggr logger.Logger, homeChainReader ccipreader.HomeChain, @@ -38,15 +37,14 @@ func New( tickInterval time.Duration, ) *launcher { return &launcher{ - capabilityVersion: capabilityVersion, - capabilityLabelledName: capabilityLabelledName, - p2pID: p2pID, - lggr: lggr, - homeChainReader: homeChainReader, - regState: registrysyncer.State{ - IDsToDONs: make(map[registrysyncer.DonID]kcr.CapabilitiesRegistryDONInfo), + p2pID: p2pID, + capabilityID: capabilityID, + lggr: lggr, + homeChainReader: homeChainReader, + regState: registrysyncer.LocalRegistry{ + IDsToDONs: make(map[registrysyncer.DonID]registrysyncer.DON), IDsToNodes: make(map[p2ptypes.PeerID]kcr.CapabilitiesRegistryNodeInfo), - IDsToCapabilities: make(map[registrysyncer.HashedCapabilityID]kcr.CapabilitiesRegistryCapabilityInfo), + IDsToCapabilities: make(map[string]registrysyncer.Capability), }, oracleCreator: oracleCreator, dons: make(map[registrysyncer.DonID]*ccipDeployment), @@ -58,16 +56,15 @@ func New( type launcher struct { services.StateMachine - capabilityVersion string - capabilityLabelledName string - p2pID ragep2ptypes.PeerID - lggr logger.Logger - homeChainReader ccipreader.HomeChain - stopChan chan struct{} + capabilityID string + p2pID ragep2ptypes.PeerID + lggr logger.Logger + homeChainReader ccipreader.HomeChain + stopChan chan struct{} // latestState is the latest capability registry state received from the syncer. - latestState registrysyncer.State + latestState registrysyncer.LocalRegistry // regState is the latest capability registry state that we have successfully processed. - regState registrysyncer.State + regState registrysyncer.LocalRegistry oracleCreator cctypes.OracleCreator lock sync.RWMutex wg sync.WaitGroup @@ -80,15 +77,15 @@ type launcher struct { } // Launch implements registrysyncer.Launcher. -func (l *launcher) Launch(ctx context.Context, state registrysyncer.State) error { +func (l *launcher) Launch(ctx context.Context, state *registrysyncer.LocalRegistry) error { l.lock.Lock() defer l.lock.Unlock() l.lggr.Debugw("Received new state from syncer", "dons", state.IDsToDONs) - l.latestState = state + l.latestState = *state return nil } -func (l *launcher) getLatestState() registrysyncer.State { +func (l *launcher) getLatestState() registrysyncer.LocalRegistry { l.lock.RLock() defer l.lock.RUnlock() return l.latestState @@ -158,7 +155,7 @@ func (l *launcher) tick() error { // launch or update any OCR instances. latestState := l.getLatestState() - diffRes, err := diff(l.capabilityVersion, l.capabilityLabelledName, l.regState, latestState) + diffRes, err := diff(l.capabilityID, l.regState, latestState) if err != nil { return fmt.Errorf("failed to diff capability registry states: %w", err) } @@ -183,14 +180,14 @@ func (l *launcher) processDiff(diff diffResult) error { return err } -func (l *launcher) processUpdate(updated map[registrysyncer.DonID]kcr.CapabilitiesRegistryDONInfo) error { +func (l *launcher) processUpdate(updated map[registrysyncer.DonID]registrysyncer.DON) error { l.lock.Lock() defer l.lock.Unlock() for donID, don := range updated { - prevDeployment, ok := l.dons[registrysyncer.DonID(don.Id)] + prevDeployment, ok := l.dons[registrysyncer.DonID(don.ID)] if !ok { - return fmt.Errorf("invariant violation: expected to find CCIP DON %d in the map of running deployments", don.Id) + return fmt.Errorf("invariant violation: expected to find CCIP DON %d in the map of running deployments", don.ID) } futDeployment, err := updateDON( @@ -219,7 +216,7 @@ func (l *launcher) processUpdate(updated map[registrysyncer.DonID]kcr.Capabiliti return nil } -func (l *launcher) processAdded(added map[registrysyncer.DonID]kcr.CapabilitiesRegistryDONInfo) error { +func (l *launcher) processAdded(added map[registrysyncer.DonID]registrysyncer.DON) error { l.lock.Lock() defer l.lock.Unlock() @@ -256,7 +253,7 @@ func (l *launcher) processAdded(added map[registrysyncer.DonID]kcr.CapabilitiesR return nil } -func (l *launcher) processRemoved(removed map[registrysyncer.DonID]kcr.CapabilitiesRegistryDONInfo) error { +func (l *launcher) processRemoved(removed map[registrysyncer.DonID]registrysyncer.DON) error { l.lock.Lock() defer l.lock.Unlock() @@ -289,34 +286,34 @@ func updateDON( homeChainReader ccipreader.HomeChain, oracleCreator cctypes.OracleCreator, prevDeployment ccipDeployment, - don kcr.CapabilitiesRegistryDONInfo, + don registrysyncer.DON, ) (futDeployment *ccipDeployment, err error) { if !isMemberOfDON(don, p2pID) { - lggr.Infow("Not a member of this DON, skipping", "donId", don.Id, "p2pId", p2pID.String()) + lggr.Infow("Not a member of this DON, skipping", "donId", don.ID, "p2pId", p2pID.String()) return nil, nil } // this should be a retryable error. - commitOCRConfigs, err := homeChainReader.GetOCRConfigs(context.Background(), don.Id, uint8(cctypes.PluginTypeCCIPCommit)) + commitOCRConfigs, err := homeChainReader.GetOCRConfigs(context.Background(), don.ID, uint8(cctypes.PluginTypeCCIPCommit)) if err != nil { return nil, fmt.Errorf("failed to fetch OCR configs for CCIP commit plugin (don id: %d) from home chain config contract: %w", - don.Id, err) + don.ID, err) } - execOCRConfigs, err := homeChainReader.GetOCRConfigs(context.Background(), don.Id, uint8(cctypes.PluginTypeCCIPExec)) + execOCRConfigs, err := homeChainReader.GetOCRConfigs(context.Background(), don.ID, uint8(cctypes.PluginTypeCCIPExec)) if err != nil { return nil, fmt.Errorf("failed to fetch OCR configs for CCIP exec plugin (don id: %d) from home chain config contract: %w", - don.Id, err) + don.ID, err) } commitBgd, err := createFutureBlueGreenDeployment(prevDeployment, commitOCRConfigs, oracleCreator, cctypes.PluginTypeCCIPCommit) if err != nil { - return nil, fmt.Errorf("failed to create future blue-green deployment for CCIP commit plugin: %w, don id: %d", err, don.Id) + return nil, fmt.Errorf("failed to create future blue-green deployment for CCIP commit plugin: %w, don id: %d", err, don.ID) } execBgd, err := createFutureBlueGreenDeployment(prevDeployment, execOCRConfigs, oracleCreator, cctypes.PluginTypeCCIPExec) if err != nil { - return nil, fmt.Errorf("failed to create future blue-green deployment for CCIP exec plugin: %w, don id: %d", err, don.Id) + return nil, fmt.Errorf("failed to create future blue-green deployment for CCIP exec plugin: %w, don id: %d", err, don.ID) } return &ccipDeployment{ @@ -331,7 +328,7 @@ func updateDON( // All other cases are invalid. This is enforced in the ccip config contract. func createFutureBlueGreenDeployment( prevDeployment ccipDeployment, - ocrConfigs []ccipreaderpkg.OCR3ConfigWithMeta, + ocrConfigs []ccipreader.OCR3ConfigWithMeta, oracleCreator cctypes.OracleCreator, pluginType cctypes.PluginType, ) (blueGreenDeployment, error) { @@ -362,33 +359,33 @@ func createDON( p2pID ragep2ptypes.PeerID, homeChainReader ccipreader.HomeChain, oracleCreator cctypes.OracleCreator, - don kcr.CapabilitiesRegistryDONInfo, + don registrysyncer.DON, ) (*ccipDeployment, error) { if !isMemberOfDON(don, p2pID) { - lggr.Infow("Not a member of this DON, skipping", "donId", don.Id, "p2pId", p2pID.String()) + lggr.Infow("Not a member of this DON, skipping", "donId", don.ID, "p2pId", p2pID.String()) return nil, nil } // this should be a retryable error. - commitOCRConfigs, err := homeChainReader.GetOCRConfigs(context.Background(), don.Id, uint8(cctypes.PluginTypeCCIPCommit)) + commitOCRConfigs, err := homeChainReader.GetOCRConfigs(context.Background(), don.ID, uint8(cctypes.PluginTypeCCIPCommit)) if err != nil { return nil, fmt.Errorf("failed to fetch OCR configs for CCIP commit plugin (don id: %d) from home chain config contract: %w", - don.Id, err) + don.ID, err) } - execOCRConfigs, err := homeChainReader.GetOCRConfigs(context.Background(), don.Id, uint8(cctypes.PluginTypeCCIPExec)) + execOCRConfigs, err := homeChainReader.GetOCRConfigs(context.Background(), don.ID, uint8(cctypes.PluginTypeCCIPExec)) if err != nil { return nil, fmt.Errorf("failed to fetch OCR configs for CCIP exec plugin (don id: %d) from home chain config contract: %w", - don.Id, err) + don.ID, err) } // upon creation we should only have one OCR config per plugin type. if len(commitOCRConfigs) != 1 { - return nil, fmt.Errorf("expected exactly one OCR config for CCIP commit plugin (don id: %d), got %d", don.Id, len(commitOCRConfigs)) + return nil, fmt.Errorf("expected exactly one OCR config for CCIP commit plugin (don id: %d), got %d", don.ID, len(commitOCRConfigs)) } if len(execOCRConfigs) != 1 { - return nil, fmt.Errorf("expected exactly one OCR config for CCIP exec plugin (don id: %d), got %d", don.Id, len(execOCRConfigs)) + return nil, fmt.Errorf("expected exactly one OCR config for CCIP exec plugin (don id: %d), got %d", don.ID, len(execOCRConfigs)) } commitOracle, commitBootstrap, err := createOracle(p2pID, oracleCreator, cctypes.PluginTypeCCIPCommit, commitOCRConfigs) @@ -417,7 +414,7 @@ func createOracle( p2pID ragep2ptypes.PeerID, oracleCreator cctypes.OracleCreator, pluginType cctypes.PluginType, - ocrConfigs []ccipreaderpkg.OCR3ConfigWithMeta, + ocrConfigs []ccipreader.OCR3ConfigWithMeta, ) (pluginOracle, bootstrapOracle cctypes.CCIPOracle, err error) { pluginOracle, err = oracleCreator.CreatePluginOracle(pluginType, cctypes.OCR3ConfigWithMeta(ocrConfigs[0])) if err != nil { diff --git a/core/capabilities/ccip/launcher/launcher_test.go b/core/capabilities/ccip/launcher/launcher_test.go index 493f962c2c6..242dd0be248 100644 --- a/core/capabilities/ccip/launcher/launcher_test.go +++ b/core/capabilities/ccip/launcher/launcher_test.go @@ -15,7 +15,6 @@ import ( ccipreaderpkg "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/internal/testutils" "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/p2pkey" @@ -154,7 +153,7 @@ func Test_createDON(t *testing.T) { p2pID ragep2ptypes.PeerID homeChainReader *mocks.HomeChainReader oracleCreator *mocks.OracleCreator - don kcr.CapabilitiesRegistryDONInfo + don registrysyncer.DON } tests := []struct { name string @@ -166,14 +165,12 @@ func Test_createDON(t *testing.T) { "not a member of the DON", args{ logger.TestLogger(t), - ragep2ptypes.PeerID(p2pkey.MustNewV2XXXTestingOnly(big.NewInt(1)).PeerID()), + p2pID1, mocks.NewHomeChainReader(t), mocks.NewOracleCreator(t), - kcr.CapabilitiesRegistryDONInfo{ - NodeP2PIds: [][32]byte{ - p2pkey.MustNewV2XXXTestingOnly(big.NewInt(2)).PeerID(), - }, - Id: 2, + registrysyncer.DON{ + DON: getDON(2, []ragep2ptypes.PeerID{p2pID2}, 0), + CapabilityConfigurations: defaultCapCfgs, }, }, func(t *testing.T, args args, oracleCreator *mocks.OracleCreator, homeChainReader *mocks.HomeChainReader) { @@ -184,15 +181,10 @@ func Test_createDON(t *testing.T) { "success, no bootstrap", args{ logger.TestLogger(t), - ragep2ptypes.PeerID(p2pkey.MustNewV2XXXTestingOnly(big.NewInt(1)).PeerID()), + p2pID1, mocks.NewHomeChainReader(t), mocks.NewOracleCreator(t), - kcr.CapabilitiesRegistryDONInfo{ - NodeP2PIds: [][32]byte{ - p2pkey.MustNewV2XXXTestingOnly(big.NewInt(1)).PeerID(), - }, - Id: 1, - }, + defaultRegistryDon, }, func(t *testing.T, args args, oracleCreator *mocks.OracleCreator, homeChainReader *mocks.HomeChainReader) { homeChainReader. @@ -262,7 +254,7 @@ func Test_updateDON(t *testing.T) { homeChainReader *mocks.HomeChainReader oracleCreator *mocks.OracleCreator prevDeployment ccipDeployment - don kcr.CapabilitiesRegistryDONInfo + don registrysyncer.DON } tests := []struct { name string @@ -293,7 +285,7 @@ func Test_launcher_processDiff(t *testing.T) { homeChainReader *mocks.HomeChainReader oracleCreator *mocks.OracleCreator dons map[registrysyncer.DonID]*ccipDeployment - regState registrysyncer.State + regState registrysyncer.LocalRegistry } type args struct { diff diffResult @@ -326,20 +318,16 @@ func Test_launcher_processDiff(t *testing.T) { }, }, }, - regState: registrysyncer.State{ - IDsToDONs: map[registrysyncer.DonID]kcr.CapabilitiesRegistryDONInfo{ - 1: { - Id: 1, - }, + regState: registrysyncer.LocalRegistry{ + IDsToDONs: map[registrysyncer.DonID]registrysyncer.DON{ + 1: defaultRegistryDon, }, }, }, args{ diff: diffResult{ - removed: map[registrysyncer.DonID]kcr.CapabilitiesRegistryDONInfo{ - 1: { - Id: 1, - }, + removed: map[registrysyncer.DonID]registrysyncer.DON{ + 1: defaultRegistryDon, }, }, }, @@ -353,7 +341,7 @@ func Test_launcher_processDiff(t *testing.T) { "don added success", fields{ lggr: logger.TestLogger(t), - p2pID: ragep2ptypes.PeerID(p2pkey.MustNewV2XXXTestingOnly(big.NewInt(1)).PeerID()), + p2pID: p2pID1, homeChainReader: newMock(t, func(t *testing.T) *mocks.HomeChainReader { return mocks.NewHomeChainReader(t) }, func(m *mocks.HomeChainReader) { @@ -375,19 +363,14 @@ func Test_launcher_processDiff(t *testing.T) { Return(execOracle, nil) }), dons: map[registrysyncer.DonID]*ccipDeployment{}, - regState: registrysyncer.State{ - IDsToDONs: map[registrysyncer.DonID]kcr.CapabilitiesRegistryDONInfo{}, + regState: registrysyncer.LocalRegistry{ + IDsToDONs: map[registrysyncer.DonID]registrysyncer.DON{}, }, }, args{ diff: diffResult{ - added: map[registrysyncer.DonID]kcr.CapabilitiesRegistryDONInfo{ - 1: { - Id: 1, - NodeP2PIds: [][32]byte{ - p2pkey.MustNewV2XXXTestingOnly(big.NewInt(1)).PeerID(), - }, - }, + added: map[registrysyncer.DonID]registrysyncer.DON{ + 1: defaultRegistryDon, }, }, }, @@ -401,7 +384,7 @@ func Test_launcher_processDiff(t *testing.T) { "don updated new green instance success", fields{ lggr: logger.TestLogger(t), - p2pID: ragep2ptypes.PeerID(p2pkey.MustNewV2XXXTestingOnly(big.NewInt(1)).PeerID()), + p2pID: p2pID1, homeChainReader: newMock(t, func(t *testing.T) *mocks.HomeChainReader { return mocks.NewHomeChainReader(t) }, func(m *mocks.HomeChainReader) { @@ -436,26 +419,19 @@ func Test_launcher_processDiff(t *testing.T) { }, }, }, - regState: registrysyncer.State{ - IDsToDONs: map[registrysyncer.DonID]kcr.CapabilitiesRegistryDONInfo{ - 1: { - Id: 1, - NodeP2PIds: [][32]byte{ - p2pkey.MustNewV2XXXTestingOnly(big.NewInt(1)).PeerID(), - }, - }, + regState: registrysyncer.LocalRegistry{ + IDsToDONs: map[registrysyncer.DonID]registrysyncer.DON{ + 1: defaultRegistryDon, }, }, }, args{ diff: diffResult{ - updated: map[registrysyncer.DonID]kcr.CapabilitiesRegistryDONInfo{ + updated: map[registrysyncer.DonID]registrysyncer.DON{ 1: { - Id: 1, - NodeP2PIds: [][32]byte{ - p2pkey.MustNewV2XXXTestingOnly(big.NewInt(1)).PeerID(), - p2pkey.MustNewV2XXXTestingOnly(big.NewInt(2)).PeerID(), // new node in don - }, + // new Node in Don: p2pID2 + DON: getDON(1, []ragep2ptypes.PeerID{p2pID1, p2pID2}, 0), + CapabilityConfigurations: defaultCapCfgs, }, }, }, @@ -463,7 +439,7 @@ func Test_launcher_processDiff(t *testing.T) { func(t *testing.T, l *launcher) { require.Len(t, l.dons, 1) require.Len(t, l.regState.IDsToDONs, 1) - require.Len(t, l.regState.IDsToDONs[1].NodeP2PIds, 2) + require.Len(t, l.regState.IDsToDONs[1].Members, 2) }, false, }, diff --git a/core/capabilities/ccip/launcher/test_helpers.go b/core/capabilities/ccip/launcher/test_helpers.go new file mode 100644 index 00000000000..a2ebf3fdba9 --- /dev/null +++ b/core/capabilities/ccip/launcher/test_helpers.go @@ -0,0 +1,56 @@ +package launcher + +import ( + "fmt" + "math/big" + + "github.com/smartcontractkit/chainlink-common/pkg/capabilities" + + "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/p2pkey" + "github.com/smartcontractkit/chainlink/v2/core/services/registrysyncer" + + ragep2ptypes "github.com/smartcontractkit/libocr/ragep2p/types" +) + +const ( + ccipCapVersion = "v1.0.0" + ccipCapNewVersion = "v1.1.0" + ccipCapName = "ccip" +) + +var ( + defaultCapability = getCapability(ccipCapName, ccipCapVersion) + newCapability = getCapability(ccipCapName, ccipCapNewVersion) + p2pID1 = getP2PID(1) + p2pID2 = getP2PID(2) + defaultCapCfgs = map[string]registrysyncer.CapabilityConfiguration{ + defaultCapability.ID: registrysyncer.CapabilityConfiguration{}, + } + defaultRegistryDon = registrysyncer.DON{ + DON: getDON(1, []ragep2ptypes.PeerID{p2pID1}, 0), + CapabilityConfigurations: defaultCapCfgs, + } +) + +func getP2PID(id uint32) ragep2ptypes.PeerID { + return ragep2ptypes.PeerID(p2pkey.MustNewV2XXXTestingOnly(big.NewInt(int64(id))).PeerID()) +} + +func getCapability(ccipCapName, ccipCapVersion string) registrysyncer.Capability { + id := fmt.Sprintf("%s@%s", ccipCapName, ccipCapVersion) + return registrysyncer.Capability{ + CapabilityType: capabilities.CapabilityTypeTarget, + ID: id, + } +} + +func getDON(id uint32, members []ragep2ptypes.PeerID, cfgVersion uint32) capabilities.DON { + return capabilities.DON{ + ID: id, + ConfigVersion: cfgVersion, + F: uint8(1), + IsPublic: true, + AcceptsWorkflows: true, + Members: members, + } +} diff --git a/core/capabilities/ccip/ocrimpls/config_tracker.go b/core/capabilities/ccip/ocrimpls/config_tracker.go index f32c796a7a4..3a6a27fa40c 100644 --- a/core/capabilities/ccip/ocrimpls/config_tracker.go +++ b/core/capabilities/ccip/ocrimpls/config_tracker.go @@ -6,6 +6,7 @@ import ( cctypes "github.com/smartcontractkit/chainlink/v2/core/capabilities/ccip/types" gethcommon "github.com/ethereum/go-ethereum/common" + "github.com/smartcontractkit/libocr/offchainreporting2plus/ocr3confighelper" "github.com/smartcontractkit/libocr/offchainreporting2plus/types" ) @@ -24,6 +25,20 @@ func (c *configTracker) LatestBlockHeight(ctx context.Context) (blockHeight uint // LatestConfig implements types.ContractConfigTracker. func (c *configTracker) LatestConfig(ctx context.Context, changedInBlock uint64) (types.ContractConfig, error) { + return c.contractConfig(), nil +} + +// LatestConfigDetails implements types.ContractConfigTracker. +func (c *configTracker) LatestConfigDetails(ctx context.Context) (changedInBlock uint64, configDigest types.ConfigDigest, err error) { + return 0, c.cfg.ConfigDigest, nil +} + +// Notify implements types.ContractConfigTracker. +func (c *configTracker) Notify() <-chan struct{} { + return nil +} + +func (c *configTracker) contractConfig() types.ContractConfig { return types.ContractConfig{ ConfigDigest: c.cfg.ConfigDigest, ConfigCount: c.cfg.ConfigCount, @@ -33,17 +48,13 @@ func (c *configTracker) LatestConfig(ctx context.Context, changedInBlock uint64) OnchainConfig: []byte{}, OffchainConfigVersion: c.cfg.Config.OffchainConfigVersion, OffchainConfig: c.cfg.Config.OffchainConfig, - }, nil -} - -// LatestConfigDetails implements types.ContractConfigTracker. -func (c *configTracker) LatestConfigDetails(ctx context.Context) (changedInBlock uint64, configDigest types.ConfigDigest, err error) { - return 0, c.cfg.ConfigDigest, nil + } } -// Notify implements types.ContractConfigTracker. -func (c *configTracker) Notify() <-chan struct{} { - return nil +// PublicConfig returns the OCR configuration as a PublicConfig so that we can +// access ReportingPluginConfig and other fields prior to launching the plugins. +func (c *configTracker) PublicConfig() (ocr3confighelper.PublicConfig, error) { + return ocr3confighelper.PublicConfigFromContractConfig(false, c.contractConfig()) } func toOnchainPublicKeys(signers [][]byte) []types.OnchainPublicKey { diff --git a/core/capabilities/ccip/oraclecreator/inprocess.go b/core/capabilities/ccip/oraclecreator/inprocess.go index 1d178678461..6616d356756 100644 --- a/core/capabilities/ccip/oraclecreator/inprocess.go +++ b/core/capabilities/ccip/oraclecreator/inprocess.go @@ -18,6 +18,7 @@ import ( chainsel "github.com/smartcontractkit/chain-selectors" "github.com/smartcontractkit/chainlink-ccip/pkg/consts" + "github.com/smartcontractkit/chainlink-ccip/pluginconfig" "github.com/smartcontractkit/libocr/commontypes" libocr3 "github.com/smartcontractkit/libocr/offchainreporting2plus" @@ -46,6 +47,10 @@ import ( var _ cctypes.OracleCreator = &inprocessOracleCreator{} +const ( + defaultCommitGasLimit = 500_000 +) + // inprocessOracleCreator creates oracles that reference plugins running // in the same process as the chainlink node, i.e not LOOPPs. type inprocessOracleCreator struct { @@ -148,6 +153,24 @@ func (i *inprocessOracleCreator) CreatePluginOracle(pluginType cctypes.PluginTyp destChainFamily := relay.NetworkEVM destRelayID := types.NewRelayID(destChainFamily, fmt.Sprintf("%d", destChainID)) + configTracker := ocrimpls.NewConfigTracker(config) + publicConfig, err := configTracker.PublicConfig() + if err != nil { + return nil, fmt.Errorf("failed to get public config from OCR config: %w", err) + } + var execBatchGasLimit uint64 + if pluginType == cctypes.PluginTypeCCIPExec { + execOffchainConfig, err2 := pluginconfig.DecodeExecuteOffchainConfig(publicConfig.ReportingPluginConfig) + if err2 != nil { + return nil, fmt.Errorf("failed to decode execute offchain config: %w, raw: %s", + err2, string(publicConfig.ReportingPluginConfig)) + } + if execOffchainConfig.BatchGasLimit == 0 && destChainFamily == relay.NetworkEVM { + return nil, fmt.Errorf("BatchGasLimit not set in execute offchain config, must be > 0") + } + execBatchGasLimit = execOffchainConfig.BatchGasLimit + } + // this is so that we can use the msg hasher and report encoder from that dest chain relayer's provider. contractReaders := make(map[cciptypes.ChainSelector]types.ContractReader) chainWriters := make(map[cciptypes.ChainSelector]types.ChainWriter) @@ -208,7 +231,12 @@ func (i *inprocessOracleCreator) CreatePluginOracle(pluginType cctypes.PluginTyp chain.Client(), chain.TxManager(), chain.GasEstimator(), - evmconfig.ChainWriterConfigRaw(fromAddress, chain.Config().EVM().GasEstimator().PriceMaxKey(fromAddress)), + evmconfig.ChainWriterConfigRaw( + fromAddress, + chain.Config().EVM().GasEstimator().PriceMaxKey(fromAddress), + defaultCommitGasLimit, + execBatchGasLimit, + ), ) if err2 != nil { return nil, fmt.Errorf("failed to create chain writer for chain %s: %w", chain.ID(), err2) @@ -297,7 +325,7 @@ func (i *inprocessOracleCreator) CreatePluginOracle(pluginType cctypes.PluginTyp BinaryNetworkEndpointFactory: i.peerWrapper.Peer2, Database: i.db, V2Bootstrappers: i.bootstrapperLocators, - ContractConfigTracker: ocrimpls.NewConfigTracker(config), + ContractConfigTracker: configTracker, ContractTransmitter: transmitter, LocalConfig: defaultLocalConfig(), Logger: ocrcommon.NewOCRWrapper( diff --git a/core/capabilities/integration_tests/mock_trigger.go b/core/capabilities/integration_tests/mock_trigger.go index cb673f54ff6..0ed1fe5c8dd 100644 --- a/core/capabilities/integration_tests/mock_trigger.go +++ b/core/capabilities/integration_tests/mock_trigger.go @@ -88,18 +88,20 @@ func (s *streamsTrigger) RegisterTrigger(ctx context.Context, request capabiliti responseCh := make(chan capabilities.CapabilityResponse) - ctxWithCancel, cancel := context.WithCancel(ctx) + ctxWithCancel, cancel := context.WithCancel(context.Background()) s.cancel = cancel s.wg.Add(1) go func() { defer s.wg.Done() - select { - case <-s.stopCh: - return - case <-ctxWithCancel.Done(): - return - case resp := <-s.toSend: - responseCh <- resp + for { + select { + case <-s.stopCh: + return + case <-ctxWithCancel.Done(): + return + case resp := <-s.toSend: + responseCh <- resp + } } }() diff --git a/core/capabilities/integration_tests/streams_test.go b/core/capabilities/integration_tests/streams_test.go index 7be392932f8..8c8f51914c2 100644 --- a/core/capabilities/integration_tests/streams_test.go +++ b/core/capabilities/integration_tests/streams_test.go @@ -24,7 +24,7 @@ func Test_AllAtOnceTransmissionSchedule(t *testing.T) { // in the setupCapabilitiesRegistryContract function, should this order change the don IDs will need updating. workflowDonInfo := createDonInfo(t, don{id: 1, numNodes: 7, f: 2}) triggerDonInfo := createDonInfo(t, don{id: 2, numNodes: 7, f: 2}) - targetDonInfo := createDonInfo(t, don{id: 3, numNodes: 4, f: 2}) + targetDonInfo := createDonInfo(t, don{id: 3, numNodes: 4, f: 1}) consumer, feedIDs, triggerSink := setupStreamDonsWithTransmissionSchedule(ctx, t, workflowDonInfo, triggerDonInfo, targetDonInfo, 3, "2s", "allAtOnce") @@ -45,8 +45,8 @@ func Test_OneAtATimeTransmissionSchedule(t *testing.T) { // The don IDs set in the below calls are inferred from the order in which the dons are added to the capabilities registry // in the setupCapabilitiesRegistryContract function, should this order change the don IDs will need updating. - workflowDonInfo := createDonInfo(t, don{id: 1, numNodes: 5, f: 1}) - triggerDonInfo := createDonInfo(t, don{id: 2, numNodes: 7, f: 1}) + workflowDonInfo := createDonInfo(t, don{id: 1, numNodes: 7, f: 2}) + triggerDonInfo := createDonInfo(t, don{id: 2, numNodes: 7, f: 2}) targetDonInfo := createDonInfo(t, don{id: 3, numNodes: 4, f: 1}) consumer, feedIDs, triggerSink := setupStreamDonsWithTransmissionSchedule(ctx, t, workflowDonInfo, triggerDonInfo, targetDonInfo, 3, diff --git a/core/capabilities/launcher.go b/core/capabilities/launcher.go index b30477e4c83..3fc321087b8 100644 --- a/core/capabilities/launcher.go +++ b/core/capabilities/launcher.go @@ -7,13 +7,17 @@ import ( "strings" "time" + "google.golang.org/protobuf/proto" + "github.com/smartcontractkit/chainlink-common/pkg/capabilities" "github.com/smartcontractkit/chainlink-common/pkg/capabilities/triggers" "github.com/smartcontractkit/chainlink-common/pkg/services" + "github.com/smartcontractkit/chainlink-common/pkg/values" "github.com/smartcontractkit/libocr/ragep2p" ragetypes "github.com/smartcontractkit/libocr/ragep2p/types" + capabilitiespb "github.com/smartcontractkit/chainlink-common/pkg/capabilities/pb" "github.com/smartcontractkit/chainlink/v2/core/capabilities/remote" "github.com/smartcontractkit/chainlink/v2/core/capabilities/remote/target" remotetypes "github.com/smartcontractkit/chainlink/v2/core/capabilities/remote/types" @@ -46,6 +50,42 @@ type launcher struct { subServices []services.Service } +func unmarshalCapabilityConfig(data []byte) (capabilities.CapabilityConfiguration, error) { + cconf := &capabilitiespb.CapabilityConfig{} + err := proto.Unmarshal(data, cconf) + if err != nil { + return capabilities.CapabilityConfiguration{}, err + } + + var remoteTriggerConfig *capabilities.RemoteTriggerConfig + var remoteTargetConfig *capabilities.RemoteTargetConfig + + switch cconf.GetRemoteConfig().(type) { + case *capabilitiespb.CapabilityConfig_RemoteTriggerConfig: + prtc := cconf.GetRemoteTriggerConfig() + remoteTriggerConfig = &capabilities.RemoteTriggerConfig{} + remoteTriggerConfig.RegistrationRefresh = prtc.RegistrationRefresh.AsDuration() + remoteTriggerConfig.RegistrationExpiry = prtc.RegistrationExpiry.AsDuration() + remoteTriggerConfig.MinResponsesToAggregate = prtc.MinResponsesToAggregate + remoteTriggerConfig.MessageExpiry = prtc.MessageExpiry.AsDuration() + case *capabilitiespb.CapabilityConfig_RemoteTargetConfig: + prtc := cconf.GetRemoteTargetConfig() + remoteTargetConfig = &capabilities.RemoteTargetConfig{} + remoteTargetConfig.RequestHashExcludedAttributes = prtc.RequestHashExcludedAttributes + } + + dc, err := values.FromMapValueProto(cconf.DefaultConfig) + if err != nil { + return capabilities.CapabilityConfiguration{}, err + } + + return capabilities.CapabilityConfiguration{ + DefaultConfig: dc, + RemoteTriggerConfig: remoteTriggerConfig, + RemoteTargetConfig: remoteTargetConfig, + }, nil +} + func NewLauncher( lggr logger.Logger, peerWrapper p2ptypes.PeerWrapper, @@ -196,6 +236,11 @@ func (w *launcher) addRemoteCapabilities(ctx context.Context, myDON registrysync return fmt.Errorf("could not find capability matching id %s", cid) } + capabilityConfig, err := unmarshalCapabilityConfig(c.Config) + if err != nil { + return fmt.Errorf("could not unmarshal capability config for id %s", cid) + } + switch capability.CapabilityType { case capabilities.CapabilityTypeTrigger: newTriggerFn := func(info capabilities.CapabilityInfo) (capabilityService, error) { @@ -224,7 +269,7 @@ func (w *launcher) addRemoteCapabilities(ctx context.Context, myDON registrysync // When this is solved, we can move to a generic aggregator // and remove this. triggerCap := remote.NewTriggerSubscriber( - c.RemoteTriggerConfig, + capabilityConfig.RemoteTriggerConfig, info, remoteDON.DON, myDON.DON, @@ -333,11 +378,16 @@ func (w *launcher) exposeCapabilities(ctx context.Context, myPeerID p2ptypes.Pee return fmt.Errorf("could not find capability matching id %s", cid) } + capabilityConfig, err := unmarshalCapabilityConfig(c.Config) + if err != nil { + return fmt.Errorf("could not unmarshal capability config for id %s", cid) + } + switch capability.CapabilityType { case capabilities.CapabilityTypeTrigger: newTriggerPublisher := func(capability capabilities.BaseCapability, info capabilities.CapabilityInfo) (receiverService, error) { publisher := remote.NewTriggerPublisher( - c.RemoteTriggerConfig, + capabilityConfig.RemoteTriggerConfig, capability.(capabilities.TriggerCapability), info, don.DON, @@ -359,7 +409,7 @@ func (w *launcher) exposeCapabilities(ctx context.Context, myPeerID p2ptypes.Pee case capabilities.CapabilityTypeTarget: newTargetServer := func(capability capabilities.BaseCapability, info capabilities.CapabilityInfo) (receiverService, error) { return target.NewServer( - c.RemoteTargetConfig, + capabilityConfig.RemoteTargetConfig, myPeerID, capability.(capabilities.TargetCapability), info, diff --git a/core/capabilities/launcher_test.go b/core/capabilities/launcher_test.go index 82b03edcecb..8bca3be0db1 100644 --- a/core/capabilities/launcher_test.go +++ b/core/capabilities/launcher_test.go @@ -4,14 +4,18 @@ import ( "context" "crypto/rand" "testing" + "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/require" + "google.golang.org/protobuf/proto" + "google.golang.org/protobuf/types/known/durationpb" ragetypes "github.com/smartcontractkit/libocr/ragep2p/types" "github.com/smartcontractkit/chainlink-common/pkg/capabilities" + capabilitiespb "github.com/smartcontractkit/chainlink-common/pkg/capabilities/pb" "github.com/smartcontractkit/chainlink-common/pkg/utils/tests" "github.com/smartcontractkit/chainlink/v2/core/capabilities/remote" remoteMocks "github.com/smartcontractkit/chainlink/v2/core/capabilities/remote/types/mocks" @@ -121,7 +125,7 @@ func TestLauncher_WiresUpExternalCapabilities(t *testing.T) { AcceptsWorkflows: true, Members: nodes, }, - CapabilityConfigurations: map[string]capabilities.CapabilityConfiguration{ + CapabilityConfigurations: map[string]registrysyncer.CapabilityConfiguration{ fullTriggerCapID: {}, fullTargetID: {}, }, @@ -223,7 +227,7 @@ func TestSyncer_IgnoresCapabilitiesForPrivateDON(t *testing.T) { AcceptsWorkflows: true, Members: nodes, }, - CapabilityConfigurations: map[string]capabilities.CapabilityConfiguration{ + CapabilityConfigurations: map[string]registrysyncer.CapabilityConfiguration{ triggerID: {}, targetID: {}, }, @@ -326,6 +330,15 @@ func TestLauncher_WiresUpClientsForPublicWorkflowDON(t *testing.T) { rtc := &capabilities.RemoteTriggerConfig{} rtc.ApplyDefaults() + cfg, err := proto.Marshal(&capabilitiespb.CapabilityConfig{ + RemoteConfig: &capabilitiespb.CapabilityConfig_RemoteTriggerConfig{ + RemoteTriggerConfig: &capabilitiespb.RemoteTriggerConfig{ + RegistrationRefresh: durationpb.New(1 * time.Second), + }, + }, + }) + require.NoError(t, err) + state := ®istrysyncer.LocalRegistry{ IDsToDONs: map[registrysyncer.DonID]registrysyncer.DON{ registrysyncer.DonID(dID): { @@ -347,12 +360,12 @@ func TestLauncher_WiresUpClientsForPublicWorkflowDON(t *testing.T) { AcceptsWorkflows: false, Members: capabilityDonNodes, }, - CapabilityConfigurations: map[string]capabilities.CapabilityConfiguration{ + CapabilityConfigurations: map[string]registrysyncer.CapabilityConfiguration{ fullTriggerCapID: { - RemoteTriggerConfig: rtc, + Config: cfg, }, fullTargetID: { - RemoteTriggerConfig: rtc, + Config: cfg, }, }, }, @@ -496,7 +509,7 @@ func TestLauncher_WiresUpClientsForPublicWorkflowDONButIgnoresPrivateCapabilitie AcceptsWorkflows: false, Members: capabilityDonNodes, }, - CapabilityConfigurations: map[string]capabilities.CapabilityConfiguration{ + CapabilityConfigurations: map[string]registrysyncer.CapabilityConfiguration{ fullTriggerCapID: {}, }, }, @@ -509,7 +522,7 @@ func TestLauncher_WiresUpClientsForPublicWorkflowDONButIgnoresPrivateCapabilitie AcceptsWorkflows: false, Members: capabilityDonNodes, }, - CapabilityConfigurations: map[string]capabilities.CapabilityConfiguration{ + CapabilityConfigurations: map[string]registrysyncer.CapabilityConfiguration{ fullTargetID: {}, }, }, @@ -653,7 +666,7 @@ func TestLauncher_SucceedsEvenIfDispatcherAlreadyHasReceiver(t *testing.T) { AcceptsWorkflows: false, Members: capabilityDonNodes, }, - CapabilityConfigurations: map[string]capabilities.CapabilityConfiguration{ + CapabilityConfigurations: map[string]registrysyncer.CapabilityConfiguration{ fullTriggerCapID: {}, }, }, diff --git a/core/capabilities/registry.go b/core/capabilities/registry.go index 8a99450c096..c3ebaab6b97 100644 --- a/core/capabilities/registry.go +++ b/core/capabilities/registry.go @@ -8,6 +8,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/capabilities" "github.com/smartcontractkit/chainlink/v2/core/logger" + "github.com/smartcontractkit/chainlink/v2/core/services/registrysyncer" ) var ( @@ -16,7 +17,7 @@ var ( type metadataRegistry interface { LocalNode(ctx context.Context) (capabilities.Node, error) - ConfigForCapability(ctx context.Context, capabilityID string, donID uint32) (capabilities.CapabilityConfiguration, error) + ConfigForCapability(ctx context.Context, capabilityID string, donID uint32) (registrysyncer.CapabilityConfiguration, error) } // Registry is a struct for the registry of capabilities. @@ -41,7 +42,12 @@ func (r *Registry) ConfigForCapability(ctx context.Context, capabilityID string, return capabilities.CapabilityConfiguration{}, errors.New("metadataRegistry information not available") } - return r.metadataRegistry.ConfigForCapability(ctx, capabilityID, donID) + cfc, err := r.metadataRegistry.ConfigForCapability(ctx, capabilityID, donID) + if err != nil { + return capabilities.CapabilityConfiguration{}, err + } + + return unmarshalCapabilityConfig(cfc.Config) } // SetLocalRegistry sets a local copy of the offchain registry for the registry to use. diff --git a/core/chains/evm/client/simulated_backend_client.go b/core/chains/evm/client/simulated_backend_client.go index 6bcc1f36960..7dfd39f444c 100644 --- a/core/chains/evm/client/simulated_backend_client.go +++ b/core/chains/evm/client/simulated_backend_client.go @@ -360,9 +360,18 @@ func (c *SimulatedBackendClient) SendTransactionReturnCode(ctx context.Context, // SendTransaction sends a transaction. func (c *SimulatedBackendClient) SendTransaction(ctx context.Context, tx *types.Transaction) error { - sender, err := types.Sender(types.NewLondonSigner(c.chainId), tx) + var ( + sender common.Address + err error + ) + // try to recover the sender from the transaction using the configured chain id + // first. if that fails, try again with the simulated chain id (1337) + sender, err = types.Sender(types.NewLondonSigner(c.chainId), tx) if err != nil { - logger.Test(c.t).Panic(fmt.Errorf("invalid transaction: %v (tx: %#v)", err, tx)) + sender, err = types.Sender(types.NewLondonSigner(big.NewInt(1337)), tx) + if err != nil { + logger.Test(c.t).Panic(fmt.Errorf("invalid transaction: %v (tx: %#v)", err, tx)) + } } pendingNonce, err := c.b.PendingNonceAt(ctx, sender) if err != nil { diff --git a/core/scripts/go.mod b/core/scripts/go.mod index ce3ac907a29..6c674a4128d 100644 --- a/core/scripts/go.mod +++ b/core/scripts/go.mod @@ -270,6 +270,7 @@ require ( github.com/shirou/gopsutil v3.21.11+incompatible // indirect github.com/shirou/gopsutil/v3 v3.24.3 // indirect github.com/smartcontractkit/chain-selectors v1.0.10 // indirect + github.com/smartcontractkit/chainlink-ccip v0.0.0-20240806144315-04ac101e9c95 // indirect github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240710121324-3ed288aa9b45 // indirect github.com/smartcontractkit/chainlink-data-streams v0.0.0-20240801131703-fd75761c982f // indirect github.com/smartcontractkit/chainlink-feeds v0.0.0-20240710170203-5b41615da827 // indirect @@ -330,7 +331,7 @@ require ( go.uber.org/zap v1.27.0 // indirect golang.org/x/arch v0.8.0 // indirect golang.org/x/crypto v0.25.0 // indirect - golang.org/x/exp v0.0.0-20240716175740-e3f259677ff7 // indirect + golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect golang.org/x/mod v0.19.0 // indirect golang.org/x/net v0.27.0 // indirect golang.org/x/oauth2 v0.21.0 // indirect diff --git a/core/scripts/go.sum b/core/scripts/go.sum index cc6576e08d2..53108870884 100644 --- a/core/scripts/go.sum +++ b/core/scripts/go.sum @@ -1184,6 +1184,8 @@ github.com/smartcontractkit/chain-selectors v1.0.10 h1:t9kJeE6B6G+hKD0GYR4kGJSCq github.com/smartcontractkit/chain-selectors v1.0.10/go.mod h1:d4Hi+E1zqjy9HqMkjBE5q1vcG9VGgxf5VxiRHfzi2kE= github.com/smartcontractkit/chainlink-automation v1.0.4 h1:iyW181JjKHLNMnDleI8umfIfVVlwC7+n5izbLSFgjw8= github.com/smartcontractkit/chainlink-automation v1.0.4/go.mod h1:u4NbPZKJ5XiayfKHD/v3z3iflQWqvtdhj13jVZXj/cM= +github.com/smartcontractkit/chainlink-ccip v0.0.0-20240806144315-04ac101e9c95 h1:LAgJTg9Yr/uCo2g7Krp88Dco2U45Y6sbJVl8uKoLkys= +github.com/smartcontractkit/chainlink-ccip v0.0.0-20240806144315-04ac101e9c95/go.mod h1:/ZWraCBaDDgaIN1prixYcbVvIk/6HeED9+8zbWQ+TMo= github.com/smartcontractkit/chainlink-common v0.2.2-0.20240805160614-501c4f40b98c h1:3apUsez/6Pkp1ckXzSwIhzPRuWjDGjzMjKapEKi0Fcw= github.com/smartcontractkit/chainlink-common v0.2.2-0.20240805160614-501c4f40b98c/go.mod h1:Jg1sCTsbxg76YByI8ifpFby3FvVqISStHT8ypy9ocmY= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240710121324-3ed288aa9b45 h1:NBQLtqk8zsyY4qTJs+NElI3aDFTcAo83JHvqD04EvB0= @@ -1484,8 +1486,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= -golang.org/x/exp v0.0.0-20240716175740-e3f259677ff7 h1:wDLEX9a7YQoKdKNQt88rtydkqDxeGaBUTnIYc3iG/mA= -golang.org/x/exp v0.0.0-20240716175740-e3f259677ff7/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY= +golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8= +golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= diff --git a/core/services/chainlink/application.go b/core/services/chainlink/application.go index 138ca25ed3b..c94d2fb8161 100644 --- a/core/services/chainlink/application.go +++ b/core/services/chainlink/application.go @@ -23,15 +23,14 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/utils" "github.com/smartcontractkit/chainlink-common/pkg/utils/jsonserializable" "github.com/smartcontractkit/chainlink-common/pkg/utils/mailbox" - "github.com/smartcontractkit/chainlink/v2/core/capabilities" - "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" - "github.com/smartcontractkit/chainlink/v2/core/services/standardcapabilities" - "github.com/smartcontractkit/chainlink/v2/core/static" "github.com/smartcontractkit/chainlink/v2/core/bridges" "github.com/smartcontractkit/chainlink/v2/core/build" + "github.com/smartcontractkit/chainlink/v2/core/capabilities" + "github.com/smartcontractkit/chainlink/v2/core/capabilities/ccip" "github.com/smartcontractkit/chainlink/v2/core/capabilities/remote" remotetypes "github.com/smartcontractkit/chainlink/v2/core/capabilities/remote/types" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/logpoller" "github.com/smartcontractkit/chainlink/v2/core/chains/evm/txmgr" evmtypes "github.com/smartcontractkit/chainlink/v2/core/chains/evm/types" evmutils "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" @@ -61,6 +60,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/services/registrysyncer" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/mercury/wsrpc" + "github.com/smartcontractkit/chainlink/v2/core/services/standardcapabilities" "github.com/smartcontractkit/chainlink/v2/core/services/streams" "github.com/smartcontractkit/chainlink/v2/core/services/telemetry" "github.com/smartcontractkit/chainlink/v2/core/services/vrf" @@ -70,6 +70,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/sessions" "github.com/smartcontractkit/chainlink/v2/core/sessions/ldapauth" "github.com/smartcontractkit/chainlink/v2/core/sessions/localauth" + "github.com/smartcontractkit/chainlink/v2/core/static" "github.com/smartcontractkit/chainlink/v2/plugins" ) @@ -213,41 +214,51 @@ func NewApplication(opts ApplicationOpts) (Application, error) { externalPeer := externalp2p.NewExternalPeerWrapper(keyStore.P2P(), cfg.Capabilities().Peering(), opts.DS, globalLogger) signer := externalPeer externalPeerWrapper = externalPeer - dispatcher = remote.NewDispatcher(externalPeerWrapper, signer, opts.CapabilitiesRegistry, globalLogger) - srvcs = append(srvcs, externalPeerWrapper) // peer wrapper must be started before dispatcher - srvcs = append(srvcs, dispatcher) - } else { // tests only + remoteDispatcher := remote.NewDispatcher(externalPeerWrapper, signer, opts.CapabilitiesRegistry, globalLogger) + srvcs = append(srvcs, remoteDispatcher) + + dispatcher = remoteDispatcher + } else { dispatcher = opts.CapabilitiesDispatcher externalPeerWrapper = opts.CapabilitiesPeerWrapper - srvcs = append(srvcs, externalPeerWrapper) } - rid := cfg.Capabilities().ExternalRegistry().RelayID() - registryAddress := cfg.Capabilities().ExternalRegistry().Address() - relayer, err := relayerChainInterops.Get(rid) - if err != nil { - return nil, fmt.Errorf("could not fetch relayer %s configured for capabilities registry: %w", rid, err) - } + srvcs = append(srvcs, externalPeerWrapper, dispatcher) - registrySyncer, err := registrysyncer.New( - globalLogger, - externalPeerWrapper, - relayer, - registryAddress, - ) - if err != nil { - return nil, fmt.Errorf("could not configure syncer: %w", err) - } + if cfg.Capabilities().ExternalRegistry().Address() != "" { + rid := cfg.Capabilities().ExternalRegistry().RelayID() + registryAddress := cfg.Capabilities().ExternalRegistry().Address() + relayer, err := relayerChainInterops.Get(rid) + if err != nil { + return nil, fmt.Errorf("could not fetch relayer %s configured for capabilities registry: %w", rid, err) + } + registrySyncer, err := registrysyncer.New( + globalLogger, + func() (p2ptypes.PeerID, error) { + p := externalPeerWrapper.GetPeer() + if p == nil { + return p2ptypes.PeerID{}, errors.New("could not get peer") + } - wfLauncher := capabilities.NewLauncher( - globalLogger, - externalPeerWrapper, - dispatcher, - opts.CapabilitiesRegistry, - ) - registrySyncer.AddLauncher(wfLauncher) + return p.ID(), nil + }, + relayer, + registryAddress, + ) + if err != nil { + return nil, fmt.Errorf("could not configure syncer: %w", err) + } + + wfLauncher := capabilities.NewLauncher( + globalLogger, + externalPeerWrapper, + dispatcher, + opts.CapabilitiesRegistry, + ) + registrySyncer.AddLauncher(wfLauncher) - srvcs = append(srvcs, dispatcher, wfLauncher, registrySyncer) + srvcs = append(srvcs, wfLauncher, registrySyncer) + } } // LOOPs can be created as options, in the case of LOOP relayers, or @@ -518,6 +529,18 @@ func NewApplication(opts ApplicationOpts) (Application, error) { cfg.Insecure(), opts.RelayerChainInteroperators, ) + delegates[job.CCIP] = ccip.NewDelegate( + globalLogger, + loopRegistrarConfig, + pipelineRunner, + opts.RelayerChainInteroperators.LegacyEVMChains(), + relayerChainInterops, + opts.KeyStore, + opts.DS, + peerWrapper, + telemetryManager, + cfg.Capabilities(), + ) } else { globalLogger.Debug("Off-chain reporting v2 disabled") } diff --git a/core/services/job/models.go b/core/services/job/models.go index 2f864efe300..1c46d08c59c 100644 --- a/core/services/job/models.go +++ b/core/services/job/models.go @@ -38,6 +38,7 @@ const ( BlockhashStore Type = (Type)(pipeline.BlockhashStoreJobType) Bootstrap Type = (Type)(pipeline.BootstrapJobType) Cron Type = (Type)(pipeline.CronJobType) + CCIP Type = (Type)(pipeline.CCIPJobType) DirectRequest Type = (Type)(pipeline.DirectRequestJobType) FluxMonitor Type = (Type)(pipeline.FluxMonitorJobType) Gateway Type = (Type)(pipeline.GatewayJobType) @@ -78,6 +79,7 @@ var ( BlockhashStore: false, Bootstrap: false, Cron: true, + CCIP: false, DirectRequest: true, FluxMonitor: true, Gateway: false, @@ -97,6 +99,7 @@ var ( BlockhashStore: false, Bootstrap: false, Cron: true, + CCIP: false, DirectRequest: true, FluxMonitor: false, Gateway: false, @@ -116,6 +119,7 @@ var ( BlockhashStore: 1, Bootstrap: 1, Cron: 1, + CCIP: 1, DirectRequest: 1, FluxMonitor: 1, Gateway: 1, @@ -176,6 +180,7 @@ type Job struct { StandardCapabilitiesSpecID *int32 StandardCapabilitiesSpec *StandardCapabilitiesSpec CCIPSpecID *int32 + CCIPSpec *CCIPSpec CCIPBootstrapSpecID *int32 JobSpecErrors []SpecError Type Type `toml:"type"` @@ -910,3 +915,48 @@ func (w *StandardCapabilitiesSpec) SetID(value string) error { w.ID = int32(ID) return nil } + +type CCIPSpec struct { + ID int32 + CreatedAt time.Time `toml:"-"` + UpdatedAt time.Time `toml:"-"` + + // P2PV2Bootstrappers is a list of "peer_id@ip_address:port" strings that are used to + // identify the bootstrap nodes of the P2P network. + // These bootstrappers will be used to bootstrap all CCIP DONs. + P2PV2Bootstrappers pq.StringArray `toml:"p2pV2Bootstrappers" db:"p2pv2_bootstrappers"` + + // CapabilityVersion is the semantic version of the CCIP capability. + // This capability version must exist in the onchain capability registry. + CapabilityVersion string `toml:"capabilityVersion" db:"capability_version"` + + // CapabilityLabelledName is the labelled name of the CCIP capability. + // Corresponds to the labelled name of the capability in the onchain capability registry. + CapabilityLabelledName string `toml:"capabilityLabelledName" db:"capability_labelled_name"` + + // OCRKeyBundleIDs is a mapping from chain type to OCR key bundle ID. + // These are explicitly specified here so that we don't run into strange errors auto-detecting + // the valid bundle, since nops can create as many bundles as they want. + // This will most likely never change for a particular CCIP capability version, + // since new chain families will likely require a new capability version. + // {"evm": "evm_key_bundle_id", "solana": "solana_key_bundle_id", ... } + OCRKeyBundleIDs JSONConfig `toml:"ocrKeyBundleIDs" db:"ocr_key_bundle_ids"` + + // RelayConfigs consists of relay specific configuration. + // Chain reader configurations are stored here, and are defined on a chain family basis, e.g + // we will have one chain reader config for EVM, one for solana, starknet, etc. + // Chain writer configurations are also stored here, and are also defined on a chain family basis, + // e.g we will have one chain writer config for EVM, one for solana, starknet, etc. + // See tests for examples of relay configs in TOML. + // { "evm": {"chainReader": {...}, "chainWriter": {...}}, "solana": {...}, ... } + // see core/services/relay/evm/types/types.go for EVM configs. + RelayConfigs JSONConfig `toml:"relayConfigs" db:"relay_configs"` + + // P2PKeyID is the ID of the P2P key of the node. + // This must be present in the capability registry otherwise the job will not start correctly. + P2PKeyID string `toml:"p2pKeyID" db:"p2p_key_id"` + + // PluginConfig contains plugin-specific config, like token price pipelines + // and RMN network info for offchain blessing. + PluginConfig JSONConfig `toml:"pluginConfig"` +} diff --git a/core/services/job/orm.go b/core/services/job/orm.go index d13decc7208..ac3bb655306 100644 --- a/core/services/job/orm.go +++ b/core/services/job/orm.go @@ -425,7 +425,34 @@ func (o *orm) CreateJob(ctx context.Context, jb *Job) error { return errors.Wrap(err, "failed to create StandardCapabilities for jobSpec") } jb.StandardCapabilitiesSpecID = &specID - + case CCIP: + sql := `INSERT INTO ccip_specs ( + capability_version, + capability_labelled_name, + ocr_key_bundle_ids, + p2p_key_id, + p2pv2_bootstrappers, + relay_configs, + plugin_config, + created_at, + updated_at + ) VALUES ( + :capability_version, + :capability_labelled_name, + :ocr_key_bundle_ids, + :p2p_key_id, + :p2pv2_bootstrappers, + :relay_configs, + :plugin_config, + NOW(), + NOW() + ) + RETURNING id;` + specID, err := tx.prepareQuerySpecID(ctx, sql, jb.CCIPSpec) + if err != nil { + return errors.Wrap(err, "failed to create CCIPSpec for jobSpec") + } + jb.CCIPSpecID = &specID default: o.lggr.Panicf("Unsupported jb.Type: %v", jb.Type) } @@ -643,19 +670,19 @@ func (o *orm) InsertJob(ctx context.Context, job *Job) error { // if job has id, emplace otherwise insert with a new id. if job.ID == 0 { query = `INSERT INTO jobs (name, stream_id, schema_version, type, max_task_duration, ocr_oracle_spec_id, ocr2_oracle_spec_id, direct_request_spec_id, flux_monitor_spec_id, - keeper_spec_id, cron_spec_id, vrf_spec_id, webhook_spec_id, blockhash_store_spec_id, bootstrap_spec_id, block_header_feeder_spec_id, gateway_spec_id, - legacy_gas_station_server_spec_id, legacy_gas_station_sidecar_spec_id, workflow_spec_id, standard_capabilities_spec_id, external_job_id, gas_limit, forwarding_allowed, created_at) + keeper_spec_id, cron_spec_id, vrf_spec_id, webhook_spec_id, blockhash_store_spec_id, bootstrap_spec_id, block_header_feeder_spec_id, gateway_spec_id, + legacy_gas_station_server_spec_id, legacy_gas_station_sidecar_spec_id, workflow_spec_id, standard_capabilities_spec_id, ccip_spec_id, external_job_id, gas_limit, forwarding_allowed, created_at) VALUES (:name, :stream_id, :schema_version, :type, :max_task_duration, :ocr_oracle_spec_id, :ocr2_oracle_spec_id, :direct_request_spec_id, :flux_monitor_spec_id, - :keeper_spec_id, :cron_spec_id, :vrf_spec_id, :webhook_spec_id, :blockhash_store_spec_id, :bootstrap_spec_id, :block_header_feeder_spec_id, :gateway_spec_id, - :legacy_gas_station_server_spec_id, :legacy_gas_station_sidecar_spec_id, :workflow_spec_id, :standard_capabilities_spec_id, :external_job_id, :gas_limit, :forwarding_allowed, NOW()) + :keeper_spec_id, :cron_spec_id, :vrf_spec_id, :webhook_spec_id, :blockhash_store_spec_id, :bootstrap_spec_id, :block_header_feeder_spec_id, :gateway_spec_id, + :legacy_gas_station_server_spec_id, :legacy_gas_station_sidecar_spec_id, :workflow_spec_id, :standard_capabilities_spec_id, :ccip_spec_id, :external_job_id, :gas_limit, :forwarding_allowed, NOW()) RETURNING *;` } else { query = `INSERT INTO jobs (id, name, stream_id, schema_version, type, max_task_duration, ocr_oracle_spec_id, ocr2_oracle_spec_id, direct_request_spec_id, flux_monitor_spec_id, - keeper_spec_id, cron_spec_id, vrf_spec_id, webhook_spec_id, blockhash_store_spec_id, bootstrap_spec_id, block_header_feeder_spec_id, gateway_spec_id, - legacy_gas_station_server_spec_id, legacy_gas_station_sidecar_spec_id, workflow_spec_id, standard_capabilities_spec_id, external_job_id, gas_limit, forwarding_allowed, created_at) + keeper_spec_id, cron_spec_id, vrf_spec_id, webhook_spec_id, blockhash_store_spec_id, bootstrap_spec_id, block_header_feeder_spec_id, gateway_spec_id, + legacy_gas_station_server_spec_id, legacy_gas_station_sidecar_spec_id, workflow_spec_id, standard_capabilities_spec_id, ccip_spec_id, external_job_id, gas_limit, forwarding_allowed, created_at) VALUES (:id, :name, :stream_id, :schema_version, :type, :max_task_duration, :ocr_oracle_spec_id, :ocr2_oracle_spec_id, :direct_request_spec_id, :flux_monitor_spec_id, - :keeper_spec_id, :cron_spec_id, :vrf_spec_id, :webhook_spec_id, :blockhash_store_spec_id, :bootstrap_spec_id, :block_header_feeder_spec_id, :gateway_spec_id, - :legacy_gas_station_server_spec_id, :legacy_gas_station_sidecar_spec_id, :workflow_spec_id, :standard_capabilities_spec_id, :external_job_id, :gas_limit, :forwarding_allowed, NOW()) + :keeper_spec_id, :cron_spec_id, :vrf_spec_id, :webhook_spec_id, :blockhash_store_spec_id, :bootstrap_spec_id, :block_header_feeder_spec_id, :gateway_spec_id, + :legacy_gas_station_server_spec_id, :legacy_gas_station_sidecar_spec_id, :workflow_spec_id, :standard_capabilities_spec_id, :ccip_spec_id, :external_job_id, :gas_limit, :forwarding_allowed, NOW()) RETURNING *;` } query, args, err := tx.ds.BindNamed(query, job) @@ -699,7 +726,8 @@ func (o *orm) DeleteJob(ctx context.Context, id int32) error { block_header_feeder_spec_id, gateway_spec_id, workflow_spec_id, - standard_capabilities_spec_id + standard_capabilities_spec_id, + ccip_spec_id ), deleted_oracle_specs AS ( DELETE FROM ocr_oracle_specs WHERE id IN (SELECT ocr_oracle_spec_id FROM deleted_jobs) @@ -742,7 +770,10 @@ func (o *orm) DeleteJob(ctx context.Context, id int32) error { ), deleted_standardcapabilities_specs AS ( DELETE FROM standardcapabilities_specs WHERE id in (SELECT standard_capabilities_spec_id FROM deleted_jobs) - ), + ), + deleted_ccip_specs AS ( + DELETE FROM ccip_specs WHERE id in (SELECT ccip_spec_id FROM deleted_jobs) + ), deleted_job_pipeline_specs AS ( DELETE FROM job_pipeline_specs WHERE job_id IN (SELECT id FROM deleted_jobs) RETURNING pipeline_spec_id ) @@ -816,7 +847,7 @@ func (o *orm) FindJobs(ctx context.Context, offset, limit int) (jobs []Job, coun return fmt.Errorf("failed to query jobs count: %w", err) } - sql = `SELECT jobs.*, job_pipeline_specs.pipeline_spec_id as pipeline_spec_id + sql = `SELECT jobs.*, job_pipeline_specs.pipeline_spec_id as pipeline_spec_id FROM jobs JOIN job_pipeline_specs ON (jobs.id = job_pipeline_specs.job_id) ORDER BY jobs.created_at DESC, jobs.id DESC OFFSET $1 LIMIT $2;` @@ -1030,8 +1061,8 @@ func (o *orm) findJob(ctx context.Context, jb *Job, col string, arg interface{}) } func (o *orm) FindJobIDsWithBridge(ctx context.Context, name string) (jids []int32, err error) { - query := `SELECT - jobs.id, pipeline_specs.dot_dag_source + query := `SELECT + jobs.id, pipeline_specs.dot_dag_source FROM jobs JOIN job_pipeline_specs ON job_pipeline_specs.job_id = jobs.id JOIN pipeline_specs ON pipeline_specs.id = job_pipeline_specs.pipeline_spec_id @@ -1078,7 +1109,7 @@ func (o *orm) FindJobIDsWithBridge(ctx context.Context, name string) (jids []int func (o *orm) FindJobIDByWorkflow(ctx context.Context, spec WorkflowSpec) (jobID int32, err error) { stmt := ` SELECT jobs.id FROM jobs -INNER JOIN workflow_specs ws on jobs.workflow_spec_id = ws.id AND ws.workflow_owner = $1 AND ws.workflow_name = $2 +INNER JOIN workflow_specs ws on jobs.workflow_spec_id = ws.id AND ws.workflow_owner = $1 AND ws.workflow_name = $2 ` err = o.ds.GetContext(ctx, &jobID, stmt, spec.WorkflowOwner, spec.WorkflowName) if err != nil { @@ -1391,6 +1422,7 @@ func (o *orm) loadAllJobTypes(ctx context.Context, job *Job) error { o.loadJobType(ctx, job, "GatewaySpec", "gateway_specs", job.GatewaySpecID), o.loadJobType(ctx, job, "WorkflowSpec", "workflow_specs", job.WorkflowSpecID), o.loadJobType(ctx, job, "StandardCapabilitiesSpec", "standardcapabilities_specs", job.StandardCapabilitiesSpecID), + o.loadJobType(ctx, job, "CCIPSpec", "ccip_specs", job.CCIPSpecID), ) } @@ -1428,7 +1460,7 @@ func (o *orm) loadJobPipelineSpec(ctx context.Context, job *Job, id *int32) erro ctx, pipelineSpecRow, `SELECT pipeline_specs.*, job_pipeline_specs.job_id as job_id - FROM pipeline_specs + FROM pipeline_specs JOIN job_pipeline_specs ON(pipeline_specs.id = job_pipeline_specs.pipeline_spec_id) WHERE job_pipeline_specs.job_id = $1 AND job_pipeline_specs.pipeline_spec_id = $2`, job.ID, *id, diff --git a/core/services/pipeline/common.go b/core/services/pipeline/common.go index 763e50546fd..1b36c8a664b 100644 --- a/core/services/pipeline/common.go +++ b/core/services/pipeline/common.go @@ -29,6 +29,7 @@ const ( BlockhashStoreJobType string = "blockhashstore" BootstrapJobType string = "bootstrap" CronJobType string = "cron" + CCIPJobType string = "ccip" DirectRequestJobType string = "directrequest" FluxMonitorJobType string = "fluxmonitor" GatewayJobType string = "gateway" diff --git a/core/services/registrysyncer/local_registry.go b/core/services/registrysyncer/local_registry.go index 4e4a632bf87..8a0e471ccda 100644 --- a/core/services/registrysyncer/local_registry.go +++ b/core/services/registrysyncer/local_registry.go @@ -16,7 +16,11 @@ type DonID uint32 type DON struct { capabilities.DON - CapabilityConfigurations map[string]capabilities.CapabilityConfiguration + CapabilityConfigurations map[string]CapabilityConfiguration +} + +type CapabilityConfiguration struct { + Config []byte } type Capability struct { @@ -26,7 +30,7 @@ type Capability struct { type LocalRegistry struct { lggr logger.Logger - peerWrapper p2ptypes.PeerWrapper + getPeerID func() (p2ptypes.PeerID, error) IDsToDONs map[DonID]DON IDsToNodes map[p2ptypes.PeerID]kcr.CapabilitiesRegistryNodeInfo IDsToCapabilities map[string]Capability @@ -36,12 +40,11 @@ func (l *LocalRegistry) LocalNode(ctx context.Context) (capabilities.Node, error // Load the current nodes PeerWrapper, this gets us the current node's // PeerID, allowing us to contextualize registry information in terms of DON ownership // (eg. get my current DON configuration, etc). - if l.peerWrapper.GetPeer() == nil { + pid, err := l.getPeerID() + if err != nil { return capabilities.Node{}, errors.New("unable to get local node: peerWrapper hasn't started yet") } - pid := l.peerWrapper.GetPeer().ID() - var workflowDON capabilities.DON capabilityDONs := []capabilities.DON{} for _, d := range l.IDsToDONs { @@ -70,15 +73,15 @@ func (l *LocalRegistry) LocalNode(ctx context.Context) (capabilities.Node, error }, nil } -func (l *LocalRegistry) ConfigForCapability(ctx context.Context, capabilityID string, donID uint32) (capabilities.CapabilityConfiguration, error) { +func (l *LocalRegistry) ConfigForCapability(ctx context.Context, capabilityID string, donID uint32) (CapabilityConfiguration, error) { d, ok := l.IDsToDONs[DonID(donID)] if !ok { - return capabilities.CapabilityConfiguration{}, fmt.Errorf("could not find don %d", donID) + return CapabilityConfiguration{}, fmt.Errorf("could not find don %d", donID) } cc, ok := d.CapabilityConfigurations[capabilityID] if !ok { - return capabilities.CapabilityConfiguration{}, fmt.Errorf("could not find capability configuration for capability %s and donID %d", capabilityID, donID) + return CapabilityConfiguration{}, fmt.Errorf("could not find capability configuration for capability %s and donID %d", capabilityID, donID) } return cc, nil diff --git a/core/services/registrysyncer/syncer.go b/core/services/registrysyncer/syncer.go index 9675d86dc86..83f77e46d35 100644 --- a/core/services/registrysyncer/syncer.go +++ b/core/services/registrysyncer/syncer.go @@ -7,14 +7,10 @@ import ( "sync" "time" - "google.golang.org/protobuf/proto" - "github.com/smartcontractkit/chainlink-common/pkg/capabilities" - capabilitiespb "github.com/smartcontractkit/chainlink-common/pkg/capabilities/pb" "github.com/smartcontractkit/chainlink-common/pkg/services" "github.com/smartcontractkit/chainlink-common/pkg/types" "github.com/smartcontractkit/chainlink-common/pkg/types/query/primitives" - "github.com/smartcontractkit/chainlink-common/pkg/values" kcr "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/keystone/generated/capabilities_registry" "github.com/smartcontractkit/chainlink/v2/core/logger" @@ -39,7 +35,7 @@ type registrySyncer struct { initReader func(ctx context.Context, lggr logger.Logger, relayer contractReaderFactory, registryAddress string) (types.ContractReader, error) relayer contractReaderFactory registryAddress string - peerWrapper p2ptypes.PeerWrapper + getPeerID func() (p2ptypes.PeerID, error) wg sync.WaitGroup lggr logger.Logger @@ -55,7 +51,7 @@ var ( // New instantiates a new RegistrySyncer func New( lggr logger.Logger, - peerWrapper p2ptypes.PeerWrapper, + getPeerID func() (p2ptypes.PeerID, error), relayer contractReaderFactory, registryAddress string, ) (*registrySyncer, error) { @@ -66,7 +62,7 @@ func New( relayer: relayer, registryAddress: registryAddress, initReader: newReader, - peerWrapper: peerWrapper, + getPeerID: getPeerID, }, nil } @@ -158,42 +154,6 @@ func (s *registrySyncer) syncLoop() { } } -func unmarshalCapabilityConfig(data []byte) (capabilities.CapabilityConfiguration, error) { - cconf := &capabilitiespb.CapabilityConfig{} - err := proto.Unmarshal(data, cconf) - if err != nil { - return capabilities.CapabilityConfiguration{}, err - } - - var remoteTriggerConfig *capabilities.RemoteTriggerConfig - var remoteTargetConfig *capabilities.RemoteTargetConfig - - switch cconf.GetRemoteConfig().(type) { - case *capabilitiespb.CapabilityConfig_RemoteTriggerConfig: - prtc := cconf.GetRemoteTriggerConfig() - remoteTriggerConfig = &capabilities.RemoteTriggerConfig{} - remoteTriggerConfig.RegistrationRefresh = prtc.RegistrationRefresh.AsDuration() - remoteTriggerConfig.RegistrationExpiry = prtc.RegistrationExpiry.AsDuration() - remoteTriggerConfig.MinResponsesToAggregate = prtc.MinResponsesToAggregate - remoteTriggerConfig.MessageExpiry = prtc.MessageExpiry.AsDuration() - case *capabilitiespb.CapabilityConfig_RemoteTargetConfig: - prtc := cconf.GetRemoteTargetConfig() - remoteTargetConfig = &capabilities.RemoteTargetConfig{} - remoteTargetConfig.RequestHashExcludedAttributes = prtc.RequestHashExcludedAttributes - } - - dc, err := values.FromMapValueProto(cconf.DefaultConfig) - if err != nil { - return capabilities.CapabilityConfiguration{}, err - } - - return capabilities.CapabilityConfiguration{ - DefaultConfig: dc, - RemoteTriggerConfig: remoteTriggerConfig, - RemoteTargetConfig: remoteTargetConfig, - }, nil -} - func (s *registrySyncer) localRegistry(ctx context.Context) (*LocalRegistry, error) { caps := []kcr.CapabilitiesRegistryCapabilityInfo{} err := s.reader.GetLatestValue(ctx, "CapabilitiesRegistry", "getCapabilities", primitives.Unconfirmed, nil, &caps) @@ -221,19 +181,16 @@ func (s *registrySyncer) localRegistry(ctx context.Context) (*LocalRegistry, err idsToDONs := map[DonID]DON{} for _, d := range dons { - cc := map[string]capabilities.CapabilityConfiguration{} + cc := map[string]CapabilityConfiguration{} for _, dc := range d.CapabilityConfigurations { cid, ok := hashedIDsToCapabilityIDs[dc.CapabilityId] if !ok { return nil, fmt.Errorf("invariant violation: could not find full ID for hashed ID %s", dc.CapabilityId) } - cconf, innerErr := unmarshalCapabilityConfig(dc.Config) - if innerErr != nil { - return nil, innerErr + cc[cid] = CapabilityConfiguration{ + Config: dc.Config, } - - cc[cid] = cconf } idsToDONs[DonID(d.Id)] = DON{ @@ -255,7 +212,7 @@ func (s *registrySyncer) localRegistry(ctx context.Context) (*LocalRegistry, err return &LocalRegistry{ lggr: s.lggr, - peerWrapper: s.peerWrapper, + getPeerID: s.getPeerID, IDsToDONs: idsToDONs, IDsToCapabilities: idsToCapabilities, IDsToNodes: idsToNodes, diff --git a/core/services/registrysyncer/syncer_test.go b/core/services/registrysyncer/syncer_test.go index c13cc904909..cd8776d882c 100644 --- a/core/services/registrysyncer/syncer_test.go +++ b/core/services/registrysyncer/syncer_test.go @@ -33,7 +33,6 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/internal/testutils/pgtest" "github.com/smartcontractkit/chainlink/v2/core/logger" p2ptypes "github.com/smartcontractkit/chainlink/v2/core/services/p2p/types" - "github.com/smartcontractkit/chainlink/v2/core/services/p2p/types/mocks" "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm" evmrelaytypes "github.com/smartcontractkit/chainlink/v2/core/services/relay/evm/types" ) @@ -237,9 +236,8 @@ func TestReader_Integration(t *testing.T) { require.NoError(t, err) - wrapper := mocks.NewPeerWrapper(t) factory := newContractReaderFactory(t, sim) - syncer, err := New(logger.TestLogger(t), wrapper, factory, regAddress.Hex()) + syncer, err := New(logger.TestLogger(t), func() (p2ptypes.PeerID, error) { return p2ptypes.PeerID{}, nil }, factory, regAddress.Hex()) require.NoError(t, err) l := &launcher{} @@ -257,29 +255,17 @@ func TestReader_Integration(t *testing.T) { }, gotCap) assert.Len(t, s.IDsToDONs, 1) - rtc := &capabilities.RemoteTriggerConfig{ - RegistrationRefresh: 20 * time.Second, - MinResponsesToAggregate: 2, - RegistrationExpiry: 60 * time.Second, - MessageExpiry: 120 * time.Second, - } - expectedDON := DON{ - DON: capabilities.DON{ - ID: 1, - ConfigVersion: 1, - IsPublic: true, - AcceptsWorkflows: true, - F: 1, - Members: toPeerIDs(nodeSet), - }, - CapabilityConfigurations: map[string]capabilities.CapabilityConfiguration{ - cid: { - DefaultConfig: values.EmptyMap(), - RemoteTriggerConfig: rtc, - }, - }, + expectedDON := capabilities.DON{ + ID: 1, + ConfigVersion: 1, + IsPublic: true, + AcceptsWorkflows: true, + F: 1, + Members: toPeerIDs(nodeSet), } - assert.Equal(t, expectedDON, s.IDsToDONs[1]) + gotDon := s.IDsToDONs[1] + assert.Equal(t, expectedDON, gotDon.DON) + assert.Equal(t, configb, gotDon.CapabilityConfigurations[cid].Config) nodesInfo := []kcr.CapabilitiesRegistryNodeInfo{ { @@ -329,10 +315,6 @@ func TestSyncer_LocalNode(t *testing.T) { var pid p2ptypes.PeerID err := pid.UnmarshalText([]byte("12D3KooWBCF1XT5Wi8FzfgNCqRL76Swv8TRU3TiD4QiJm8NMNX7N")) require.NoError(t, err) - peer := mocks.NewPeer(t) - peer.On("ID").Return(pid) - wrapper := mocks.NewPeerWrapper(t) - wrapper.On("GetPeer").Return(peer) workflowDonNodes := []p2ptypes.PeerID{ pid, @@ -346,8 +328,8 @@ func TestSyncer_LocalNode(t *testing.T) { // which exposes the streams-trigger and write_chain capabilities. // We expect receivers to be wired up and both capabilities to be added to the registry. localRegistry := LocalRegistry{ - lggr: lggr, - peerWrapper: wrapper, + lggr: lggr, + getPeerID: func() (p2ptypes.PeerID, error) { return pid, nil }, IDsToDONs: map[DonID]DON{ DonID(dID): { DON: capabilities.DON{ diff --git a/core/services/synchronization/common.go b/core/services/synchronization/common.go index bfb9fba6de6..394830a76af 100644 --- a/core/services/synchronization/common.go +++ b/core/services/synchronization/common.go @@ -24,6 +24,10 @@ const ( OCR3Mercury TelemetryType = "ocr3-mercury" AutomationCustom TelemetryType = "automation-custom" OCR3Automation TelemetryType = "ocr3-automation" + OCR3Rebalancer TelemetryType = "ocr3-rebalancer" + OCR3CCIPCommit TelemetryType = "ocr3-ccip-commit" + OCR3CCIPExec TelemetryType = "ocr3-ccip-exec" + OCR3CCIPBootstrap TelemetryType = "ocr3-bootstrap" ) type TelemPayload struct { diff --git a/core/services/workflows/engine_test.go b/core/services/workflows/engine_test.go index 3af87284131..0a38bf719b2 100644 --- a/core/services/workflows/engine_test.go +++ b/core/services/workflows/engine_test.go @@ -11,8 +11,10 @@ import ( "github.com/shopspring/decimal" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "google.golang.org/protobuf/proto" "github.com/smartcontractkit/chainlink-common/pkg/capabilities" + capabilitiespb "github.com/smartcontractkit/chainlink-common/pkg/capabilities/pb" "github.com/smartcontractkit/chainlink-common/pkg/services/servicetest" "github.com/smartcontractkit/chainlink-common/pkg/values" "github.com/smartcontractkit/chainlink-common/pkg/workflows" @@ -22,6 +24,7 @@ import ( "github.com/smartcontractkit/chainlink/v2/core/logger" "github.com/smartcontractkit/chainlink/v2/core/services/job" p2ptypes "github.com/smartcontractkit/chainlink/v2/core/services/p2p/types" + "github.com/smartcontractkit/chainlink/v2/core/services/registrysyncer" "github.com/smartcontractkit/chainlink/v2/core/services/workflows/store" ) @@ -101,7 +104,7 @@ func newTestDBStore(t *testing.T, clock clockwork.Clock) store.Store { type testConfigProvider struct { localNode func(ctx context.Context) (capabilities.Node, error) - configForCapability func(ctx context.Context, capabilityID string, donID uint32) (capabilities.CapabilityConfiguration, error) + configForCapability func(ctx context.Context, capabilityID string, donID uint32) (registrysyncer.CapabilityConfiguration, error) } func (t testConfigProvider) LocalNode(ctx context.Context) (capabilities.Node, error) { @@ -118,12 +121,12 @@ func (t testConfigProvider) LocalNode(ctx context.Context) (capabilities.Node, e }, nil } -func (t testConfigProvider) ConfigForCapability(ctx context.Context, capabilityID string, donID uint32) (capabilities.CapabilityConfiguration, error) { +func (t testConfigProvider) ConfigForCapability(ctx context.Context, capabilityID string, donID uint32) (registrysyncer.CapabilityConfiguration, error) { if t.configForCapability != nil { return t.configForCapability(ctx, capabilityID, donID) } - return capabilities.CapabilityConfiguration{}, nil + return registrysyncer.CapabilityConfiguration{}, nil } // newTestEngine creates a new engine with some test defaults. @@ -1028,11 +1031,9 @@ func TestEngine_MergesWorkflowConfigAndCRConfig(t *testing.T) { simpleWorkflow, ) reg.SetLocalRegistry(testConfigProvider{ - configForCapability: func(ctx context.Context, capabilityID string, donID uint32) (capabilities.CapabilityConfiguration, error) { + configForCapability: func(ctx context.Context, capabilityID string, donID uint32) (registrysyncer.CapabilityConfiguration, error) { if capabilityID != writeID { - return capabilities.CapabilityConfiguration{ - DefaultConfig: values.EmptyMap(), - }, nil + return registrysyncer.CapabilityConfiguration{}, nil } cm, err := values.WrapMap(map[string]any{ @@ -1040,12 +1041,15 @@ func TestEngine_MergesWorkflowConfigAndCRConfig(t *testing.T) { "schedule": "allAtOnce", }) if err != nil { - return capabilities.CapabilityConfiguration{}, err + return registrysyncer.CapabilityConfiguration{}, err } - return capabilities.CapabilityConfiguration{ - DefaultConfig: cm, - }, nil + cb, err := proto.Marshal(&capabilitiespb.CapabilityConfig{ + DefaultConfig: values.ProtoMap(cm), + }) + return registrysyncer.CapabilityConfiguration{ + Config: cb, + }, err }, }) diff --git a/core/web/presenters/job.go b/core/web/presenters/job.go index ad6bf617a82..bb518650516 100644 --- a/core/web/presenters/job.go +++ b/core/web/presenters/job.go @@ -468,6 +468,26 @@ func NewStandardCapabilitiesSpec(spec *job.StandardCapabilitiesSpec) *StandardCa } } +type CCIPSpec struct { + CreatedAt time.Time `json:"createdAt"` + UpdatedAt time.Time `json:"updatedAt"` + CapabilityVersion string `json:"capabilityVersion"` + CapabilityLabelledName string `json:"capabilityLabelledName"` + OCRKeyBundleIDs map[string]interface{} `json:"ocrKeyBundleIDs"` + P2PKeyID string `json:"p2pKeyID"` +} + +func NewCCIPSpec(spec *job.CCIPSpec) *CCIPSpec { + return &CCIPSpec{ + CreatedAt: spec.CreatedAt, + UpdatedAt: spec.UpdatedAt, + CapabilityVersion: spec.CapabilityVersion, + CapabilityLabelledName: spec.CapabilityLabelledName, + OCRKeyBundleIDs: spec.OCRKeyBundleIDs, + P2PKeyID: spec.P2PKeyID, + } +} + // JobError represents errors on the job type JobError struct { ID int64 `json:"id"` @@ -512,6 +532,7 @@ type JobResource struct { GatewaySpec *GatewaySpec `json:"gatewaySpec"` WorkflowSpec *WorkflowSpec `json:"workflowSpec"` StandardCapabilitiesSpec *StandardCapabilitiesSpec `json:"standardCapabilitiesSpec"` + CCIPSpec *CCIPSpec `json:"ccipSpec"` PipelineSpec PipelineSpec `json:"pipelineSpec"` Errors []JobError `json:"errors"` } @@ -562,6 +583,8 @@ func NewJobResource(j job.Job) *JobResource { resource.WorkflowSpec = NewWorkflowSpec(j.WorkflowSpec) case job.StandardCapabilities: resource.StandardCapabilitiesSpec = NewStandardCapabilitiesSpec(j.StandardCapabilitiesSpec) + case job.CCIP: + resource.CCIPSpec = NewCCIPSpec(j.CCIPSpec) case job.LegacyGasStationServer, job.LegacyGasStationSidecar: // unsupported } diff --git a/core/web/presenters/job_test.go b/core/web/presenters/job_test.go index 5de71f918e3..75697c6e068 100644 --- a/core/web/presenters/job_test.go +++ b/core/web/presenters/job_test.go @@ -130,6 +130,7 @@ func TestJob(t *testing.T) { "bootstrapSpec": null, "gatewaySpec": null, "standardCapabilitiesSpec": null, + "ccipSpec": null, "errors": [] } } @@ -208,6 +209,7 @@ func TestJob(t *testing.T) { "bootstrapSpec": null, "gatewaySpec": null, "standardCapabilitiesSpec": null, + "ccipSpec": null, "errors": [] } } @@ -296,6 +298,7 @@ func TestJob(t *testing.T) { "bootstrapSpec": null, "gatewaySpec": null, "standardCapabilitiesSpec": null, + "ccipSpec": null, "errors": [] } } @@ -361,6 +364,7 @@ func TestJob(t *testing.T) { "bootstrapSpec": null, "gatewaySpec": null, "standardCapabilitiesSpec": null, + "ccipSpec": null, "errors": [] } } @@ -423,6 +427,7 @@ func TestJob(t *testing.T) { "bootstrapSpec": null, "gatewaySpec": null, "standardCapabilitiesSpec": null, + "ccipSpec": null, "errors": [] } } @@ -481,6 +486,7 @@ func TestJob(t *testing.T) { "bootstrapSpec": null, "gatewaySpec": null, "standardCapabilitiesSpec": null, + "ccipSpec": null, "errors": [] } } @@ -566,7 +572,9 @@ func TestJob(t *testing.T) { "dotDagSource": "" }, "gatewaySpec": null, - "standardCapabilitiesSpec": null, + "standardCapabilitiesSpec": null, + "standardCapabilitiesSpec": null, + "ccipSpec": null, "errors": [] } } @@ -649,6 +657,7 @@ func TestJob(t *testing.T) { }, "gatewaySpec": null, "standardCapabilitiesSpec": null, + "ccipSpec": null, "errors": [] } } @@ -731,6 +740,7 @@ func TestJob(t *testing.T) { }, "gatewaySpec": null, "standardCapabilitiesSpec": null, + "ccipSpec": null, "errors": [] } } @@ -780,14 +790,14 @@ func TestJob(t *testing.T) { "blockhashStoreSpec": null, "blockHeaderFeederSpec": null, "bootstrapSpec": { - "blockchainTimeout":"0s", - "contractConfigConfirmations":0, - "contractConfigTrackerPollInterval":"0s", - "contractConfigTrackerSubscribeInterval":"0s", - "contractID":"0x16988483b46e695f6c8D58e6e1461DC703e008e1", - "createdAt":"0001-01-01T00:00:00Z", - "relay":"evm", - "relayConfig":{"chainID":1337}, + "blockchainTimeout":"0s", + "contractConfigConfirmations":0, + "contractConfigTrackerPollInterval":"0s", + "contractConfigTrackerSubscribeInterval":"0s", + "contractID":"0x16988483b46e695f6c8D58e6e1461DC703e008e1", + "createdAt":"0001-01-01T00:00:00Z", + "relay":"evm", + "relayConfig":{"chainID":1337}, "updatedAt":"0001-01-01T00:00:00Z" }, "pipelineSpec": { @@ -797,6 +807,7 @@ func TestJob(t *testing.T) { }, "gatewaySpec": null, "standardCapabilitiesSpec": null, + "ccipSpec": null, "errors": [] } } @@ -855,6 +866,7 @@ func TestJob(t *testing.T) { "updatedAt":"0001-01-01T00:00:00Z" }, "standardCapabilitiesSpec": null, + "ccipSpec": null, "pipelineSpec": { "id": 1, "jobID": 0, @@ -919,6 +931,7 @@ func TestJob(t *testing.T) { "bootstrapSpec": null, "gatewaySpec": null, "standardCapabilitiesSpec": null, + "ccipSpec": null, "pipelineSpec": { "id": 1, "jobID": 0, @@ -979,6 +992,72 @@ func TestJob(t *testing.T) { "createdAt":"0001-01-01T00:00:00Z", "updatedAt":"0001-01-01T00:00:00Z" }, + "ccipSpec": null, + "pipelineSpec": { + "id": 1, + "jobID": 0, + "dotDagSource": "" + }, + "errors": [] + } + } + }`, + }, + { + name: "ccip spec", + job: job.Job{ + ID: 1, + CCIPSpec: &job.CCIPSpec{ + ID: 3, + CreatedAt: timestamp, + UpdatedAt: timestamp, + CapabilityVersion: "4.5.9", + CapabilityLabelledName: "ccip", + }, + PipelineSpec: &pipeline.Spec{ + ID: 1, + DotDagSource: "", + }, + ExternalJobID: uuid.MustParse("0eec7e1d-d0d2-476c-a1a8-72dfb6633f46"), + Type: job.CCIP, + SchemaVersion: 1, + Name: null.StringFrom("ccip test"), + }, + want: ` + { + "data": { + "type": "jobs", + "id": "1", + "attributes": { + "name": "ccip test", + "type": "ccip", + "schemaVersion": 1, + "maxTaskDuration": "0s", + "externalJobID": "0eec7e1d-d0d2-476c-a1a8-72dfb6633f46", + "directRequestSpec": null, + "fluxMonitorSpec": null, + "gasLimit": null, + "forwardingAllowed": false, + "cronSpec": null, + "offChainReportingOracleSpec": null, + "offChainReporting2OracleSpec": null, + "keeperSpec": null, + "vrfSpec": null, + "webhookSpec": null, + "workflowSpec": null, + "blockhashStoreSpec": null, + "blockHeaderFeederSpec": null, + "bootstrapSpec": null, + "gatewaySpec": null, + "standardCapabilitiesSpec": null, + "ccipSpec": { + "capabilityVersion":"4.5.9", + "capabilityLabelledName":"ccip", + "ocrKeyBundleIDs": null, + "p2pKeyID": "", + "createdAt":"2000-01-01T00:00:00Z", + "updatedAt":"2000-01-01T00:00:00Z" + }, "pipelineSpec": { "id": 1, "jobID": 0, @@ -1058,6 +1137,7 @@ func TestJob(t *testing.T) { "bootstrapSpec": null, "gatewaySpec": null, "standardCapabilitiesSpec": null, + "ccipSpec": null, "errors": [{ "id": 200, "description": "some error", diff --git a/go.mod b/go.mod index c9bb357215d..85da46028f5 100644 --- a/go.mod +++ b/go.mod @@ -74,7 +74,7 @@ require ( github.com/shopspring/decimal v1.4.0 github.com/smartcontractkit/chain-selectors v1.0.10 github.com/smartcontractkit/chainlink-automation v1.0.4 - github.com/smartcontractkit/chainlink-ccip v0.0.0-20240805140125-f23843ca95b3 + github.com/smartcontractkit/chainlink-ccip v0.0.0-20240806144315-04ac101e9c95 github.com/smartcontractkit/chainlink-common v0.2.2-0.20240805160614-501c4f40b98c github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240710121324-3ed288aa9b45 github.com/smartcontractkit/chainlink-data-streams v0.0.0-20240801131703-fd75761c982f @@ -103,7 +103,7 @@ require ( go.uber.org/multierr v1.11.0 go.uber.org/zap v1.27.0 golang.org/x/crypto v0.25.0 - golang.org/x/exp v0.0.0-20240716175740-e3f259677ff7 + golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 golang.org/x/mod v0.19.0 golang.org/x/net v0.27.0 golang.org/x/sync v0.7.0 diff --git a/go.sum b/go.sum index 5e4833d5117..68bff30133f 100644 --- a/go.sum +++ b/go.sum @@ -1139,8 +1139,8 @@ github.com/smartcontractkit/chain-selectors v1.0.10 h1:t9kJeE6B6G+hKD0GYR4kGJSCq github.com/smartcontractkit/chain-selectors v1.0.10/go.mod h1:d4Hi+E1zqjy9HqMkjBE5q1vcG9VGgxf5VxiRHfzi2kE= github.com/smartcontractkit/chainlink-automation v1.0.4 h1:iyW181JjKHLNMnDleI8umfIfVVlwC7+n5izbLSFgjw8= github.com/smartcontractkit/chainlink-automation v1.0.4/go.mod h1:u4NbPZKJ5XiayfKHD/v3z3iflQWqvtdhj13jVZXj/cM= -github.com/smartcontractkit/chainlink-ccip v0.0.0-20240805140125-f23843ca95b3 h1:GQhGwuXw9UqRctfxTkk7ZWbond28kNsyjc+2W4KDXtc= -github.com/smartcontractkit/chainlink-ccip v0.0.0-20240805140125-f23843ca95b3/go.mod h1:K67FldZZmg+//7yyI0yBMXEw6uvYevTj/ErBEvXaBXM= +github.com/smartcontractkit/chainlink-ccip v0.0.0-20240806144315-04ac101e9c95 h1:LAgJTg9Yr/uCo2g7Krp88Dco2U45Y6sbJVl8uKoLkys= +github.com/smartcontractkit/chainlink-ccip v0.0.0-20240806144315-04ac101e9c95/go.mod h1:/ZWraCBaDDgaIN1prixYcbVvIk/6HeED9+8zbWQ+TMo= github.com/smartcontractkit/chainlink-common v0.2.2-0.20240805160614-501c4f40b98c h1:3apUsez/6Pkp1ckXzSwIhzPRuWjDGjzMjKapEKi0Fcw= github.com/smartcontractkit/chainlink-common v0.2.2-0.20240805160614-501c4f40b98c/go.mod h1:Jg1sCTsbxg76YByI8ifpFby3FvVqISStHT8ypy9ocmY= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240710121324-3ed288aa9b45 h1:NBQLtqk8zsyY4qTJs+NElI3aDFTcAo83JHvqD04EvB0= @@ -1438,8 +1438,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= -golang.org/x/exp v0.0.0-20240716175740-e3f259677ff7 h1:wDLEX9a7YQoKdKNQt88rtydkqDxeGaBUTnIYc3iG/mA= -golang.org/x/exp v0.0.0-20240716175740-e3f259677ff7/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY= +golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8= +golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= diff --git a/integration-tests/go.mod b/integration-tests/go.mod index 09f92be3299..7fe64f118f9 100644 --- a/integration-tests/go.mod +++ b/integration-tests/go.mod @@ -376,6 +376,7 @@ require ( github.com/shoenig/go-m1cpu v0.1.6 // indirect github.com/sirupsen/logrus v1.9.3 // indirect github.com/smartcontractkit/chain-selectors v1.0.10 // indirect + github.com/smartcontractkit/chainlink-ccip v0.0.0-20240806144315-04ac101e9c95 // indirect github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240710121324-3ed288aa9b45 // indirect github.com/smartcontractkit/chainlink-data-streams v0.0.0-20240801131703-fd75761c982f // indirect github.com/smartcontractkit/chainlink-feeds v0.0.0-20240710170203-5b41615da827 // indirect @@ -447,7 +448,7 @@ require ( go4.org/netipx v0.0.0-20230125063823-8449b0a6169f // indirect golang.org/x/arch v0.8.0 // indirect golang.org/x/crypto v0.25.0 // indirect - golang.org/x/exp v0.0.0-20240716175740-e3f259677ff7 // indirect + golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect golang.org/x/mod v0.19.0 // indirect golang.org/x/net v0.27.0 // indirect golang.org/x/oauth2 v0.21.0 // indirect diff --git a/integration-tests/go.sum b/integration-tests/go.sum index 159886ffbee..09a67871f55 100644 --- a/integration-tests/go.sum +++ b/integration-tests/go.sum @@ -1486,6 +1486,8 @@ github.com/smartcontractkit/chain-selectors v1.0.10 h1:t9kJeE6B6G+hKD0GYR4kGJSCq github.com/smartcontractkit/chain-selectors v1.0.10/go.mod h1:d4Hi+E1zqjy9HqMkjBE5q1vcG9VGgxf5VxiRHfzi2kE= github.com/smartcontractkit/chainlink-automation v1.0.4 h1:iyW181JjKHLNMnDleI8umfIfVVlwC7+n5izbLSFgjw8= github.com/smartcontractkit/chainlink-automation v1.0.4/go.mod h1:u4NbPZKJ5XiayfKHD/v3z3iflQWqvtdhj13jVZXj/cM= +github.com/smartcontractkit/chainlink-ccip v0.0.0-20240806144315-04ac101e9c95 h1:LAgJTg9Yr/uCo2g7Krp88Dco2U45Y6sbJVl8uKoLkys= +github.com/smartcontractkit/chainlink-ccip v0.0.0-20240806144315-04ac101e9c95/go.mod h1:/ZWraCBaDDgaIN1prixYcbVvIk/6HeED9+8zbWQ+TMo= github.com/smartcontractkit/chainlink-common v0.2.2-0.20240805160614-501c4f40b98c h1:3apUsez/6Pkp1ckXzSwIhzPRuWjDGjzMjKapEKi0Fcw= github.com/smartcontractkit/chainlink-common v0.2.2-0.20240805160614-501c4f40b98c/go.mod h1:Jg1sCTsbxg76YByI8ifpFby3FvVqISStHT8ypy9ocmY= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240710121324-3ed288aa9b45 h1:NBQLtqk8zsyY4qTJs+NElI3aDFTcAo83JHvqD04EvB0= @@ -1834,8 +1836,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= -golang.org/x/exp v0.0.0-20240716175740-e3f259677ff7 h1:wDLEX9a7YQoKdKNQt88rtydkqDxeGaBUTnIYc3iG/mA= -golang.org/x/exp v0.0.0-20240716175740-e3f259677ff7/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY= +golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8= +golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= diff --git a/integration-tests/load/go.mod b/integration-tests/load/go.mod index 03c2c50411c..4223ffe601c 100644 --- a/integration-tests/load/go.mod +++ b/integration-tests/load/go.mod @@ -38,6 +38,7 @@ require ( github.com/google/gnostic-models v0.6.9-0.20230804172637-c7be7c783f49 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect + github.com/smartcontractkit/chainlink-ccip v0.0.0-20240806144315-04ac101e9c95 // indirect github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240710121324-3ed288aa9b45 // indirect k8s.io/apimachinery v0.30.2 // indirect ) @@ -444,7 +445,7 @@ require ( go4.org/netipx v0.0.0-20230125063823-8449b0a6169f // indirect golang.org/x/arch v0.8.0 // indirect golang.org/x/crypto v0.25.0 // indirect - golang.org/x/exp v0.0.0-20240716175740-e3f259677ff7 // indirect + golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect golang.org/x/mod v0.19.0 // indirect golang.org/x/net v0.27.0 // indirect golang.org/x/oauth2 v0.21.0 // indirect diff --git a/integration-tests/load/go.sum b/integration-tests/load/go.sum index 2c3f5e0d83a..414ad998edb 100644 --- a/integration-tests/load/go.sum +++ b/integration-tests/load/go.sum @@ -1468,6 +1468,8 @@ github.com/smartcontractkit/chain-selectors v1.0.10 h1:t9kJeE6B6G+hKD0GYR4kGJSCq github.com/smartcontractkit/chain-selectors v1.0.10/go.mod h1:d4Hi+E1zqjy9HqMkjBE5q1vcG9VGgxf5VxiRHfzi2kE= github.com/smartcontractkit/chainlink-automation v1.0.4 h1:iyW181JjKHLNMnDleI8umfIfVVlwC7+n5izbLSFgjw8= github.com/smartcontractkit/chainlink-automation v1.0.4/go.mod h1:u4NbPZKJ5XiayfKHD/v3z3iflQWqvtdhj13jVZXj/cM= +github.com/smartcontractkit/chainlink-ccip v0.0.0-20240806144315-04ac101e9c95 h1:LAgJTg9Yr/uCo2g7Krp88Dco2U45Y6sbJVl8uKoLkys= +github.com/smartcontractkit/chainlink-ccip v0.0.0-20240806144315-04ac101e9c95/go.mod h1:/ZWraCBaDDgaIN1prixYcbVvIk/6HeED9+8zbWQ+TMo= github.com/smartcontractkit/chainlink-common v0.2.2-0.20240805160614-501c4f40b98c h1:3apUsez/6Pkp1ckXzSwIhzPRuWjDGjzMjKapEKi0Fcw= github.com/smartcontractkit/chainlink-common v0.2.2-0.20240805160614-501c4f40b98c/go.mod h1:Jg1sCTsbxg76YByI8ifpFby3FvVqISStHT8ypy9ocmY= github.com/smartcontractkit/chainlink-cosmos v0.4.1-0.20240710121324-3ed288aa9b45 h1:NBQLtqk8zsyY4qTJs+NElI3aDFTcAo83JHvqD04EvB0= @@ -1816,8 +1818,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0 golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM= golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= -golang.org/x/exp v0.0.0-20240716175740-e3f259677ff7 h1:wDLEX9a7YQoKdKNQt88rtydkqDxeGaBUTnIYc3iG/mA= -golang.org/x/exp v0.0.0-20240716175740-e3f259677ff7/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY= +golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8= +golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=