From 7e8268fbd492fdef43f735e8c00c794766f9637a Mon Sep 17 00:00:00 2001 From: krehermann <16602512+krehermann@users.noreply.github.com> Date: Thu, 5 Dec 2024 17:34:30 -0500 Subject: [PATCH] plumbing update nodes --- deployment/keystone/capability_management.go | 25 +++++++++------- deployment/keystone/changeset/helpers_test.go | 9 ++---- .../keystone/changeset/internal/test/utils.go | 1 + .../keystone/changeset/internal/update_don.go | 7 ++++- .../changeset/internal/update_nodes.go | 4 ++- .../changeset/update_node_capabilities.go | 2 ++ deployment/keystone/changeset/update_nodes.go | 30 +++++++++++++++++-- 7 files changed, 57 insertions(+), 21 deletions(-) diff --git a/deployment/keystone/capability_management.go b/deployment/keystone/capability_management.go index 3887430c393..888cba5b931 100644 --- a/deployment/keystone/capability_management.go +++ b/deployment/keystone/capability_management.go @@ -1,7 +1,6 @@ package keystone import ( - "bytes" "fmt" "github.com/smartcontractkit/ccip-owner-contracts/pkg/proposal/timelock" @@ -54,26 +53,30 @@ func CapabilityID(c kcr.CapabilitiesRegistryCapability) string { // contract reverts on adding the same capability twice and that would cause the whole transaction to revert // which is very bad for us for mcms func dedupCapabilities(registry *kcr.CapabilitiesRegistry, capabilities []kcr.CapabilitiesRegistryCapability) ([]kcr.CapabilitiesRegistryCapability, error) { - var deduped []kcr.CapabilitiesRegistryCapability + var out []kcr.CapabilitiesRegistryCapability existing, err := registry.GetCapabilities(nil) if err != nil { return nil, fmt.Errorf("failed to call GetCapabilities: %w", err) } + existingByID := make(map[[32]byte]struct{}) + for _, cap := range existing { + existingByID[cap.HashedId] = struct{}{} + } + seen := make(map[string]struct{}) for _, candidate := range capabilities { - isNew := true h, err := registry.GetHashedCapabilityId(nil, candidate.LabelledName, candidate.Version) if err != nil { return nil, fmt.Errorf("failed to call GetHashedCapabilityId: %w", err) } - for _, cap := range existing { - if bytes.Equal(h[:], cap.HashedId[:]) { - isNew = false - break - } + // dedup input capabilities + if _, exists := seen[CapabilityID(candidate)]; exists { + continue } - if isNew { - deduped = append(deduped, candidate) + seen[CapabilityID(candidate)] = struct{}{} + // dedup with respect to the registry + if _, exists := existingByID[h]; !exists { + out = append(out, candidate) } } - return deduped, nil + return out, nil } diff --git a/deployment/keystone/changeset/helpers_test.go b/deployment/keystone/changeset/helpers_test.go index d4435d8f7a6..0c1e27cc529 100644 --- a/deployment/keystone/changeset/helpers_test.go +++ b/deployment/keystone/changeset/helpers_test.go @@ -223,15 +223,13 @@ func SetupTestEnv(t *testing.T, c TestConfig) TestEnv { } var allDons = []keystone.DonCapabilities{wfDon, cwDon, assetDon} - _, err = kschangeset.ConfigureInitialContractsChangeset(env, kschangeset.InitialContractsCfg{ + csOut, err := kschangeset.ConfigureInitialContractsChangeset(env, kschangeset.InitialContractsCfg{ RegistryChainSel: registryChainSel, Dons: allDons, OCR3Config: &ocr3Config, }) require.NoError(t, err) - // TODO: KS-rm_deploy_opt - //require.Nil(t, csOut.AddressBook, "no new addresses should be created in configure initial contracts") - //require.NoError(t, env.ExistingAddresses.Merge(csOut.AddressBook)) + require.Nil(t, csOut.AddressBook, "no new addresses should be created in configure initial contracts") req := &keystone.GetContractSetsRequest{ Chains: env.Chains, @@ -259,8 +257,7 @@ func SetupTestEnv(t *testing.T, c TestConfig) TestEnv { validateDon(t, gotRegistry, assetNodes, assetDon) if c.UseMCMS { - // TODO: mcms on all the chains, currently only on the registry chain. need to fix this for forwarders - // deploy, configure and xfer ownership of MCMS + // deploy, configure and xfer ownership of MCMS on all chains timelockCfgs := make(map[uint64]commontypes.MCMSWithTimelockConfig) for sel := range env.Chains { t.Logf("Enabling MCMS on chain %d", sel) diff --git a/deployment/keystone/changeset/internal/test/utils.go b/deployment/keystone/changeset/internal/test/utils.go index 6fe4a8f4a2e..a7aed2c9cb1 100644 --- a/deployment/keystone/changeset/internal/test/utils.go +++ b/deployment/keystone/changeset/internal/test/utils.go @@ -33,6 +33,7 @@ type SetupTestRegistryRequest struct { P2pToCapabilities map[p2pkey.PeerID][]kcr.CapabilitiesRegistryCapability NopToNodes map[kcr.CapabilitiesRegistryNodeOperator][]*internal.P2PSignerEnc Dons []Don + // TODO maybe add support for MCMS at this level } type SetupTestRegistryResponse struct { diff --git a/deployment/keystone/changeset/internal/update_don.go b/deployment/keystone/changeset/internal/update_don.go index 4883368dc4d..d56f77c1c78 100644 --- a/deployment/keystone/changeset/internal/update_don.go +++ b/deployment/keystone/changeset/internal/update_don.go @@ -9,6 +9,7 @@ import ( "sort" "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/smartcontractkit/ccip-owner-contracts/pkg/proposal/timelock" "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink/deployment" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/p2pkey" @@ -31,6 +32,8 @@ type UpdateDonRequest struct { P2PIDs []p2pkey.PeerID // this is the unique identifier for the don CapabilityConfigs []CapabilityConfig // if Config subfield is nil, a default config is used + + UseMCMS bool } func (r *UpdateDonRequest) appendNodeCapabilitiesRequest() *AppendNodeCapabilitiesRequest { @@ -38,6 +41,7 @@ func (r *UpdateDonRequest) appendNodeCapabilitiesRequest() *AppendNodeCapabiliti Chain: r.Chain, Registry: r.Registry, P2pToCapabilities: make(map[p2pkey.PeerID][]kcr.CapabilitiesRegistryCapability), + UseMCMS: r.UseMCMS, } for _, p2pid := range r.P2PIDs { if _, exists := out.P2pToCapabilities[p2pid]; !exists { @@ -61,7 +65,8 @@ func (r *UpdateDonRequest) Validate() error { } type UpdateDonResponse struct { - DonInfo kcr.CapabilitiesRegistryDONInfo + DonInfo kcr.CapabilitiesRegistryDONInfo + Proposals []timelock.MCMSWithTimelockProposal } func UpdateDon(lggr logger.Logger, req *UpdateDonRequest) (*UpdateDonResponse, error) { diff --git a/deployment/keystone/changeset/internal/update_nodes.go b/deployment/keystone/changeset/internal/update_nodes.go index 016b32d7b7c..618d8651a4a 100644 --- a/deployment/keystone/changeset/internal/update_nodes.go +++ b/deployment/keystone/changeset/internal/update_nodes.go @@ -31,7 +31,9 @@ type UpdateNodesRequest struct { Registry *kcr.CapabilitiesRegistry P2pToUpdates map[p2pkey.PeerID]NodeUpdate - UseMCMS bool + + ContractSet kslib.ContractSet // contract set for the given chain + UseMCMS bool } func (req *UpdateNodesRequest) NodeParams() ([]kcr.CapabilitiesRegistryNodeParams, error) { diff --git a/deployment/keystone/changeset/update_node_capabilities.go b/deployment/keystone/changeset/update_node_capabilities.go index 1d6dde6af5a..655614ed7f0 100644 --- a/deployment/keystone/changeset/update_node_capabilities.go +++ b/deployment/keystone/changeset/update_node_capabilities.go @@ -54,6 +54,7 @@ type MutateNodeCapabilitiesRequest struct { RegistryChainSel uint64 P2pToCapabilities map[p2pkey.PeerID][]kcr.CapabilitiesRegistryCapability + UseMCMS bool } func (req *MutateNodeCapabilitiesRequest) Validate() error { @@ -95,6 +96,7 @@ func (req *MutateNodeCapabilitiesRequest) updateNodeCapabilitiesImplRequest(e de Chain: registryChain, Registry: registry, P2pToCapabilities: req.P2pToCapabilities, + UseMCMS: req.UseMCMS, }, nil } diff --git a/deployment/keystone/changeset/update_nodes.go b/deployment/keystone/changeset/update_nodes.go index 7e436160d2e..7dfd4a5c44a 100644 --- a/deployment/keystone/changeset/update_nodes.go +++ b/deployment/keystone/changeset/update_nodes.go @@ -4,19 +4,45 @@ import ( "fmt" "github.com/smartcontractkit/chainlink/deployment" + + kslib "github.com/smartcontractkit/chainlink/deployment/keystone" "github.com/smartcontractkit/chainlink/deployment/keystone/changeset/internal" + "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/p2pkey" ) var _ deployment.ChangeSet[*UpdateNodesRequest] = UpdateNodes -type UpdateNodesRequest = internal.UpdateNodesRequest +type UpdateNodesRequest struct { + RegistryChainSel uint64 + P2pToUpdates map[p2pkey.PeerID]NodeUpdate + + UseMCMS bool +} type NodeUpdate = internal.NodeUpdate // UpdateNodes updates the a set of nodes. // This a complex action in practice that involves registering missing capabilities, adding the nodes, and updating // the capabilities of the DON func UpdateNodes(env deployment.Environment, req *UpdateNodesRequest) (deployment.ChangesetOutput, error) { - _, err := internal.UpdateNodes(env.Logger, req) + // extract the registry contract and chain from the environment + registryChain, ok := env.Chains[req.RegistryChainSel] + if !ok { + return deployment.ChangesetOutput{}, fmt.Errorf("registry chain selector %d does not exist in environment", req.RegistryChainSel) + } + contracts, err := kslib.GetContractSets(env.Logger, &kslib.GetContractSetsRequest{ + Chains: env.Chains, + AddressBook: env.ExistingAddresses, + }) + if err != nil { + return deployment.ChangesetOutput{}, fmt.Errorf("failed to get contract sets: %w", err) + } + + _, err = internal.UpdateNodes(env.Logger, &internal.UpdateNodesRequest{ + Chain: registryChain, + Registry: contracts.ContractSets[req.RegistryChainSel].CapabilitiesRegistry, + P2pToUpdates: req.P2pToUpdates, + UseMCMS: req.UseMCMS, + }) if err != nil { return deployment.ChangesetOutput{}, fmt.Errorf("failed to update don: %w", err) }