From b375b3ca23dd4ff5c4c4524e9773e72ea397b58b Mon Sep 17 00:00:00 2001 From: connorwstein Date: Wed, 20 Nov 2024 10:43:57 -0500 Subject: [PATCH] Move a bunch of home chain stuff to internal --- deployment/ccip/changeset/active_candidate.go | 3 +- .../changeset/active_candidate_helpers.go | 13 +- .../ccip/changeset/active_candidate_test.go | 5 +- deployment/ccip/changeset/add_chain.go | 5 +- deployment/ccip/changeset/add_chain_test.go | 5 +- deployment/ccip/changeset/deploy.go | 9 +- .../ccip/changeset/deploy_home_chain.go | 545 +----------------- .../changeset/internal/deploy_home_chain.go | 535 +++++++++++++++++ deployment/ccip/changeset/jobs.go | 9 +- 9 files changed, 576 insertions(+), 553 deletions(-) diff --git a/deployment/ccip/changeset/active_candidate.go b/deployment/ccip/changeset/active_candidate.go index f75d0e5e942..a336cf69536 100644 --- a/deployment/ccip/changeset/active_candidate.go +++ b/deployment/ccip/changeset/active_candidate.go @@ -7,6 +7,7 @@ import ( "github.com/smartcontractkit/ccip-owner-contracts/pkg/proposal/timelock" "github.com/smartcontractkit/chainlink/deployment" + "github.com/smartcontractkit/chainlink/deployment/ccip/changeset/internal" cctypes "github.com/smartcontractkit/chainlink/v2/core/capabilities/ccip/types" ) @@ -51,7 +52,7 @@ func SetCandidatePluginChangeset( tokenConfig TokenConfig, pluginType cctypes.PluginType, ) (deployment.ChangesetOutput, error) { - newDONArgs, err := BuildOCR3ConfigForCCIPHome( + newDONArgs, err := internal.BuildOCR3ConfigForCCIPHome( ocrSecrets, state.Chains[newChainSel].OffRamp, e.Chains[newChainSel], diff --git a/deployment/ccip/changeset/active_candidate_helpers.go b/deployment/ccip/changeset/active_candidate_helpers.go index 914f8fc0c17..aea488c36b2 100644 --- a/deployment/ccip/changeset/active_candidate_helpers.go +++ b/deployment/ccip/changeset/active_candidate_helpers.go @@ -7,6 +7,7 @@ import ( "github.com/smartcontractkit/ccip-owner-contracts/pkg/proposal/mcms" "github.com/smartcontractkit/chainlink/deployment" + "github.com/smartcontractkit/chainlink/deployment/ccip/changeset/internal" cctypes "github.com/smartcontractkit/chainlink/v2/core/capabilities/ccip/types" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/ccip_home" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/keystone/generated/capabilities_registry" @@ -22,12 +23,12 @@ func SetCandidateOnExistingDon( nodes deployment.Nodes, ) ([]mcms.Operation, error) { // fetch DON ID for the chain - donID, err := DonIDForChain(capReg, ccipHome, chainSelector) + donID, err := internal.DonIDForChain(capReg, ccipHome, chainSelector) if err != nil { return nil, fmt.Errorf("fetch don id for chain: %w", err) } fmt.Printf("donID: %d", donID) - encodedSetCandidateCall, err := CCIPHomeABI.Pack( + encodedSetCandidateCall, err := internal.CCIPHomeABI.Pack( "setCandidate", donID, pluginConfig.PluginType, @@ -45,7 +46,7 @@ func SetCandidateOnExistingDon( nodes.PeerIDs(), []capabilities_registry.CapabilitiesRegistryCapabilityConfiguration{ { - CapabilityId: CCIPCapabilityID, + CapabilityId: internal.CCIPCapabilityID, Config: encodedSetCandidateCall, }, }, @@ -77,7 +78,7 @@ func PromoteCandidateOp(donID uint32, pluginType uint8, capReg *capabilities_reg } fmt.Printf("commit candidate digest after setCandidate: %x\n", allConfigs.CandidateConfig.ConfigDigest) - encodedPromotionCall, err := CCIPHomeABI.Pack( + encodedPromotionCall, err := internal.CCIPHomeABI.Pack( "promoteCandidateAndRevokeActive", donID, pluginType, @@ -94,7 +95,7 @@ func PromoteCandidateOp(donID uint32, pluginType uint8, capReg *capabilities_reg nodes.PeerIDs(), []capabilities_registry.CapabilitiesRegistryCapabilityConfiguration{ { - CapabilityId: CCIPCapabilityID, + CapabilityId: internal.CCIPCapabilityID, Config: encodedPromotionCall, }, }, @@ -119,7 +120,7 @@ func PromoteAllCandidatesForChainOps( nodes deployment.Nodes, ) ([]mcms.Operation, error) { // fetch DON ID for the chain - donID, err := DonIDForChain(capReg, ccipHome, chainSelector) + donID, err := internal.DonIDForChain(capReg, ccipHome, chainSelector) if err != nil { return nil, fmt.Errorf("fetch don id for chain: %w", err) } diff --git a/deployment/ccip/changeset/active_candidate_test.go b/deployment/ccip/changeset/active_candidate_test.go index 0a85b7ef51d..e917c7a7e31 100644 --- a/deployment/ccip/changeset/active_candidate_test.go +++ b/deployment/ccip/changeset/active_candidate_test.go @@ -8,6 +8,7 @@ import ( "github.com/smartcontractkit/ccip-owner-contracts/pkg/proposal/timelock" "github.com/smartcontractkit/chainlink-testing-framework/lib/utils/testcontext" + "github.com/smartcontractkit/chainlink/deployment/ccip/changeset/internal" cctypes "github.com/smartcontractkit/chainlink/v2/core/capabilities/ccip/types" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/router" @@ -85,7 +86,7 @@ func TestActiveCandidate(t *testing.T) { // [ACTIVE, CANDIDATE] setup by setting candidate through cap reg capReg, ccipHome := state.Chains[tenv.HomeChainSel].CapabilityRegistry, state.Chains[tenv.HomeChainSel].CCIPHome - donID, err := DonIDForChain(capReg, ccipHome, tenv.FeedChainSel) + donID, err := internal.DonIDForChain(capReg, ccipHome, tenv.FeedChainSel) require.NoError(t, err) donInfo, err := state.Chains[tenv.HomeChainSel].CapabilityRegistry.GetDON(nil, donID) require.NoError(t, err) @@ -113,7 +114,7 @@ func TestActiveCandidate(t *testing.T) { // commit and exec plugin we will be using rmnHomeAddress := state.Chains[tenv.HomeChainSel].RMNHome.Address() tokenConfig := NewTestTokenConfig(state.Chains[tenv.FeedChainSel].USDFeeds) - ocr3ConfigMap, err := BuildOCR3ConfigForCCIPHome( + ocr3ConfigMap, err := internal.BuildOCR3ConfigForCCIPHome( deployment.XXXGenerateTestOCRSecrets(), state.Chains[tenv.FeedChainSel].OffRamp, e.Chains[tenv.FeedChainSel], diff --git a/deployment/ccip/changeset/add_chain.go b/deployment/ccip/changeset/add_chain.go index f58da7b4e5d..cb7d0701973 100644 --- a/deployment/ccip/changeset/add_chain.go +++ b/deployment/ccip/changeset/add_chain.go @@ -4,6 +4,7 @@ import ( "fmt" "math/big" + "github.com/smartcontractkit/chainlink/deployment/ccip/changeset/internal" "github.com/smartcontractkit/chainlink/v2/core/capabilities/ccip/types" "github.com/smartcontractkit/ccip-owner-contracts/pkg/proposal/mcms" @@ -97,7 +98,7 @@ func AddDonAndSetCandidateChangeset( tokenConfig TokenConfig, pluginType types.PluginType, ) (deployment.ChangesetOutput, error) { - newDONArgs, err := BuildOCR3ConfigForCCIPHome( + newDONArgs, err := internal.BuildOCR3ConfigForCCIPHome( ocrSecrets, state.Chains[newChainSel].OffRamp, e.Chains[newChainSel], @@ -110,7 +111,7 @@ func AddDonAndSetCandidateChangeset( if err != nil { return deployment.ChangesetOutput{}, err } - latestDon, err := LatestCCIPDON(state.Chains[homeChainSel].CapabilityRegistry) + latestDon, err := internal.LatestCCIPDON(state.Chains[homeChainSel].CapabilityRegistry) if err != nil { return deployment.ChangesetOutput{}, err } diff --git a/deployment/ccip/changeset/add_chain_test.go b/deployment/ccip/changeset/add_chain_test.go index 3dc18f5161c..aa702a002cd 100644 --- a/deployment/ccip/changeset/add_chain_test.go +++ b/deployment/ccip/changeset/add_chain_test.go @@ -5,6 +5,7 @@ import ( "testing" "time" + "github.com/smartcontractkit/chainlink/deployment/ccip/changeset/internal" commonchangeset "github.com/smartcontractkit/chainlink/deployment/common/changeset" commontypes "github.com/smartcontractkit/chainlink/deployment/common/types" "github.com/smartcontractkit/chainlink/v2/core/capabilities/ccip/types" @@ -204,9 +205,9 @@ func TestAddChainInbound(t *testing.T) { _, err = deployment.ConfirmIfNoError(e.Env.Chains[newChain], tx, err) require.NoError(t, err) // Set the OCR3 config on new 4th chain to enable the plugin. - latestDON, err := LatestCCIPDON(state.Chains[e.HomeChainSel].CapabilityRegistry) + latestDON, err := internal.LatestCCIPDON(state.Chains[e.HomeChainSel].CapabilityRegistry) require.NoError(t, err) - ocrConfigs, err := BuildSetOCR3ConfigArgs(latestDON.Id, state.Chains[e.HomeChainSel].CCIPHome, newChain) + ocrConfigs, err := internal.BuildSetOCR3ConfigArgs(latestDON.Id, state.Chains[e.HomeChainSel].CCIPHome, newChain) require.NoError(t, err) tx, err = state.Chains[newChain].OffRamp.SetOCR3Configs(e.Env.Chains[newChain].DeployerKey, ocrConfigs) require.NoError(t, err) diff --git a/deployment/ccip/changeset/deploy.go b/deployment/ccip/changeset/deploy.go index 264127c9030..33459c17678 100644 --- a/deployment/ccip/changeset/deploy.go +++ b/deployment/ccip/changeset/deploy.go @@ -12,6 +12,7 @@ import ( cciptypes "github.com/smartcontractkit/chainlink-ccip/pkg/types/ccipocr3" "github.com/smartcontractkit/chainlink-ccip/pluginconfig" commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" + "github.com/smartcontractkit/chainlink/deployment/ccip/changeset/internal" "github.com/smartcontractkit/chainlink/deployment" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/ccip_home" @@ -438,15 +439,15 @@ func DeployChainContractsForChains( return fmt.Errorf("capability registry not found") } cr, err := capReg.GetHashedCapabilityId( - &bind.CallOpts{}, CapabilityLabelledName, CapabilityVersion) + &bind.CallOpts{}, internal.CapabilityLabelledName, internal.CapabilityVersion) if err != nil { e.Logger.Errorw("Failed to get hashed capability id", "err", err) return err } - if cr != CCIPCapabilityID { - return fmt.Errorf("capability registry does not support CCIP %s %s", hexutil.Encode(cr[:]), hexutil.Encode(CCIPCapabilityID[:])) + if cr != internal.CCIPCapabilityID { + return fmt.Errorf("capability registry does not support CCIP %s %s", hexutil.Encode(cr[:]), hexutil.Encode(internal.CCIPCapabilityID[:])) } - capability, err := capReg.GetCapability(nil, CCIPCapabilityID) + capability, err := capReg.GetCapability(nil, internal.CCIPCapabilityID) if err != nil { e.Logger.Errorw("Failed to get capability", "err", err) return err diff --git a/deployment/ccip/changeset/deploy_home_chain.go b/deployment/ccip/changeset/deploy_home_chain.go index 47dd5f590e6..446328c0530 100644 --- a/deployment/ccip/changeset/deploy_home_chain.go +++ b/deployment/ccip/changeset/deploy_home_chain.go @@ -7,10 +7,7 @@ import ( "encoding/json" "fmt" "math/big" - "os" - "time" - "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/pkg/errors" @@ -20,16 +17,11 @@ import ( "github.com/smartcontractkit/chainlink-ccip/chainconfig" "github.com/smartcontractkit/chainlink-ccip/pkg/types/ccipocr3" "github.com/smartcontractkit/chainlink-ccip/pluginconfig" - commonconfig "github.com/smartcontractkit/chainlink-common/pkg/config" "github.com/smartcontractkit/chainlink-common/pkg/logger" - "github.com/smartcontractkit/chainlink-common/pkg/merklemulti" - - confighelper2 "github.com/smartcontractkit/libocr/offchainreporting2plus/confighelper" - "github.com/smartcontractkit/libocr/offchainreporting2plus/ocr3confighelper" + "github.com/smartcontractkit/chainlink/deployment/ccip/changeset/internal" "github.com/smartcontractkit/chainlink/deployment" cctypes "github.com/smartcontractkit/chainlink/v2/core/capabilities/ccip/types" - "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/ccip_home" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/offramp" "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/rmn_home" @@ -37,54 +29,6 @@ import ( p2ptypes "github.com/smartcontractkit/chainlink/v2/core/services/p2p/types" ) -const ( - NodeOperatorID = 1 - CapabilityLabelledName = "ccip" - CapabilityVersion = "v1.0.0" - - FirstBlockAge = 8 * time.Hour - RemoteGasPriceBatchWriteFrequency = 30 * time.Minute - TokenPriceBatchWriteFrequency = 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 = 500 * time.Millisecond - MaxDurationObservation = 5 * time.Second - MaxDurationShouldAcceptAttestedReport = 10 * time.Second - MaxDurationShouldTransmitAcceptedReport = 10 * time.Second -) - -var ( - CCIPCapabilityID = utils.Keccak256Fixed(MustABIEncode(`[{"type": "string"}, {"type": "string"}]`, CapabilityLabelledName, CapabilityVersion)) - CCIPHomeABI *abi.ABI -) - -func init() { - var err error - CCIPHomeABI, err = ccip_home.CCIPHomeMetaData.GetAbi() - if err != nil { - panic(err) - } -} - -func MustABIEncode(abiString string, args ...interface{}) []byte { - encoded, err := utils.ABIEncode(abiString, args...) - if err != nil { - panic(err) - } - return encoded -} - // DeployCapReg deploys the CapabilitiesRegistry contract if it is not already deployed // and returns a deployment.ContractDeploy struct with the address and contract instance. func DeployCapReg( @@ -212,8 +156,8 @@ func deployHomeChain( tx, err = capReg.Contract.AddCapabilities(chain.DeployerKey, []capabilities_registry.CapabilitiesRegistryCapability{ { - LabelledName: CapabilityLabelledName, - Version: CapabilityVersion, + LabelledName: internal.CapabilityLabelledName, + Version: internal.CapabilityVersion, CapabilityType: 2, // consensus. not used (?) ResponseType: 0, // report. not used (?) ConfigurationContract: ccipHome.Address, @@ -259,27 +203,6 @@ func deployHomeChain( return capReg, nil } -// getNodeOperatorIDMap returns a map of node operator names to their IDs -// If maxNops is greater than the number of node operators, it will return all node operators -func getNodeOperatorIDMap(capReg *capabilities_registry.CapabilitiesRegistry, maxNops uint32) (map[string]uint32, error) { - nopIdByName := make(map[string]uint32) - operators, err := capReg.GetNodeOperators(nil) - if err != nil { - return nil, err - } - if len(operators) < int(maxNops) { - maxNops = uint32(len(operators)) - } - for i := uint32(1); i <= maxNops; i++ { - operator, err := capReg.GetNodeOperator(nil, i) - if err != nil { - return nil, err - } - nopIdByName[operator.Name] = i - } - return nopIdByName, nil -} - func isEqualCapabilitiesRegistryNodeParams(a, b capabilities_registry.CapabilitiesRegistryNodeParams) (bool, error) { aBytes, err := json.Marshal(a) if err != nil { @@ -323,7 +246,7 @@ func AddNodes( Signer: p2pID, // Not used in tests P2pId: p2pID, EncryptionPublicKey: p2pID, // Not used in tests - HashedCapabilityIds: [][32]byte{CCIPCapabilityID}, + HashedCapabilityIds: [][32]byte{internal.CCIPCapabilityID}, } if existing, ok := existingNodeParams[p2pID]; ok { if isEqual, err := isEqualCapabilitiesRegistryNodeParams(existing, nodeParam); err != nil && isEqual { @@ -386,214 +309,6 @@ func AddChainConfig( return chainConfig, nil } -func BuildOCR3ConfigForCCIPHome( - ocrSecrets deployment.OCRSecrets, - offRamp *offramp.OffRamp, - dest deployment.Chain, - feedChainSel uint64, - tokenInfo map[ccipocr3.UnknownEncodedAddress]pluginconfig.TokenInfo, - nodes deployment.Nodes, - rmnHomeAddress common.Address, - configs []pluginconfig.TokenDataObserverConfig, -) (map[cctypes.PluginType]ccip_home.CCIPHomeOCR3Config, error) { - p2pIDs := nodes.PeerIDs() - // Get OCR3 Config from helper - var schedule []int - var oracles []confighelper2.OracleIdentityExtra - for _, node := range nodes { - schedule = append(schedule, 1) - cfg := node.SelToOCRConfig[dest.Selector] - oracles = append(oracles, confighelper2.OracleIdentityExtra{ - OracleIdentity: confighelper2.OracleIdentity{ - OnchainPublicKey: cfg.OnchainPublicKey, - TransmitAccount: cfg.TransmitAccount, - OffchainPublicKey: cfg.OffchainPublicKey, - PeerID: cfg.PeerID.String()[4:], - }, ConfigEncryptionPublicKey: cfg.ConfigEncryptionPublicKey, - }) - } - - // Add DON on capability registry contract - ocr3Configs := make(map[cctypes.PluginType]ccip_home.CCIPHomeOCR3Config) - 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), - TokenPriceBatchWriteFrequency: *commonconfig.MustNewDuration(TokenPriceBatchWriteFrequency), - PriceFeedChainSelector: ccipocr3.ChainSelector(feedChainSel), - TokenInfo: tokenInfo, - NewMsgScanBatchSize: merklemulti.MaxNumberTreeLeaves, - MaxReportTransmissionCheckAttempts: 5, - MaxMerkleTreeSize: merklemulti.MaxNumberTreeLeaves, - SignObservationPrefix: "chainlink ccip 1.6 rmn observation", - RMNEnabled: os.Getenv("ENABLE_RMN") == "true", // only enabled in manual test - }) - } 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, - TokenDataObservers: configs, - }) - } - if err2 != nil { - return nil, err2 - } - signers, transmitters, configF, _, offchainConfigVersion, offchainConfig, err2 := ocr3confighelper.ContractSetConfigArgsDeterministic( - ocrSecrets.EphemeralSk, - ocrSecrets.SharedSecret, - DeltaProgress, - DeltaResend, - DeltaInitial, - DeltaRound, - DeltaGrace, - DeltaCertifiedCommitRequest, - DeltaStage, - Rmax, - schedule, - oracles, - encodedOffchainConfig, - nil, // maxDurationInitialization - MaxDurationQuery, - MaxDurationObservation, - MaxDurationShouldAcceptAttestedReport, - MaxDurationShouldTransmitAcceptedReport, - int(nodes.DefaultF()), - []byte{}, // empty OnChainConfig - ) - if err2 != nil { - return nil, err2 - } - - signersBytes := make([][]byte, len(signers)) - for i, signer := range signers { - signersBytes[i] = signer - } - - transmittersBytes := make([][]byte, len(transmitters)) - for i, transmitter := range transmitters { - parsed, err2 := common.ParseHexOrString(string(transmitter)) - if err2 != nil { - return nil, err2 - } - transmittersBytes[i] = parsed - } - - var ocrNodes []ccip_home.CCIPHomeOCR3Node - for i := range nodes { - ocrNodes = append(ocrNodes, ccip_home.CCIPHomeOCR3Node{ - P2pId: p2pIDs[i], - SignerKey: signersBytes[i], - TransmitterKey: transmittersBytes[i], - }) - } - - _, ok := ocr3Configs[pluginType] - if ok { - return nil, fmt.Errorf("pluginType %s already exists in ocr3Configs", pluginType.String()) - } - - ocr3Configs[pluginType] = ccip_home.CCIPHomeOCR3Config{ - PluginType: uint8(pluginType), - ChainSelector: dest.Selector, - FRoleDON: configF, - OffchainConfigVersion: offchainConfigVersion, - OfframpAddress: offRamp.Address().Bytes(), - Nodes: ocrNodes, - OffchainConfig: offchainConfig, - RmnHomeAddress: rmnHomeAddress.Bytes(), - } - } - - return ocr3Configs, nil -} - -func LatestCCIPDON(registry *capabilities_registry.CapabilitiesRegistry) (*capabilities_registry.CapabilitiesRegistryDONInfo, error) { - dons, err := registry.GetDONs(nil) - if err != nil { - return nil, err - } - var ccipDON capabilities_registry.CapabilitiesRegistryDONInfo - for _, don := range dons { - if len(don.CapabilityConfigurations) == 1 && - don.CapabilityConfigurations[0].CapabilityId == CCIPCapabilityID && - don.Id > ccipDON.Id { - ccipDON = don - } - } - return &ccipDON, nil -} - -// DonIDForChain returns the DON ID for the chain with the given selector -// It looks up with the CCIPHome contract to find the OCR3 configs for the DONs, and returns the DON ID for the chain matching with the given selector from the OCR3 configs -func DonIDForChain(registry *capabilities_registry.CapabilitiesRegistry, ccipHome *ccip_home.CCIPHome, chainSelector uint64) (uint32, error) { - dons, err := registry.GetDONs(nil) - if err != nil { - return 0, err - } - // TODO: what happens if there are multiple dons for one chain (accidentally?) - for _, don := range dons { - if len(don.CapabilityConfigurations) == 1 && - don.CapabilityConfigurations[0].CapabilityId == CCIPCapabilityID { - configs, err := ccipHome.GetAllConfigs(nil, don.Id, uint8(cctypes.PluginTypeCCIPCommit)) - if err != nil { - return 0, err - } - if configs.ActiveConfig.Config.ChainSelector == chainSelector || configs.CandidateConfig.Config.ChainSelector == chainSelector { - return don.Id, nil - } - } - } - return 0, fmt.Errorf("no DON found for chain %d", chainSelector) -} - -func BuildSetOCR3ConfigArgs( - donID uint32, - ccipHome *ccip_home.CCIPHome, - destSelector uint64, -) ([]offramp.MultiOCR3BaseOCRConfigArgs, error) { - var offrampOCR3Configs []offramp.MultiOCR3BaseOCRConfigArgs - for _, pluginType := range []cctypes.PluginType{cctypes.PluginTypeCCIPCommit, cctypes.PluginTypeCCIPExec} { - ocrConfig, err2 := ccipHome.GetAllConfigs(&bind.CallOpts{ - Context: context.Background(), - }, donID, uint8(pluginType)) - if err2 != nil { - return nil, err2 - } - - fmt.Printf("pluginType: %s, destSelector: %d, donID: %d, activeConfig digest: %x, candidateConfig digest: %x\n", - pluginType.String(), destSelector, donID, ocrConfig.ActiveConfig.ConfigDigest, ocrConfig.CandidateConfig.ConfigDigest) - - // we expect only an active config and no candidate config. - if ocrConfig.ActiveConfig.ConfigDigest == [32]byte{} || ocrConfig.CandidateConfig.ConfigDigest != [32]byte{} { - return nil, fmt.Errorf("invalid OCR3 config state, expected active config and no candidate config, donID: %d", donID) - } - - activeConfig := ocrConfig.ActiveConfig - var signerAddresses []common.Address - var transmitterAddresses []common.Address - for _, node := range activeConfig.Config.Nodes { - signerAddresses = append(signerAddresses, common.BytesToAddress(node.SignerKey)) - transmitterAddresses = append(transmitterAddresses, common.BytesToAddress(node.TransmitterKey)) - } - - offrampOCR3Configs = append(offrampOCR3Configs, offramp.MultiOCR3BaseOCRConfigArgs{ - ConfigDigest: activeConfig.ConfigDigest, - OcrPluginType: uint8(pluginType), - F: activeConfig.Config.FRoleDON, - IsSignatureVerificationEnabled: pluginType == cctypes.PluginTypeCCIPCommit, - Signers: signerAddresses, - Transmitters: transmitterAddresses, - }) - } - return offrampOCR3Configs, nil -} - // CreateDON creates one DON with 2 plugins (commit and exec) // It first set a new candidate for the DON with the first plugin type and AddDON on capReg // Then for subsequent operations it uses UpdateDON to promote the first plugin to the active deployment @@ -617,154 +332,26 @@ func CreateDON( return fmt.Errorf("missing exec plugin in ocr3Configs") } - latestDon, err := LatestCCIPDON(capReg) + latestDon, err := internal.LatestCCIPDON(capReg) if err != nil { return err } donID := latestDon.Id + 1 - err = setupCommitDON(donID, commitConfig, capReg, home, nodes, ccipHome) + err = internal.SetupCommitDON(donID, commitConfig, capReg, home, nodes, ccipHome) if err != nil { return fmt.Errorf("setup commit don: %w", err) } // TODO: bug in contract causing this to not work as expected. - err = setupExecDON(donID, execConfig, capReg, home, nodes, ccipHome) + err = internal.SetupExecDON(donID, execConfig, capReg, home, nodes, ccipHome) if err != nil { return fmt.Errorf("setup exec don: %w", err) } return ValidateCCIPHomeConfigSetUp(capReg, ccipHome, newChainSel) } -func setupExecDON( - donID uint32, - execConfig ccip_home.CCIPHomeOCR3Config, - capReg *capabilities_registry.CapabilitiesRegistry, - home deployment.Chain, - nodes deployment.Nodes, - ccipHome *ccip_home.CCIPHome, -) error { - encodedSetCandidateCall, err := CCIPHomeABI.Pack( - "setCandidate", - donID, - execConfig.PluginType, - execConfig, - [32]byte{}, - ) - if err != nil { - return fmt.Errorf("pack set candidate call: %w", err) - } - - // set candidate call - tx, err := capReg.UpdateDON( - home.DeployerKey, - donID, - nodes.PeerIDs(), - []capabilities_registry.CapabilitiesRegistryCapabilityConfiguration{ - { - CapabilityId: CCIPCapabilityID, - Config: encodedSetCandidateCall, - }, - }, - false, - nodes.DefaultF(), - ) - if err != nil { - return fmt.Errorf("update don w/ exec config: %w", err) - } - - if _, err := deployment.ConfirmIfNoError(home, tx, err); err != nil { - return fmt.Errorf("confirm update don w/ exec config: %w", err) - } - - execCandidateDigest, err := ccipHome.GetCandidateDigest(nil, donID, execConfig.PluginType) - if err != nil { - return fmt.Errorf("get exec candidate digest 1st time: %w", err) - } - - if execCandidateDigest == [32]byte{} { - return fmt.Errorf("candidate digest is empty, expected nonempty") - } - - // promote candidate call - encodedPromotionCall, err := CCIPHomeABI.Pack( - "promoteCandidateAndRevokeActive", - donID, - execConfig.PluginType, - execCandidateDigest, - [32]byte{}, - ) - if err != nil { - return fmt.Errorf("pack promotion call: %w", err) - } - - tx, err = capReg.UpdateDON( - home.DeployerKey, - donID, - nodes.PeerIDs(), - []capabilities_registry.CapabilitiesRegistryCapabilityConfiguration{ - { - CapabilityId: CCIPCapabilityID, - Config: encodedPromotionCall, - }, - }, - false, - nodes.DefaultF(), - ) - if err != nil { - return fmt.Errorf("update don w/ exec config: %w", err) - } - bn, err := deployment.ConfirmIfNoError(home, tx, err) - if err != nil { - return fmt.Errorf("confirm update don w/ exec config: %w", err) - } - if bn == 0 { - return fmt.Errorf("UpdateDON tx not confirmed") - } - // check if candidate digest is promoted - pEvent, err := ccipHome.FilterConfigPromoted(&bind.FilterOpts{ - Context: context.Background(), - Start: bn, - }, [][32]byte{execCandidateDigest}) - if err != nil { - return fmt.Errorf("filter exec config promoted: %w", err) - } - if !pEvent.Next() { - return fmt.Errorf("exec config not promoted") - } - // check that candidate digest is empty. - execCandidateDigest, err = ccipHome.GetCandidateDigest(nil, donID, execConfig.PluginType) - if err != nil { - return fmt.Errorf("get exec candidate digest 2nd time: %w", err) - } - - if execCandidateDigest != [32]byte{} { - return fmt.Errorf("candidate digest is nonempty after promotion, expected empty") - } - - // check that active digest is non-empty. - execActiveDigest, err := ccipHome.GetActiveDigest(nil, donID, uint8(cctypes.PluginTypeCCIPExec)) - if err != nil { - return fmt.Errorf("get active exec digest: %w", err) - } - - if execActiveDigest == [32]byte{} { - return fmt.Errorf("active exec digest is empty, expected nonempty") - } - - execConfigs, err := ccipHome.GetAllConfigs(nil, donID, uint8(cctypes.PluginTypeCCIPExec)) - if err != nil { - return fmt.Errorf("get all exec configs 2nd time: %w", err) - } - - // print the above info - fmt.Printf("completed exec DON creation and promotion: donID: %d execCandidateDigest: %x, execActiveDigest: %x, execCandidateDigestFromGetAllConfigs: %x, execActiveDigestFromGetAllConfigs: %x\n", - donID, execCandidateDigest, execActiveDigest, execConfigs.CandidateConfig.ConfigDigest, execConfigs.ActiveConfig.ConfigDigest) - - return nil -} - // SetCandidateCommitPluginWithAddDonOps sets the candidate commit config by calling setCandidate on CCIPHome contract through the AddDON call on CapReg contract // This should be done first before calling any other UpdateDON calls // This proposes to set up OCR3 config for the commit plugin for the DON @@ -774,7 +361,7 @@ func NewDonWithCandidateOp( capReg *capabilities_registry.CapabilitiesRegistry, nodes deployment.Nodes, ) (mcms.Operation, error) { - encodedSetCandidateCall, err := CCIPHomeABI.Pack( + encodedSetCandidateCall, err := internal.CCIPHomeABI.Pack( "setCandidate", donID, pluginConfig.PluginType, @@ -786,7 +373,7 @@ func NewDonWithCandidateOp( } addDonTx, err := capReg.AddDON(deployment.SimTransactOpts(), nodes.PeerIDs(), []capabilities_registry.CapabilitiesRegistryCapabilityConfiguration{ { - CapabilityId: CCIPCapabilityID, + CapabilityId: internal.CCIPCapabilityID, Config: encodedSetCandidateCall, }, }, false, false, nodes.DefaultF()) @@ -807,7 +394,7 @@ func ValidateCCIPHomeConfigSetUp( chainSel uint64, ) error { // fetch DONID - donID, err := DonIDForChain(capReg, ccipHome, chainSel) + donID, err := internal.DonIDForChain(capReg, ccipHome, chainSel) if err != nil { return fmt.Errorf("fetch don id for chain: %w", err) } @@ -850,112 +437,6 @@ func ValidateCCIPHomeConfigSetUp( return nil } -func setupCommitDON( - donID uint32, - commitConfig ccip_home.CCIPHomeOCR3Config, - capReg *capabilities_registry.CapabilitiesRegistry, - home deployment.Chain, - nodes deployment.Nodes, - ccipHome *ccip_home.CCIPHome, -) error { - encodedSetCandidateCall, err := CCIPHomeABI.Pack( - "setCandidate", - donID, - commitConfig.PluginType, - commitConfig, - [32]byte{}, - ) - if err != nil { - return fmt.Errorf("pack set candidate call: %w", err) - } - tx, err := capReg.AddDON(home.DeployerKey, nodes.PeerIDs(), []capabilities_registry.CapabilitiesRegistryCapabilityConfiguration{ - { - CapabilityId: CCIPCapabilityID, - Config: encodedSetCandidateCall, - }, - }, false, false, nodes.DefaultF()) - if err != nil { - return fmt.Errorf("add don w/ commit config: %w", err) - } - - if _, err := deployment.ConfirmIfNoError(home, tx, err); err != nil { - return fmt.Errorf("confirm add don w/ commit config: %w", err) - } - - commitCandidateDigest, err := ccipHome.GetCandidateDigest(nil, donID, commitConfig.PluginType) - if err != nil { - return fmt.Errorf("get commit candidate digest: %w", err) - } - - if commitCandidateDigest == [32]byte{} { - return fmt.Errorf("candidate digest is empty, expected nonempty") - } - fmt.Printf("commit candidate digest after setCandidate: %x\n", commitCandidateDigest) - - encodedPromotionCall, err := CCIPHomeABI.Pack( - "promoteCandidateAndRevokeActive", - donID, - commitConfig.PluginType, - commitCandidateDigest, - [32]byte{}, - ) - if err != nil { - return fmt.Errorf("pack promotion call: %w", err) - } - - tx, err = capReg.UpdateDON( - home.DeployerKey, - donID, - nodes.PeerIDs(), - []capabilities_registry.CapabilitiesRegistryCapabilityConfiguration{ - { - CapabilityId: CCIPCapabilityID, - Config: encodedPromotionCall, - }, - }, - false, - nodes.DefaultF(), - ) - if err != nil { - return fmt.Errorf("update don w/ commit config: %w", err) - } - - if _, err := deployment.ConfirmIfNoError(home, tx, err); err != nil { - return fmt.Errorf("confirm update don w/ commit config: %w", err) - } - - // check that candidate digest is empty. - commitCandidateDigest, err = ccipHome.GetCandidateDigest(nil, donID, commitConfig.PluginType) - if err != nil { - return fmt.Errorf("get commit candidate digest 2nd time: %w", err) - } - - if commitCandidateDigest != [32]byte{} { - return fmt.Errorf("candidate digest is nonempty after promotion, expected empty") - } - - // check that active digest is non-empty. - commitActiveDigest, err := ccipHome.GetActiveDigest(nil, donID, uint8(cctypes.PluginTypeCCIPCommit)) - if err != nil { - return fmt.Errorf("get active commit digest: %w", err) - } - - if commitActiveDigest == [32]byte{} { - return fmt.Errorf("active commit digest is empty, expected nonempty") - } - - commitConfigs, err := ccipHome.GetAllConfigs(nil, donID, uint8(cctypes.PluginTypeCCIPCommit)) - if err != nil { - return fmt.Errorf("get all commit configs 2nd time: %w", err) - } - - // print the above information - fmt.Printf("completed commit DON creation and promotion: donID: %d, commitCandidateDigest: %x, commitActiveDigest: %x, commitCandidateDigestFromGetAllConfigs: %x, commitActiveDigestFromGetAllConfigs: %x\n", - donID, commitCandidateDigest, commitActiveDigest, commitConfigs.CandidateConfig.ConfigDigest, commitConfigs.ActiveConfig.ConfigDigest) - - return nil -} - func AddDON( lggr logger.Logger, ocrSecrets deployment.OCRSecrets, @@ -971,7 +452,7 @@ func AddDON( nodes deployment.Nodes, tokenConfigs []pluginconfig.TokenDataObserverConfig, ) error { - ocrConfigs, err := BuildOCR3ConfigForCCIPHome( + ocrConfigs, err := internal.BuildOCR3ConfigForCCIPHome( ocrSecrets, offRamp, dest, feedChainSel, tokenInfo, nodes, rmnHomeAddress, tokenConfigs) if err != nil { return err @@ -980,13 +461,13 @@ func AddDON( if err != nil { return err } - don, err := LatestCCIPDON(capReg) + don, err := internal.LatestCCIPDON(capReg) if err != nil { return err } lggr.Infow("Added DON", "donID", don.Id) - offrampOCR3Configs, err := BuildSetOCR3ConfigArgs(don.Id, ccipHome, dest.Selector) + offrampOCR3Configs, err := internal.BuildSetOCR3ConfigArgs(don.Id, ccipHome, dest.Selector) if err != nil { return err } diff --git a/deployment/ccip/changeset/internal/deploy_home_chain.go b/deployment/ccip/changeset/internal/deploy_home_chain.go index 5bf0569ce8c..af41b290828 100644 --- a/deployment/ccip/changeset/internal/deploy_home_chain.go +++ b/deployment/ccip/changeset/internal/deploy_home_chain.go @@ -1 +1,536 @@ package internal + +import ( + "context" + "fmt" + "os" + "time" + + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/smartcontractkit/libocr/offchainreporting2plus/confighelper" + "github.com/smartcontractkit/libocr/offchainreporting2plus/ocr3confighelper" + + "github.com/smartcontractkit/chainlink-ccip/pkg/types/ccipocr3" + "github.com/smartcontractkit/chainlink-ccip/pluginconfig" + "github.com/smartcontractkit/chainlink-common/pkg/config" + "github.com/smartcontractkit/chainlink-common/pkg/merklemulti" + "github.com/smartcontractkit/chainlink/deployment" + "github.com/smartcontractkit/chainlink/v2/core/capabilities/ccip/types" + "github.com/smartcontractkit/chainlink/v2/core/chains/evm/utils" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/ccip_home" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/ccip/generated/offramp" + "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/keystone/generated/capabilities_registry" +) + +const ( + CapabilityLabelledName = "ccip" + CapabilityVersion = "v1.0.0" + + FirstBlockAge = 8 * time.Hour + RemoteGasPriceBatchWriteFrequency = 30 * time.Minute + TokenPriceBatchWriteFrequency = 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 = 500 * time.Millisecond + MaxDurationObservation = 5 * time.Second + MaxDurationShouldAcceptAttestedReport = 10 * time.Second + MaxDurationShouldTransmitAcceptedReport = 10 * time.Second +) + +var ( + CCIPCapabilityID = utils.Keccak256Fixed(MustABIEncode(`[{"type": "string"}, {"type": "string"}]`, CapabilityLabelledName, CapabilityVersion)) + CCIPHomeABI *abi.ABI +) + +func init() { + var err error + CCIPHomeABI, err = ccip_home.CCIPHomeMetaData.GetAbi() + if err != nil { + panic(err) + } +} + +func MustABIEncode(abiString string, args ...interface{}) []byte { + encoded, err := utils.ABIEncode(abiString, args...) + if err != nil { + panic(err) + } + return encoded +} + +// getNodeOperatorIDMap returns a map of node operator names to their IDs +// If maxNops is greater than the number of node operators, it will return all node operators +// Unused now but could be useful in the future. +func getNodeOperatorIDMap(capReg *capabilities_registry.CapabilitiesRegistry, maxNops uint32) (map[string]uint32, error) { + nopIdByName := make(map[string]uint32) + operators, err := capReg.GetNodeOperators(nil) + if err != nil { + return nil, err + } + if len(operators) < int(maxNops) { + maxNops = uint32(len(operators)) + } + for i := uint32(1); i <= maxNops; i++ { + operator, err := capReg.GetNodeOperator(nil, i) + if err != nil { + return nil, err + } + nopIdByName[operator.Name] = i + } + return nopIdByName, nil +} + +func LatestCCIPDON(registry *capabilities_registry.CapabilitiesRegistry) (*capabilities_registry.CapabilitiesRegistryDONInfo, error) { + dons, err := registry.GetDONs(nil) + if err != nil { + return nil, err + } + var ccipDON capabilities_registry.CapabilitiesRegistryDONInfo + for _, don := range dons { + if len(don.CapabilityConfigurations) == 1 && + don.CapabilityConfigurations[0].CapabilityId == CCIPCapabilityID && + don.Id > ccipDON.Id { + ccipDON = don + } + } + return &ccipDON, nil +} + +// DonIDForChain returns the DON ID for the chain with the given selector +// It looks up with the CCIPHome contract to find the OCR3 configs for the DONs, and returns the DON ID for the chain matching with the given selector from the OCR3 configs +func DonIDForChain(registry *capabilities_registry.CapabilitiesRegistry, ccipHome *ccip_home.CCIPHome, chainSelector uint64) (uint32, error) { + dons, err := registry.GetDONs(nil) + if err != nil { + return 0, err + } + // TODO: what happens if there are multiple dons for one chain (accidentally?) + for _, don := range dons { + if len(don.CapabilityConfigurations) == 1 && + don.CapabilityConfigurations[0].CapabilityId == CCIPCapabilityID { + configs, err := ccipHome.GetAllConfigs(nil, don.Id, uint8(types.PluginTypeCCIPCommit)) + if err != nil { + return 0, err + } + if configs.ActiveConfig.Config.ChainSelector == chainSelector || configs.CandidateConfig.Config.ChainSelector == chainSelector { + return don.Id, nil + } + } + } + return 0, fmt.Errorf("no DON found for chain %d", chainSelector) +} + +func BuildSetOCR3ConfigArgs( + donID uint32, + ccipHome *ccip_home.CCIPHome, + destSelector uint64, +) ([]offramp.MultiOCR3BaseOCRConfigArgs, error) { + var offrampOCR3Configs []offramp.MultiOCR3BaseOCRConfigArgs + for _, pluginType := range []types.PluginType{types.PluginTypeCCIPCommit, types.PluginTypeCCIPExec} { + ocrConfig, err2 := ccipHome.GetAllConfigs(&bind.CallOpts{ + Context: context.Background(), + }, donID, uint8(pluginType)) + if err2 != nil { + return nil, err2 + } + + fmt.Printf("pluginType: %s, destSelector: %d, donID: %d, activeConfig digest: %x, candidateConfig digest: %x\n", + pluginType.String(), destSelector, donID, ocrConfig.ActiveConfig.ConfigDigest, ocrConfig.CandidateConfig.ConfigDigest) + + // we expect only an active config and no candidate config. + if ocrConfig.ActiveConfig.ConfigDigest == [32]byte{} || ocrConfig.CandidateConfig.ConfigDigest != [32]byte{} { + return nil, fmt.Errorf("invalid OCR3 config state, expected active config and no candidate config, donID: %d", donID) + } + + activeConfig := ocrConfig.ActiveConfig + var signerAddresses []common.Address + var transmitterAddresses []common.Address + for _, node := range activeConfig.Config.Nodes { + signerAddresses = append(signerAddresses, common.BytesToAddress(node.SignerKey)) + transmitterAddresses = append(transmitterAddresses, common.BytesToAddress(node.TransmitterKey)) + } + + offrampOCR3Configs = append(offrampOCR3Configs, offramp.MultiOCR3BaseOCRConfigArgs{ + ConfigDigest: activeConfig.ConfigDigest, + OcrPluginType: uint8(pluginType), + F: activeConfig.Config.FRoleDON, + IsSignatureVerificationEnabled: pluginType == types.PluginTypeCCIPCommit, + Signers: signerAddresses, + Transmitters: transmitterAddresses, + }) + } + return offrampOCR3Configs, nil +} + +func SetupExecDON( + donID uint32, + execConfig ccip_home.CCIPHomeOCR3Config, + capReg *capabilities_registry.CapabilitiesRegistry, + home deployment.Chain, + nodes deployment.Nodes, + ccipHome *ccip_home.CCIPHome, +) error { + encodedSetCandidateCall, err := CCIPHomeABI.Pack( + "setCandidate", + donID, + execConfig.PluginType, + execConfig, + [32]byte{}, + ) + if err != nil { + return fmt.Errorf("pack set candidate call: %w", err) + } + + // set candidate call + tx, err := capReg.UpdateDON( + home.DeployerKey, + donID, + nodes.PeerIDs(), + []capabilities_registry.CapabilitiesRegistryCapabilityConfiguration{ + { + CapabilityId: CCIPCapabilityID, + Config: encodedSetCandidateCall, + }, + }, + false, + nodes.DefaultF(), + ) + if err != nil { + return fmt.Errorf("update don w/ exec config: %w", err) + } + + if _, err := deployment.ConfirmIfNoError(home, tx, err); err != nil { + return fmt.Errorf("confirm update don w/ exec config: %w", err) + } + + execCandidateDigest, err := ccipHome.GetCandidateDigest(nil, donID, execConfig.PluginType) + if err != nil { + return fmt.Errorf("get exec candidate digest 1st time: %w", err) + } + + if execCandidateDigest == [32]byte{} { + return fmt.Errorf("candidate digest is empty, expected nonempty") + } + + // promote candidate call + encodedPromotionCall, err := CCIPHomeABI.Pack( + "promoteCandidateAndRevokeActive", + donID, + execConfig.PluginType, + execCandidateDigest, + [32]byte{}, + ) + if err != nil { + return fmt.Errorf("pack promotion call: %w", err) + } + + tx, err = capReg.UpdateDON( + home.DeployerKey, + donID, + nodes.PeerIDs(), + []capabilities_registry.CapabilitiesRegistryCapabilityConfiguration{ + { + CapabilityId: CCIPCapabilityID, + Config: encodedPromotionCall, + }, + }, + false, + nodes.DefaultF(), + ) + if err != nil { + return fmt.Errorf("update don w/ exec config: %w", err) + } + bn, err := deployment.ConfirmIfNoError(home, tx, err) + if err != nil { + return fmt.Errorf("confirm update don w/ exec config: %w", err) + } + if bn == 0 { + return fmt.Errorf("UpdateDON tx not confirmed") + } + // check if candidate digest is promoted + pEvent, err := ccipHome.FilterConfigPromoted(&bind.FilterOpts{ + Context: context.Background(), + Start: bn, + }, [][32]byte{execCandidateDigest}) + if err != nil { + return fmt.Errorf("filter exec config promoted: %w", err) + } + if !pEvent.Next() { + return fmt.Errorf("exec config not promoted") + } + // check that candidate digest is empty. + execCandidateDigest, err = ccipHome.GetCandidateDigest(nil, donID, execConfig.PluginType) + if err != nil { + return fmt.Errorf("get exec candidate digest 2nd time: %w", err) + } + + if execCandidateDigest != [32]byte{} { + return fmt.Errorf("candidate digest is nonempty after promotion, expected empty") + } + + // check that active digest is non-empty. + execActiveDigest, err := ccipHome.GetActiveDigest(nil, donID, uint8(types.PluginTypeCCIPExec)) + if err != nil { + return fmt.Errorf("get active exec digest: %w", err) + } + + if execActiveDigest == [32]byte{} { + return fmt.Errorf("active exec digest is empty, expected nonempty") + } + + execConfigs, err := ccipHome.GetAllConfigs(nil, donID, uint8(types.PluginTypeCCIPExec)) + if err != nil { + return fmt.Errorf("get all exec configs 2nd time: %w", err) + } + + // print the above info + fmt.Printf("completed exec DON creation and promotion: donID: %d execCandidateDigest: %x, execActiveDigest: %x, execCandidateDigestFromGetAllConfigs: %x, execActiveDigestFromGetAllConfigs: %x\n", + donID, execCandidateDigest, execActiveDigest, execConfigs.CandidateConfig.ConfigDigest, execConfigs.ActiveConfig.ConfigDigest) + + return nil +} + +func SetupCommitDON( + donID uint32, + commitConfig ccip_home.CCIPHomeOCR3Config, + capReg *capabilities_registry.CapabilitiesRegistry, + home deployment.Chain, + nodes deployment.Nodes, + ccipHome *ccip_home.CCIPHome, +) error { + encodedSetCandidateCall, err := CCIPHomeABI.Pack( + "setCandidate", + donID, + commitConfig.PluginType, + commitConfig, + [32]byte{}, + ) + if err != nil { + return fmt.Errorf("pack set candidate call: %w", err) + } + tx, err := capReg.AddDON(home.DeployerKey, nodes.PeerIDs(), []capabilities_registry.CapabilitiesRegistryCapabilityConfiguration{ + { + CapabilityId: CCIPCapabilityID, + Config: encodedSetCandidateCall, + }, + }, false, false, nodes.DefaultF()) + if err != nil { + return fmt.Errorf("add don w/ commit config: %w", err) + } + + if _, err := deployment.ConfirmIfNoError(home, tx, err); err != nil { + return fmt.Errorf("confirm add don w/ commit config: %w", err) + } + + commitCandidateDigest, err := ccipHome.GetCandidateDigest(nil, donID, commitConfig.PluginType) + if err != nil { + return fmt.Errorf("get commit candidate digest: %w", err) + } + + if commitCandidateDigest == [32]byte{} { + return fmt.Errorf("candidate digest is empty, expected nonempty") + } + fmt.Printf("commit candidate digest after setCandidate: %x\n", commitCandidateDigest) + + encodedPromotionCall, err := CCIPHomeABI.Pack( + "promoteCandidateAndRevokeActive", + donID, + commitConfig.PluginType, + commitCandidateDigest, + [32]byte{}, + ) + if err != nil { + return fmt.Errorf("pack promotion call: %w", err) + } + + tx, err = capReg.UpdateDON( + home.DeployerKey, + donID, + nodes.PeerIDs(), + []capabilities_registry.CapabilitiesRegistryCapabilityConfiguration{ + { + CapabilityId: CCIPCapabilityID, + Config: encodedPromotionCall, + }, + }, + false, + nodes.DefaultF(), + ) + if err != nil { + return fmt.Errorf("update don w/ commit config: %w", err) + } + + if _, err := deployment.ConfirmIfNoError(home, tx, err); err != nil { + return fmt.Errorf("confirm update don w/ commit config: %w", err) + } + + // check that candidate digest is empty. + commitCandidateDigest, err = ccipHome.GetCandidateDigest(nil, donID, commitConfig.PluginType) + if err != nil { + return fmt.Errorf("get commit candidate digest 2nd time: %w", err) + } + + if commitCandidateDigest != [32]byte{} { + return fmt.Errorf("candidate digest is nonempty after promotion, expected empty") + } + + // check that active digest is non-empty. + commitActiveDigest, err := ccipHome.GetActiveDigest(nil, donID, uint8(types.PluginTypeCCIPCommit)) + if err != nil { + return fmt.Errorf("get active commit digest: %w", err) + } + + if commitActiveDigest == [32]byte{} { + return fmt.Errorf("active commit digest is empty, expected nonempty") + } + + commitConfigs, err := ccipHome.GetAllConfigs(nil, donID, uint8(types.PluginTypeCCIPCommit)) + if err != nil { + return fmt.Errorf("get all commit configs 2nd time: %w", err) + } + + // print the above information + fmt.Printf("completed commit DON creation and promotion: donID: %d, commitCandidateDigest: %x, commitActiveDigest: %x, commitCandidateDigestFromGetAllConfigs: %x, commitActiveDigestFromGetAllConfigs: %x\n", + donID, commitCandidateDigest, commitActiveDigest, commitConfigs.CandidateConfig.ConfigDigest, commitConfigs.ActiveConfig.ConfigDigest) + + return nil +} + +func BuildOCR3ConfigForCCIPHome( + ocrSecrets deployment.OCRSecrets, + offRamp *offramp.OffRamp, + dest deployment.Chain, + feedChainSel uint64, + tokenInfo map[ccipocr3.UnknownEncodedAddress]pluginconfig.TokenInfo, + nodes deployment.Nodes, + rmnHomeAddress common.Address, + configs []pluginconfig.TokenDataObserverConfig, +) (map[types.PluginType]ccip_home.CCIPHomeOCR3Config, error) { + p2pIDs := nodes.PeerIDs() + // Get OCR3 Config from helper + var schedule []int + var oracles []confighelper.OracleIdentityExtra + for _, node := range nodes { + schedule = append(schedule, 1) + cfg := node.SelToOCRConfig[dest.Selector] + oracles = append(oracles, confighelper.OracleIdentityExtra{ + OracleIdentity: confighelper.OracleIdentity{ + OnchainPublicKey: cfg.OnchainPublicKey, + TransmitAccount: cfg.TransmitAccount, + OffchainPublicKey: cfg.OffchainPublicKey, + PeerID: cfg.PeerID.String()[4:], + }, ConfigEncryptionPublicKey: cfg.ConfigEncryptionPublicKey, + }) + } + + // Add DON on capability registry contract + ocr3Configs := make(map[types.PluginType]ccip_home.CCIPHomeOCR3Config) + for _, pluginType := range []types.PluginType{types.PluginTypeCCIPCommit, types.PluginTypeCCIPExec} { + var encodedOffchainConfig []byte + var err2 error + if pluginType == types.PluginTypeCCIPCommit { + encodedOffchainConfig, err2 = pluginconfig.EncodeCommitOffchainConfig(pluginconfig.CommitOffchainConfig{ + RemoteGasPriceBatchWriteFrequency: *config.MustNewDuration(RemoteGasPriceBatchWriteFrequency), + TokenPriceBatchWriteFrequency: *config.MustNewDuration(TokenPriceBatchWriteFrequency), + PriceFeedChainSelector: ccipocr3.ChainSelector(feedChainSel), + TokenInfo: tokenInfo, + NewMsgScanBatchSize: merklemulti.MaxNumberTreeLeaves, + MaxReportTransmissionCheckAttempts: 5, + MaxMerkleTreeSize: merklemulti.MaxNumberTreeLeaves, + SignObservationPrefix: "chainlink ccip 1.6 rmn observation", + RMNEnabled: os.Getenv("ENABLE_RMN") == "true", // only enabled in manual test + }) + } else { + encodedOffchainConfig, err2 = pluginconfig.EncodeExecuteOffchainConfig(pluginconfig.ExecuteOffchainConfig{ + BatchGasLimit: BatchGasLimit, + RelativeBoostPerWaitHour: RelativeBoostPerWaitHour, + MessageVisibilityInterval: *config.MustNewDuration(FirstBlockAge), + InflightCacheExpiry: *config.MustNewDuration(InflightCacheExpiry), + RootSnoozeTime: *config.MustNewDuration(RootSnoozeTime), + BatchingStrategyID: BatchingStrategyID, + TokenDataObservers: configs, + }) + } + if err2 != nil { + return nil, err2 + } + signers, transmitters, configF, _, offchainConfigVersion, offchainConfig, err2 := ocr3confighelper.ContractSetConfigArgsDeterministic( + ocrSecrets.EphemeralSk, + ocrSecrets.SharedSecret, + DeltaProgress, + DeltaResend, + DeltaInitial, + DeltaRound, + DeltaGrace, + DeltaCertifiedCommitRequest, + DeltaStage, + Rmax, + schedule, + oracles, + encodedOffchainConfig, + nil, // maxDurationInitialization + MaxDurationQuery, + MaxDurationObservation, + MaxDurationShouldAcceptAttestedReport, + MaxDurationShouldTransmitAcceptedReport, + int(nodes.DefaultF()), + []byte{}, // empty OnChainConfig + ) + if err2 != nil { + return nil, err2 + } + + signersBytes := make([][]byte, len(signers)) + for i, signer := range signers { + signersBytes[i] = signer + } + + transmittersBytes := make([][]byte, len(transmitters)) + for i, transmitter := range transmitters { + parsed, err2 := common.ParseHexOrString(string(transmitter)) + if err2 != nil { + return nil, err2 + } + transmittersBytes[i] = parsed + } + + var ocrNodes []ccip_home.CCIPHomeOCR3Node + for i := range nodes { + ocrNodes = append(ocrNodes, ccip_home.CCIPHomeOCR3Node{ + P2pId: p2pIDs[i], + SignerKey: signersBytes[i], + TransmitterKey: transmittersBytes[i], + }) + } + + _, ok := ocr3Configs[pluginType] + if ok { + return nil, fmt.Errorf("pluginType %s already exists in ocr3Configs", pluginType.String()) + } + + ocr3Configs[pluginType] = ccip_home.CCIPHomeOCR3Config{ + PluginType: uint8(pluginType), + ChainSelector: dest.Selector, + FRoleDON: configF, + OffchainConfigVersion: offchainConfigVersion, + OfframpAddress: offRamp.Address().Bytes(), + Nodes: ocrNodes, + OffchainConfig: offchainConfig, + RmnHomeAddress: rmnHomeAddress.Bytes(), + } + } + + return ocr3Configs, nil +} diff --git a/deployment/ccip/changeset/jobs.go b/deployment/ccip/changeset/jobs.go index 5cfe112ff53..3a5b0e294d8 100644 --- a/deployment/ccip/changeset/jobs.go +++ b/deployment/ccip/changeset/jobs.go @@ -2,6 +2,7 @@ package changeset import ( "github.com/smartcontractkit/chainlink/deployment" + "github.com/smartcontractkit/chainlink/deployment/ccip/changeset/internal" "github.com/smartcontractkit/chainlink/v2/core/capabilities/ccip/validate" "github.com/smartcontractkit/chainlink/v2/core/services/relay" ) @@ -26,8 +27,8 @@ func NewCCIPJobSpecs(nodeIds []string, oc deployment.OffchainClient) (map[string if !node.IsBootstrap { spec, err = validate.NewCCIPSpecToml(validate.SpecArgs{ P2PV2Bootstrappers: nodes.BootstrapLocators(), - CapabilityVersion: CapabilityVersion, - CapabilityLabelledName: CapabilityLabelledName, + CapabilityVersion: internal.CapabilityVersion, + CapabilityLabelledName: internal.CapabilityLabelledName, OCRKeyBundleIDs: map[string]string{ // TODO: Validate that that all EVM chains are using the same keybundle. relay.NetworkEVM: node.FirstOCRKeybundle().KeyBundleID, @@ -39,8 +40,8 @@ func NewCCIPJobSpecs(nodeIds []string, oc deployment.OffchainClient) (map[string } else { spec, err = validate.NewCCIPSpecToml(validate.SpecArgs{ P2PV2Bootstrappers: []string{}, // Intentionally empty for bootstraps. - CapabilityVersion: CapabilityVersion, - CapabilityLabelledName: CapabilityLabelledName, + CapabilityVersion: internal.CapabilityVersion, + CapabilityLabelledName: internal.CapabilityLabelledName, OCRKeyBundleIDs: map[string]string{}, // TODO: validate that all EVM chains are using the same keybundle P2PKeyID: node.PeerID.String(),