From cb6ec96ebf162414472ae9f76014f46e4af4ea3a Mon Sep 17 00:00:00 2001 From: Graham Goh Date: Tue, 18 Feb 2025 11:52:46 +1100 Subject: [PATCH] fix(mcms): update keystones changesets to new MCMS Update the existing keystone changesets to use the new MCMS library types. We want to eventually remove the legacy MCMS type. There should be no changes needed on the CLD side as there are no breaking api type changes on the CLD facing API. JIRA: https://smartcontract-it.atlassian.net/browse/DPA-1476 --- deployment/common/changeset/test_helpers.go | 17 +++++-- .../common/proposalutils/mcms_test_helpers.go | 33 +++++++++---- .../keystone/changeset/add_capabilities.go | 29 ++++++++---- .../changeset/add_capabilities_test.go | 2 +- deployment/keystone/changeset/add_nodes.go | 31 +++++++----- .../keystone/changeset/add_nodes_test.go | 4 +- .../changeset/append_node_capabilities.go | 29 ++++++++---- .../append_node_capabilities_test.go | 8 ++-- deployment/keystone/changeset/deploy_ocr3.go | 29 ++++++++---- .../keystone/changeset/deploy_ocr3_test.go | 9 ++-- .../internal/capability_management.go | 25 +++++----- .../keystone/changeset/internal/deploy.go | 45 +++++++++--------- .../changeset/internal/deploy_test.go | 9 ++-- .../keystone/changeset/internal/ocr3config.go | 23 ++++----- .../keystone/changeset/internal/update_don.go | 23 ++++----- .../changeset/internal/update_nodes.go | 27 +++++------ deployment/keystone/changeset/update_don.go | 6 +-- .../keystone/changeset/update_don_test.go | 4 +- .../changeset/update_node_capabilities.go | 31 +++++++----- .../update_node_capabilities_test.go | 8 ++-- deployment/keystone/changeset/update_nodes.go | 31 +++++++----- .../keystone/changeset/update_nodes_test.go | 2 +- .../changeset/workflowregistry/strategies.go | 47 +++++++++++-------- .../workflowregistry/update_allowed_dons.go | 1 + .../update_allowed_dons_test.go | 2 +- .../update_authorized_addresses.go | 1 + .../update_authorized_addresses_test.go | 2 +- 27 files changed, 275 insertions(+), 203 deletions(-) diff --git a/deployment/common/changeset/test_helpers.go b/deployment/common/changeset/test_helpers.go index d0a472ccd8c..5e3dc928849 100644 --- a/deployment/common/changeset/test_helpers.go +++ b/deployment/common/changeset/test_helpers.go @@ -96,14 +96,25 @@ func ApplyChangesets(t *testing.T, e deployment.Environment, timelockContractsPe if out.MCMSTimelockProposals != nil { for _, prop := range out.MCMSTimelockProposals { mcmProp := proposalutils.SignMCMSTimelockProposal(t, e, &prop) - proposalutils.ExecuteMCMSProposalV2(t, e, mcmProp) - proposalutils.ExecuteMCMSTimelockProposalV2(t, e, &prop) + // return the error so devs can ensure expected reversions + err = proposalutils.ExecuteMCMSProposalV2(t, e, mcmProp) + if err != nil { + return deployment.Environment{}, err + } + err = proposalutils.ExecuteMCMSTimelockProposalV2(t, e, &prop) + if err != nil { + return deployment.Environment{}, err + } } } if out.MCMSProposals != nil { for _, prop := range out.MCMSProposals { p := proposalutils.SignMCMSProposal(t, e, &prop) - proposalutils.ExecuteMCMSProposalV2(t, e, p) + // return the error so devs can ensure expected reversions + err = proposalutils.ExecuteMCMSProposalV2(t, e, p) + if err != nil { + return deployment.Environment{}, err + } } } currentEnv = deployment.Environment{ diff --git a/deployment/common/proposalutils/mcms_test_helpers.go b/deployment/common/proposalutils/mcms_test_helpers.go index c49dddcc301..a3e3047fa2e 100644 --- a/deployment/common/proposalutils/mcms_test_helpers.go +++ b/deployment/common/proposalutils/mcms_test_helpers.go @@ -2,6 +2,7 @@ package proposalutils import ( "crypto/ecdsa" + "fmt" "math/big" "testing" "time" @@ -182,7 +183,7 @@ func SignMCMSProposal(t *testing.T, env deployment.Environment, proposal *mcmsli } // ExecuteMCMSProposalV2 - Executes an MCMS proposal on a chain. For timelock proposal, use ExecuteMCMSTimelockProposalV2 instead. -func ExecuteMCMSProposalV2(t *testing.T, env deployment.Environment, proposal *mcmslib.Proposal) { +func ExecuteMCMSProposalV2(t *testing.T, env deployment.Environment, proposal *mcmslib.Proposal) error { t.Log("Executing proposal") encoders, err := proposal.GetEncoders() @@ -226,7 +227,9 @@ func ExecuteMCMSProposalV2(t *testing.T, env deployment.Environment, proposal *m for chainSelector := range executorsMap { t.Logf("[ExecuteMCMSProposalV2] Setting root on chain %d...", chainSelector) root, err := executable.SetRoot(env.GetContext(), chainSelector) - require.NoError(t, deployment.MaybeDataErr(err), "[ExecuteMCMSProposalV2] SetRoot failed") + if err != nil { + return fmt.Errorf("[ExecuteMCMSProposalV2] SetRoot failed: %w", err) + } family, err := chainsel.GetSelectorFamily(uint64(chainSelector)) require.NoError(t, err) @@ -237,7 +240,9 @@ func ExecuteMCMSProposalV2(t *testing.T, env deployment.Environment, proposal *m evmTransaction := root.RawTransaction.(*gethtypes.Transaction) t.Logf("[ExecuteMCMSProposalV2] SetRoot EVM tx hash: %s", evmTransaction.Hash().String()) _, err = chain.Confirm(evmTransaction) - require.NoError(t, err) + if err != nil { + return fmt.Errorf("[ExecuteMCMSProposalV2] Confirm failed: %w", err) + } } } @@ -245,7 +250,9 @@ func ExecuteMCMSProposalV2(t *testing.T, env deployment.Environment, proposal *m for i, op := range proposal.Operations { t.Logf("[ExecuteMCMSProposalV2] Executing operation index=%d on chain %d...", i, uint64(op.ChainSelector)) result, err := executable.Execute(env.GetContext(), i) - require.NoError(t, err) + if err != nil { + return fmt.Errorf("[ExecuteMCMSProposalV2] Execute failed: %w", err) + } family, err := chainsel.GetSelectorFamily(uint64(op.ChainSelector)) require.NoError(t, err) @@ -255,14 +262,18 @@ func ExecuteMCMSProposalV2(t *testing.T, env deployment.Environment, proposal *m evmTransaction := result.RawTransaction.(*gethtypes.Transaction) t.Logf("[ExecuteMCMSProposalV2] Operation %d EVM tx hash: %s", i, evmTransaction.Hash().String()) _, err = chain.Confirm(evmTransaction) - require.NoError(t, err) + if err != nil { + return fmt.Errorf("[ExecuteMCMSProposalV2] Confirm failed: %w", err) + } } } + + return nil } // ExecuteMCMSTimelockProposalV2 - Includes an option to set callProxy to execute the calls through a proxy. // If the callProxy is not set, the calls will be executed directly to the timelock. -func ExecuteMCMSTimelockProposalV2(t *testing.T, env deployment.Environment, timelockProposal *mcmslib.TimelockProposal, opts ...mcmslib.Option) { +func ExecuteMCMSTimelockProposalV2(t *testing.T, env deployment.Environment, timelockProposal *mcmslib.TimelockProposal, opts ...mcmslib.Option) error { t.Log("Executing timelock proposal") // build a "chainSelector => executor" map @@ -296,7 +307,9 @@ func ExecuteMCMSTimelockProposalV2(t *testing.T, env deployment.Environment, tim var tx = mcmstypes.TransactionResult{} for i, op := range timelockProposal.Operations { tx, err = timelockExecutable.Execute(env.GetContext(), i, opts...) - require.NoError(t, err) + if err != nil { + return fmt.Errorf("[ExecuteMCMSTimelockProposalV2] Execute failed: %w", err) + } family, err := chainsel.GetSelectorFamily(uint64(op.ChainSelector)) require.NoError(t, err) @@ -306,9 +319,13 @@ func ExecuteMCMSTimelockProposalV2(t *testing.T, env deployment.Environment, tim chain := env.Chains[uint64(op.ChainSelector)] evmTransaction := tx.RawTransaction.(*gethtypes.Transaction) _, err = chain.Confirm(evmTransaction) - require.NoError(t, err) + if err != nil { + return fmt.Errorf("[ExecuteMCMSTimelockProposalV2] Confirm failed: %w", err) + } } } + + return nil } func SingleGroupTimelockConfig(t *testing.T) commontypes.MCMSWithTimelockConfig { diff --git a/deployment/keystone/changeset/add_capabilities.go b/deployment/keystone/changeset/add_capabilities.go index 7f9639ff870..cb792939858 100644 --- a/deployment/keystone/changeset/add_capabilities.go +++ b/deployment/keystone/changeset/add_capabilities.go @@ -4,9 +4,9 @@ import ( "errors" "fmt" - gethcommon "github.com/ethereum/go-ethereum/common" - "github.com/smartcontractkit/ccip-owner-contracts/pkg/gethwrappers" - "github.com/smartcontractkit/ccip-owner-contracts/pkg/proposal/timelock" + "github.com/smartcontractkit/mcms" + mcmssdk "github.com/smartcontractkit/mcms/sdk" + mcmstypes "github.com/smartcontractkit/mcms/types" kcr "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/keystone/generated/capabilities_registry_1_1_0" @@ -58,24 +58,33 @@ func AddCapabilities(env deployment.Environment, req *AddCapabilitiesRequest) (d if ops == nil { return out, errors.New("expected MCMS operation to be non-nil") } - timelocksPerChain := map[uint64]gethcommon.Address{ - registryChain.Selector: contractSet.Timelock.Address(), + timelocksPerChain := map[uint64]string{ + registryChain.Selector: contractSet.Timelock.Address().Hex(), } - proposerMCMSes := map[uint64]*gethwrappers.ManyChainMultiSig{ - registryChain.Selector: contractSet.ProposerMcm, + proposerMCMSes := map[uint64]string{ + registryChain.Selector: contractSet.ProposerMcm.Address().Hex(), + } + inspector, err := proposalutils.McmsInspectorForChain(env, req.RegistryChainSel) + if err != nil { + return deployment.ChangesetOutput{}, err + } + inspectorPerChain := map[uint64]mcmssdk.Inspector{ + req.RegistryChainSel: inspector, } - proposal, err := proposalutils.BuildProposalFromBatches( + proposal, err := proposalutils.BuildProposalFromBatchesV2( + env.GetContext(), timelocksPerChain, proposerMCMSes, - []timelock.BatchChainOperation{*ops}, + inspectorPerChain, + []mcmstypes.BatchOperation{*ops}, "proposal to add capabilities", req.MCMSConfig.MinDuration, ) if err != nil { return out, fmt.Errorf("failed to build proposal: %w", err) } - out.Proposals = []timelock.MCMSWithTimelockProposal{*proposal} + out.MCMSTimelockProposals = []mcms.TimelockProposal{*proposal} } return out, nil } diff --git a/deployment/keystone/changeset/add_capabilities_test.go b/deployment/keystone/changeset/add_capabilities_test.go index 7175a29f86f..b9aad9e310a 100644 --- a/deployment/keystone/changeset/add_capabilities_test.go +++ b/deployment/keystone/changeset/add_capabilities_test.go @@ -63,7 +63,7 @@ func TestAddCapabilities(t *testing.T) { } csOut, err := changeset.AddCapabilities(te.Env, req) require.NoError(t, err) - require.Len(t, csOut.Proposals, 1) + require.Len(t, csOut.MCMSTimelockProposals, 1) require.Nil(t, csOut.AddressBook) // now apply the changeset such that the proposal is signed and execed diff --git a/deployment/keystone/changeset/add_nodes.go b/deployment/keystone/changeset/add_nodes.go index 1166b5fff27..b5bd7448026 100644 --- a/deployment/keystone/changeset/add_nodes.go +++ b/deployment/keystone/changeset/add_nodes.go @@ -4,9 +4,9 @@ import ( "errors" "fmt" - gethcommon "github.com/ethereum/go-ethereum/common" - "github.com/smartcontractkit/ccip-owner-contracts/pkg/gethwrappers" - "github.com/smartcontractkit/ccip-owner-contracts/pkg/proposal/timelock" + "github.com/smartcontractkit/mcms" + mcmssdk "github.com/smartcontractkit/mcms/sdk" + "github.com/smartcontractkit/mcms/types" "github.com/smartcontractkit/chainlink/deployment" "github.com/smartcontractkit/chainlink/deployment/common/proposalutils" @@ -236,20 +236,29 @@ func AddNodes(env deployment.Environment, req *AddNodesRequest) (deployment.Chan // create mcms proposal if needed out := deployment.ChangesetOutput{} if useMCMS { - if resp.Ops == nil || len(resp.Ops.Batch) == 0 { + if resp.Ops == nil || len(resp.Ops.Transactions) == 0 { return out, errors.New("expected MCMS operation to be non-nil") } - timelocksPerChain := map[uint64]gethcommon.Address{ - registryChain.Selector: registryChainContracts.Timelock.Address(), + timelocksPerChain := map[uint64]string{ + registryChain.Selector: registryChainContracts.Timelock.Address().Hex(), } - proposerMCMSes := map[uint64]*gethwrappers.ManyChainMultiSig{ - registryChain.Selector: registryChainContracts.ProposerMcm, + proposerMCMSes := map[uint64]string{ + registryChain.Selector: registryChainContracts.ProposerMcm.Address().Hex(), + } + inspector, err := proposalutils.McmsInspectorForChain(env, req.RegistryChainSel) + if err != nil { + return deployment.ChangesetOutput{}, err + } + inspectorPerChain := map[uint64]mcmssdk.Inspector{ + req.RegistryChainSel: inspector, } - proposal, err := proposalutils.BuildProposalFromBatches( + proposal, err := proposalutils.BuildProposalFromBatchesV2( + env.GetContext(), timelocksPerChain, proposerMCMSes, - []timelock.BatchChainOperation{*resp.Ops}, + inspectorPerChain, + []types.BatchOperation{*resp.Ops}, "proposal to add nodes", req.MCMSConfig.MinDuration, ) @@ -257,7 +266,7 @@ func AddNodes(env deployment.Environment, req *AddNodesRequest) (deployment.Chan return out, fmt.Errorf("failed to build proposal: %w", err) } - out.Proposals = []timelock.MCMSWithTimelockProposal{*proposal} //nolint:staticcheck //SA1019 ignoring deprecated field for compatibility; we don't have tools to generate the new field + out.MCMSTimelockProposals = []mcms.TimelockProposal{*proposal} } return out, nil } diff --git a/deployment/keystone/changeset/add_nodes_test.go b/deployment/keystone/changeset/add_nodes_test.go index 75bf8eeacf6..f7a9e120567 100644 --- a/deployment/keystone/changeset/add_nodes_test.go +++ b/deployment/keystone/changeset/add_nodes_test.go @@ -266,8 +266,8 @@ func TestAddNodes(t *testing.T) { tc.checkErr(t, useMCMS, err) return } - require.NotNil(t, r.Proposals) //nolint:staticcheck //SA1019 ignoring deprecated field for compatibility; we don't have tools to generate the new field - require.Len(t, r.Proposals, 1) //nolint:staticcheck //SA1019 ignoring deprecated field for compatibility; we don't have tools to generate the new field + require.NotNil(t, r.MCMSTimelockProposals) + require.Len(t, r.MCMSTimelockProposals, 1) applyErr := applyProposal( t, tc.input.te, diff --git a/deployment/keystone/changeset/append_node_capabilities.go b/deployment/keystone/changeset/append_node_capabilities.go index 826ba4601f7..fcd20b856ad 100644 --- a/deployment/keystone/changeset/append_node_capabilities.go +++ b/deployment/keystone/changeset/append_node_capabilities.go @@ -4,9 +4,9 @@ import ( "errors" "fmt" - "github.com/ethereum/go-ethereum/common" - "github.com/smartcontractkit/ccip-owner-contracts/pkg/gethwrappers" - "github.com/smartcontractkit/ccip-owner-contracts/pkg/proposal/timelock" + "github.com/smartcontractkit/mcms" + "github.com/smartcontractkit/mcms/sdk" + "github.com/smartcontractkit/mcms/types" "github.com/smartcontractkit/chainlink/deployment" "github.com/smartcontractkit/chainlink/deployment/common/proposalutils" @@ -34,24 +34,33 @@ func AppendNodeCapabilities(env deployment.Environment, req *AppendNodeCapabilit if r.Ops == nil { return out, errors.New("expected MCMS operation to be non-nil") } - timelocksPerChain := map[uint64]common.Address{ - c.Chain.Selector: contractSet.Timelock.Address(), + timelocksPerChain := map[uint64]string{ + c.Chain.Selector: contractSet.Timelock.Address().Hex(), } - proposerMCMSes := map[uint64]*gethwrappers.ManyChainMultiSig{ - c.Chain.Selector: contractSet.ProposerMcm, + proposerMCMSes := map[uint64]string{ + c.Chain.Selector: contractSet.ProposerMcm.Address().Hex(), + } + inspector, err := proposalutils.McmsInspectorForChain(env, req.RegistryChainSel) + if err != nil { + return deployment.ChangesetOutput{}, err + } + inspectorPerChain := map[uint64]sdk.Inspector{ + req.RegistryChainSel: inspector, } - proposal, err := proposalutils.BuildProposalFromBatches( + proposal, err := proposalutils.BuildProposalFromBatchesV2( + env.GetContext(), timelocksPerChain, proposerMCMSes, - []timelock.BatchChainOperation{*r.Ops}, + inspectorPerChain, + []types.BatchOperation{*r.Ops}, "proposal to set update node capabilities", req.MCMSConfig.MinDuration, ) if err != nil { return out, fmt.Errorf("failed to build proposal: %w", err) } - out.Proposals = []timelock.MCMSWithTimelockProposal{*proposal} + out.MCMSTimelockProposals = []mcms.TimelockProposal{*proposal} } return out, nil } diff --git a/deployment/keystone/changeset/append_node_capabilities_test.go b/deployment/keystone/changeset/append_node_capabilities_test.go index 3952b0ef158..1c307aa949c 100644 --- a/deployment/keystone/changeset/append_node_capabilities_test.go +++ b/deployment/keystone/changeset/append_node_capabilities_test.go @@ -50,7 +50,7 @@ func TestAppendNodeCapabilities(t *testing.T) { csOut, err := changeset.AppendNodeCapabilities(te.Env, &cfg) require.NoError(t, err) - require.Empty(t, csOut.Proposals) + require.Empty(t, csOut.MCMSTimelockProposals) require.Nil(t, csOut.AddressBook) validateCapabilityAppends(t, te, newCapabilities) @@ -78,9 +78,9 @@ func TestAppendNodeCapabilities(t *testing.T) { csOut, err := changeset.AppendNodeCapabilities(te.Env, &cfg) require.NoError(t, err) - require.Len(t, csOut.Proposals, 1) - require.Len(t, csOut.Proposals[0].Transactions, 1) - require.Len(t, csOut.Proposals[0].Transactions[0].Batch, 2) // add capabilities, update nodes + require.Len(t, csOut.MCMSTimelockProposals, 1) + require.Len(t, csOut.MCMSTimelockProposals[0].Operations, 1) + require.Len(t, csOut.MCMSTimelockProposals[0].Operations[0].Transactions, 2) // add capabilities, update nodes require.Nil(t, csOut.AddressBook) // now apply the changeset such that the proposal is signed and execed diff --git a/deployment/keystone/changeset/deploy_ocr3.go b/deployment/keystone/changeset/deploy_ocr3.go index 75f9b75ecd1..c9da8b81237 100644 --- a/deployment/keystone/changeset/deploy_ocr3.go +++ b/deployment/keystone/changeset/deploy_ocr3.go @@ -7,9 +7,9 @@ import ( "io" "github.com/ethereum/go-ethereum/common" - - "github.com/smartcontractkit/ccip-owner-contracts/pkg/gethwrappers" - "github.com/smartcontractkit/ccip-owner-contracts/pkg/proposal/timelock" + "github.com/smartcontractkit/mcms" + "github.com/smartcontractkit/mcms/sdk" + mcmstypes "github.com/smartcontractkit/mcms/types" "github.com/smartcontractkit/chainlink/deployment" "github.com/smartcontractkit/chainlink/deployment/common/proposalutils" @@ -92,24 +92,33 @@ func ConfigureOCR3Contract(env deployment.Environment, cfg ConfigureOCR3Config) return out, fmt.Errorf("failed to get contract sets: %w", err) } contracts := r.ContractSets[cfg.ChainSel] - timelocksPerChain := map[uint64]common.Address{ - cfg.ChainSel: contracts.Timelock.Address(), + timelocksPerChain := map[uint64]string{ + cfg.ChainSel: contracts.Timelock.Address().Hex(), } - proposerMCMSes := map[uint64]*gethwrappers.ManyChainMultiSig{ - cfg.ChainSel: contracts.ProposerMcm, + proposerMCMSes := map[uint64]string{ + cfg.ChainSel: contracts.ProposerMcm.Address().Hex(), } - proposal, err := proposalutils.BuildProposalFromBatches( + inspector, err := proposalutils.McmsInspectorForChain(env, cfg.ChainSel) + if err != nil { + return deployment.ChangesetOutput{}, err + } + inspectorPerChain := map[uint64]sdk.Inspector{ + cfg.ChainSel: inspector, + } + proposal, err := proposalutils.BuildProposalFromBatchesV2( + env.GetContext(), timelocksPerChain, proposerMCMSes, - []timelock.BatchChainOperation{*resp.Ops}, + inspectorPerChain, + []mcmstypes.BatchOperation{*resp.Ops}, "proposal to set OCR3 config", cfg.MCMSConfig.MinDuration, ) if err != nil { return out, fmt.Errorf("failed to build proposal: %w", err) } - out.Proposals = []timelock.MCMSWithTimelockProposal{*proposal} + out.MCMSTimelockProposals = []mcms.TimelockProposal{*proposal} } return out, nil } diff --git a/deployment/keystone/changeset/deploy_ocr3_test.go b/deployment/keystone/changeset/deploy_ocr3_test.go index b8fa43e9076..b9d2d034997 100644 --- a/deployment/keystone/changeset/deploy_ocr3_test.go +++ b/deployment/keystone/changeset/deploy_ocr3_test.go @@ -11,6 +11,7 @@ import ( "go.uber.org/zap/zapcore" "github.com/smartcontractkit/chainlink-common/pkg/logger" + "github.com/smartcontractkit/chainlink/deployment" commonchangeset "github.com/smartcontractkit/chainlink/deployment/common/changeset" @@ -81,7 +82,7 @@ func TestConfigureOCR3(t *testing.T) { require.NoError(t, err) assert.Len(t, got.Signers, 4) assert.Len(t, got.Transmitters, 4) - assert.Nil(t, csOut.Proposals) + assert.Nil(t, csOut.MCMSTimelockProposals) }) t.Run("success multiple OCR3 contracts", func(t *testing.T) { @@ -146,7 +147,7 @@ func TestConfigureOCR3(t *testing.T) { require.NoError(t, err) assert.Len(t, got.Signers, 4) assert.Len(t, got.Transmitters, 4) - assert.Nil(t, csOut.Proposals) + assert.Nil(t, csOut.MCMSTimelockProposals) }) t.Run("fails multiple OCR3 contracts but unspecified address", func(t *testing.T) { @@ -258,8 +259,8 @@ func TestConfigureOCR3(t *testing.T) { require.NoError(t, err) assert.Len(t, got.Signers, 4) assert.Len(t, got.Transmitters, 4) - assert.NotNil(t, csOut.Proposals) - t.Logf("got: %v", csOut.Proposals[0]) + assert.NotNil(t, csOut.MCMSTimelockProposals) + t.Logf("got: %v", csOut.MCMSTimelockProposals[0]) contracts := te.ContractSets()[te.RegistrySelector] require.NoError(t, err) diff --git a/deployment/keystone/changeset/internal/capability_management.go b/deployment/keystone/changeset/internal/capability_management.go index 47f211fdcef..8f14dbc1b24 100644 --- a/deployment/keystone/changeset/internal/capability_management.go +++ b/deployment/keystone/changeset/internal/capability_management.go @@ -4,18 +4,19 @@ import ( "fmt" "math/big" - "github.com/smartcontractkit/ccip-owner-contracts/pkg/proposal/mcms" - "github.com/smartcontractkit/ccip-owner-contracts/pkg/proposal/timelock" + mcmstypes "github.com/smartcontractkit/mcms/types" "github.com/smartcontractkit/chainlink-common/pkg/logger" + "github.com/smartcontractkit/chainlink/deployment" + "github.com/smartcontractkit/chainlink/deployment/common/proposalutils" kcr "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/keystone/generated/capabilities_registry_1_1_0" ) // AddCapabilities adds the capabilities to the registry // // It is idempotent. It deduplicates the input capabilities. -func AddCapabilities(lggr logger.Logger, registry *kcr.CapabilitiesRegistry, chain deployment.Chain, capabilities []kcr.CapabilitiesRegistryCapability, useMCMS bool) (*timelock.BatchChainOperation, error) { +func AddCapabilities(lggr logger.Logger, registry *kcr.CapabilitiesRegistry, chain deployment.Chain, capabilities []kcr.CapabilitiesRegistryCapability, useMCMS bool) (*mcmstypes.BatchOperation, error) { if len(capabilities) == 0 { return nil, nil } @@ -43,23 +44,19 @@ func AddCapabilities(lggr logger.Logger, registry *kcr.CapabilitiesRegistry, cha return nil, nil } -func addCapabilitiesMCMSProposal(registry *kcr.CapabilitiesRegistry, caps []kcr.CapabilitiesRegistryCapability, regChain deployment.Chain) (*timelock.BatchChainOperation, error) { +func addCapabilitiesMCMSProposal(registry *kcr.CapabilitiesRegistry, caps []kcr.CapabilitiesRegistryCapability, regChain deployment.Chain) (*mcmstypes.BatchOperation, error) { tx, err := registry.AddCapabilities(deployment.SimTransactOpts(), caps) if err != nil { err = deployment.DecodeErr(kcr.CapabilitiesRegistryABI, err) return nil, fmt.Errorf("failed to call AddNodeOperators: %w", err) } - return &timelock.BatchChainOperation{ - ChainIdentifier: mcms.ChainIdentifier(regChain.Selector), - Batch: []mcms.Operation{ - { - To: registry.Address(), - Data: tx.Data(), - Value: big.NewInt(0), - }, - }, - }, nil + ops, err := proposalutils.BatchOperationForChain(regChain.Selector, registry.Address().Hex(), tx.Data(), big.NewInt(0), string(CapabilitiesRegistry), nil) + if err != nil { + return nil, fmt.Errorf("failed to create batch operation: %w", err) + } + + return &ops, nil } // CapabilityID returns a unique id for the capability diff --git a/deployment/keystone/changeset/internal/deploy.go b/deployment/keystone/changeset/internal/deploy.go index 5abb33dc3a4..c8183182c3e 100644 --- a/deployment/keystone/changeset/internal/deploy.go +++ b/deployment/keystone/changeset/internal/deploy.go @@ -18,6 +18,7 @@ import ( "github.com/smartcontractkit/ccip-owner-contracts/pkg/proposal/mcms" "github.com/smartcontractkit/ccip-owner-contracts/pkg/proposal/timelock" chainsel "github.com/smartcontractkit/chain-selectors" + mcmstypes "github.com/smartcontractkit/mcms/types" "golang.org/x/exp/maps" "google.golang.org/protobuf/proto" @@ -25,6 +26,7 @@ import ( "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink/deployment" + "github.com/smartcontractkit/chainlink/deployment/common/proposalutils" capabilities_registry "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/keystone/generated/capabilities_registry_1_1_0" kf "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/keystone/generated/forwarder_1_0_0" ) @@ -337,7 +339,7 @@ func ConfigureOCR3Contract(env *deployment.Environment, chainSel uint64, dons [] type ConfigureOCR3Resp struct { OCR2OracleConfig - Ops *timelock.BatchChainOperation + Ops *mcmstypes.BatchOperation } type ConfigureOCR3Config struct { @@ -544,9 +546,10 @@ type RegisterNodesRequest struct { Nops []*capabilities_registry.CapabilitiesRegistryNodeOperatorAdded UseMCMS bool } + type RegisterNodesResponse struct { nodeIDToParams map[string]capabilities_registry.CapabilitiesRegistryNodeParams - Ops *timelock.BatchChainOperation + Ops *mcmstypes.BatchOperation } // registerNodes registers the nodes with the registry. it assumes that the deployer key in the Chain @@ -679,8 +682,9 @@ type AddNodesResponse struct { // It may be empty if no nodes were added AddedNodes []capabilities_registry.CapabilitiesRegistryNodeParams // Ops is only populated if UseMCMS is true - Ops *timelock.BatchChainOperation + Ops *mcmstypes.BatchOperation } + type AddNodesRequest struct { RegistryChain deployment.Chain CapabilitiesRegistry *capabilities_registry.CapabilitiesRegistry @@ -771,23 +775,19 @@ func getNodesToRegister( } // addNodesMCMSProposal generates a single call to AddNodes for all the node params at once. -func addNodesMCMSProposal(registry *capabilities_registry.CapabilitiesRegistry, params []capabilities_registry.CapabilitiesRegistryNodeParams, regChainSel uint64) (*timelock.BatchChainOperation, error) { +func addNodesMCMSProposal(registry *capabilities_registry.CapabilitiesRegistry, params []capabilities_registry.CapabilitiesRegistryNodeParams, regChainSel uint64) (*mcmstypes.BatchOperation, error) { tx, err := registry.AddNodes(deployment.SimTransactOpts(), params) if err != nil { err = deployment.DecodeErr(capabilities_registry.CapabilitiesRegistryABI, err) return nil, fmt.Errorf("failed to simulate call to AddNodes: %w", err) } - return &timelock.BatchChainOperation{ - ChainIdentifier: mcms.ChainIdentifier(regChainSel), - Batch: []mcms.Operation{ - { - To: registry.Address(), - Data: tx.Data(), - Value: big.NewInt(0), - }, - }, - }, nil + ops, err := proposalutils.BatchOperationForChain(regChainSel, registry.Address().Hex(), tx.Data(), big.NewInt(0), string(CapabilitiesRegistry), nil) + if err != nil { + return nil, fmt.Errorf("failed to create batch operation: %w", err) + } + + return &ops, nil } type DONToRegister struct { @@ -808,7 +808,7 @@ type RegisterDonsRequest struct { type RegisterDonsResponse struct { DonInfos map[string]capabilities_registry.CapabilitiesRegistryDONInfo - Ops *timelock.BatchChainOperation + Ops *mcmstypes.BatchOperation } func sortedHash(p2pids [][32]byte) string { @@ -844,7 +844,7 @@ func RegisterDons(lggr logger.Logger, req RegisterDonsRequest) (*RegisterDonsRes } lggr.Infow("fetched existing DONs...", "len", len(donInfos), "lenByNodesHash", len(existingDONs)) - mcmsOps := make([]mcms.Operation, 0) + mcmsOps := make([]mcmstypes.Transaction, 0) for _, don := range req.DonsToRegister { var p2pIds [][32]byte for _, n := range don.Nodes { @@ -905,10 +905,9 @@ func RegisterDons(lggr logger.Logger, req RegisterDonsRequest) (*RegisterDonsRes if req.UseMCMS { lggr.Debugw("adding mcms op for DON", "don", don.Name) - op := mcms.Operation{ - To: registry.Address(), - Data: tx.Data(), - Value: big.NewInt(0), + op, err := proposalutils.TransactionForChain(req.RegistryChainSelector, registry.Address().Hex(), tx.Data(), big.NewInt(0), "", nil) + if err != nil { + return nil, fmt.Errorf("failed to create transaction for chain %d: %w", req.RegistryChainSelector, err) } mcmsOps = append(mcmsOps, op) continue @@ -925,9 +924,9 @@ func RegisterDons(lggr logger.Logger, req RegisterDonsRequest) (*RegisterDonsRes if req.UseMCMS { if len(mcmsOps) > 0 { return &RegisterDonsResponse{ - Ops: &timelock.BatchChainOperation{ - ChainIdentifier: mcms.ChainIdentifier(registryChain.Selector), - Batch: mcmsOps, + Ops: &mcmstypes.BatchOperation{ + ChainSelector: mcmstypes.ChainSelector(registryChain.Selector), + Transactions: mcmsOps, }, }, nil } diff --git a/deployment/keystone/changeset/internal/deploy_test.go b/deployment/keystone/changeset/internal/deploy_test.go index 96fd0c3ef2a..41c1a793d4e 100644 --- a/deployment/keystone/changeset/internal/deploy_test.go +++ b/deployment/keystone/changeset/internal/deploy_test.go @@ -10,6 +10,7 @@ import ( "github.com/stretchr/testify/require" "github.com/smartcontractkit/chainlink-common/pkg/logger" + "github.com/smartcontractkit/chainlink/deployment" "github.com/smartcontractkit/chainlink/deployment/keystone/changeset/internal" kstest "github.com/smartcontractkit/chainlink/deployment/keystone/changeset/test" @@ -88,7 +89,7 @@ func Test_AddCapabilities(t *testing.T) { ops, err := internal.AddCapabilities(lggr, registry, chain, capabilities, useMCMS) require.NoError(t, err) require.NotNil(t, ops) - require.Len(t, ops.Batch, 1) + require.Len(t, ops.Transactions, 1) }) t.Run("does nothing if no capabilities", func(t *testing.T) { @@ -284,7 +285,7 @@ func Test_RegisterNodes(t *testing.T) { require.NoError(t, err) if tc.useMCMS { require.NotNil(t, resp.Ops) - require.Len(t, resp.Ops.Batch, tc.want.nOps) + require.Len(t, resp.Ops.Transactions, tc.want.nOps) } else { assertNodesExist(t, registry, tc.want.nodes...) } @@ -419,7 +420,7 @@ func Test_RegisterDons(t *testing.T) { }) require.NoError(t, err) require.NotNil(t, resp.Ops) - require.Len(t, resp.Ops.Batch, 1) + require.Len(t, resp.Ops.Transactions, 1) }) t.Run("no new dons to add results in no mcms ops", func(t *testing.T) { @@ -551,7 +552,7 @@ func Test_RegisterDons(t *testing.T) { }) require.NoError(t, err) require.NotNil(t, resp.Ops) - require.Len(t, resp.Ops.Batch, 2) + require.Len(t, resp.Ops.Transactions, 2) }) } diff --git a/deployment/keystone/changeset/internal/ocr3config.go b/deployment/keystone/changeset/internal/ocr3config.go index ef5bd9bda2e..e8038134f02 100644 --- a/deployment/keystone/changeset/internal/ocr3config.go +++ b/deployment/keystone/changeset/internal/ocr3config.go @@ -13,15 +13,14 @@ import ( "time" "github.com/ethereum/go-ethereum/common" + mcmstypes "github.com/smartcontractkit/mcms/types" "github.com/smartcontractkit/libocr/offchainreporting2plus/confighelper" "github.com/smartcontractkit/libocr/offchainreporting2plus/ocr3confighelper" "github.com/smartcontractkit/libocr/offchainreporting2plus/types" - "github.com/smartcontractkit/ccip-owner-contracts/pkg/proposal/mcms" - "github.com/smartcontractkit/ccip-owner-contracts/pkg/proposal/timelock" - "github.com/smartcontractkit/chainlink/deployment" + "github.com/smartcontractkit/chainlink/deployment/common/proposalutils" kocr3 "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/keystone/generated/ocr3_capability_1_0_0" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/chaintype" "github.com/smartcontractkit/chainlink/v2/core/services/ocrcommon" @@ -301,7 +300,7 @@ func (r configureOCR3Request) generateOCR3Config() (OCR2OracleConfig, error) { type configureOCR3Response struct { ocrConfig OCR2OracleConfig - ops *timelock.BatchChainOperation + ops *mcmstypes.BatchOperation } func configureOCR3contract(req configureOCR3Request) (*configureOCR3Response, error) { @@ -334,7 +333,7 @@ func configureOCR3contract(req configureOCR3Request) (*configureOCR3Response, er return nil, fmt.Errorf("failed to call SetConfig for OCR3 contract %s using mcms: %T: %w", req.contract.Address().String(), req.useMCMS, err) } - var ops *timelock.BatchChainOperation + var ops mcmstypes.BatchOperation if !req.useMCMS { _, err = req.chain.Confirm(tx) if err != nil { @@ -342,17 +341,11 @@ func configureOCR3contract(req configureOCR3Request) (*configureOCR3Response, er return nil, fmt.Errorf("failed to confirm SetConfig for OCR3 contract %s: %w", req.contract.Address().String(), err) } } else { - ops = &timelock.BatchChainOperation{ - ChainIdentifier: mcms.ChainIdentifier(req.chain.Selector), - Batch: []mcms.Operation{ - { - To: req.contract.Address(), - Data: tx.Data(), - Value: big.NewInt(0), - }, - }, + ops, err = proposalutils.BatchOperationForChain(req.chain.Selector, req.contract.Address().Hex(), tx.Data(), big.NewInt(0), string(OCR3Capability), nil) + if err != nil { + return nil, fmt.Errorf("failed to create batch operation: %w", err) } } - return &configureOCR3Response{ocrConfig, ops}, nil + return &configureOCR3Response{ocrConfig, &ops}, nil } diff --git a/deployment/keystone/changeset/internal/update_don.go b/deployment/keystone/changeset/internal/update_don.go index 92529a939dd..fb7702fc43f 100644 --- a/deployment/keystone/changeset/internal/update_don.go +++ b/deployment/keystone/changeset/internal/update_don.go @@ -11,13 +11,12 @@ import ( "sort" "github.com/ethereum/go-ethereum/accounts/abi/bind" - - "github.com/smartcontractkit/ccip-owner-contracts/pkg/proposal/mcms" - "github.com/smartcontractkit/ccip-owner-contracts/pkg/proposal/timelock" + "github.com/smartcontractkit/mcms/types" "github.com/smartcontractkit/chainlink-common/pkg/logger" "github.com/smartcontractkit/chainlink/deployment" + "github.com/smartcontractkit/chainlink/deployment/common/proposalutils" kcr "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/keystone/generated/capabilities_registry_1_1_0" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/p2pkey" ) @@ -68,7 +67,7 @@ func (r *UpdateDonRequest) Validate() error { type UpdateDonResponse struct { DonInfo kcr.CapabilitiesRegistryDONInfo - Ops *timelock.BatchChainOperation + Ops *types.BatchOperation } func UpdateDon(_ logger.Logger, req *UpdateDonRequest) (*UpdateDonResponse, error) { @@ -108,28 +107,22 @@ func UpdateDon(_ logger.Logger, req *UpdateDonRequest) (*UpdateDonResponse, erro err = deployment.DecodeErr(kcr.CapabilitiesRegistryABI, err) return nil, fmt.Errorf("failed to call UpdateDON: %w", err) } - var ops *timelock.BatchChainOperation + var ops types.BatchOperation if !req.UseMCMS { _, err = req.Chain.Confirm(tx) if err != nil { return nil, fmt.Errorf("failed to confirm UpdateDON transaction %s: %w", tx.Hash().String(), err) } } else { - ops = &timelock.BatchChainOperation{ - ChainIdentifier: mcms.ChainIdentifier(req.Chain.Selector), - Batch: []mcms.Operation{ - { - To: registry.Address(), - Data: tx.Data(), - Value: big.NewInt(0), - }, - }, + ops, err = proposalutils.BatchOperationForChain(req.Chain.Selector, registry.Address().Hex(), tx.Data(), big.NewInt(0), string(CapabilitiesRegistry), nil) + if err != nil { + return nil, fmt.Errorf("failed to create batch operation: %w", err) } } out := don out.CapabilityConfigurations = cfgs - return &UpdateDonResponse{DonInfo: out, Ops: ops}, nil + return &UpdateDonResponse{DonInfo: out, Ops: &ops}, nil } func PeerIDsToBytes(p2pIDs []p2pkey.PeerID) [][32]byte { diff --git a/deployment/keystone/changeset/internal/update_nodes.go b/deployment/keystone/changeset/internal/update_nodes.go index 4c33b3d08a3..2c496a13158 100644 --- a/deployment/keystone/changeset/internal/update_nodes.go +++ b/deployment/keystone/changeset/internal/update_nodes.go @@ -9,11 +9,11 @@ import ( "sort" "github.com/ethereum/go-ethereum/accounts/abi/bind" - - "github.com/smartcontractkit/ccip-owner-contracts/pkg/proposal/mcms" - "github.com/smartcontractkit/ccip-owner-contracts/pkg/proposal/timelock" + mcmstypes "github.com/smartcontractkit/mcms/types" "github.com/smartcontractkit/chainlink-common/pkg/logger" + + "github.com/smartcontractkit/chainlink/deployment/common/proposalutils" kcr "github.com/smartcontractkit/chainlink/v2/core/gethwrappers/keystone/generated/capabilities_registry_1_1_0" "github.com/smartcontractkit/chainlink/v2/core/services/keystore/keys/p2pkey" @@ -37,7 +37,7 @@ type UpdateNodesRequest struct { UseMCMS bool // If UseMCMS is true, and Ops is not nil then the UpdateNodes contract operation // will be added to the Ops.Batch - Ops *timelock.BatchChainOperation + Ops *mcmstypes.BatchOperation } func (req *UpdateNodesRequest) NodeParams() ([]kcr.CapabilitiesRegistryNodeParams, error) { @@ -90,7 +90,7 @@ type UpdateNodesResponse struct { NodeParams []kcr.CapabilitiesRegistryNodeParams // MCMS operation to update the nodes // The operation is added to the Batch of the given Ops if not nil - Ops *timelock.BatchChainOperation + Ops *mcmstypes.BatchOperation } // UpdateNodes updates the nodes in the registry @@ -124,21 +124,20 @@ func UpdateNodes(lggr logger.Logger, req *UpdateNodesRequest) (*UpdateNodesRespo return nil, fmt.Errorf("failed to confirm UpdateNodes confirm transaction %s: %w", tx.Hash().String(), err) } } else { - op := mcms.Operation{ - To: registry.Address(), - Data: tx.Data(), - Value: big.NewInt(0), + transaction, err := proposalutils.TransactionForChain(req.Chain.Selector, registry.Address().Hex(), tx.Data(), big.NewInt(0), "", nil) + if err != nil { + return nil, err } if ops == nil { - ops = &timelock.BatchChainOperation{ - ChainIdentifier: mcms.ChainIdentifier(req.Chain.Selector), - Batch: []mcms.Operation{ - op, + ops = &mcmstypes.BatchOperation{ + ChainSelector: mcmstypes.ChainSelector(req.Chain.Selector), + Transactions: []mcmstypes.Transaction{ + transaction, }, } } else { - ops.Batch = append(ops.Batch, op) + ops.Transactions = append(ops.Transactions, transaction) } } diff --git a/deployment/keystone/changeset/update_don.go b/deployment/keystone/changeset/update_don.go index 6f168bb55d6..7d02db0eda0 100644 --- a/deployment/keystone/changeset/update_don.go +++ b/deployment/keystone/changeset/update_don.go @@ -66,16 +66,16 @@ func UpdateDon(env deployment.Environment, req *UpdateDonRequest) (deployment.Ch if updateResult.Ops == nil { return out, errors.New("expected MCMS operation to be non-nil") } - if len(appendResult.Proposals) == 0 { + if len(appendResult.MCMSTimelockProposals) == 0 { return out, errors.New("expected append node capabilities to return proposals") } - out.Proposals = appendResult.Proposals + out.MCMSTimelockProposals = appendResult.MCMSTimelockProposals // add the update don to the existing batch // this makes the proposal all-or-nothing because all the operations are in the same batch, there is only one tr // transaction and only one proposal - out.Proposals[0].Transactions[0].Batch = append(out.Proposals[0].Transactions[0].Batch, updateResult.Ops.Batch...) + out.MCMSTimelockProposals[0].Operations[0].Transactions = append(out.MCMSTimelockProposals[0].Operations[0].Transactions, updateResult.Ops.Transactions...) } return out, nil } diff --git a/deployment/keystone/changeset/update_don_test.go b/deployment/keystone/changeset/update_don_test.go index ca037c45058..c567da56551 100644 --- a/deployment/keystone/changeset/update_don_test.go +++ b/deployment/keystone/changeset/update_don_test.go @@ -129,8 +129,8 @@ func TestUpdateDon(t *testing.T) { tc.checkErr(t, useMCMS, err) return } - require.NotNil(t, csOut.Proposals) //nolint:staticcheck //SA1019 ignoring deprecated field for compatibility; we don't have tools to generate the new field - require.Len(t, csOut.Proposals, 1) //nolint:staticcheck //SA1019 ignoring deprecated field for compatibility; we don't have tools to generate the new field + require.NotNil(t, csOut.MCMSTimelockProposals) + require.Len(t, csOut.MCMSTimelockProposals, 1) applyErr := applyProposal(t, te, commonchangeset.Configure( deployment.CreateLegacyChangeSet(changeset.UpdateDon), &cfg, diff --git a/deployment/keystone/changeset/update_node_capabilities.go b/deployment/keystone/changeset/update_node_capabilities.go index bf869416604..38cd8b6dfb5 100644 --- a/deployment/keystone/changeset/update_node_capabilities.go +++ b/deployment/keystone/changeset/update_node_capabilities.go @@ -5,11 +5,10 @@ import ( "fmt" "strconv" - "github.com/ethereum/go-ethereum/common" chainsel "github.com/smartcontractkit/chain-selectors" - - "github.com/smartcontractkit/ccip-owner-contracts/pkg/gethwrappers" - "github.com/smartcontractkit/ccip-owner-contracts/pkg/proposal/timelock" + "github.com/smartcontractkit/mcms" + mcmssdk "github.com/smartcontractkit/mcms/sdk" + "github.com/smartcontractkit/mcms/types" "github.com/smartcontractkit/chainlink/deployment" "github.com/smartcontractkit/chainlink/deployment/common/proposalutils" @@ -123,24 +122,32 @@ func UpdateNodeCapabilities(env deployment.Environment, req *UpdateNodeCapabilit if r.Ops == nil { return out, errors.New("expected MCMS operation to be non-nil") } - timelocksPerChain := map[uint64]common.Address{ - c.Chain.Selector: contractSet.Timelock.Address(), + timelocksPerChain := map[uint64]string{ + c.Chain.Selector: contractSet.Timelock.Address().Hex(), } - proposerMCMSes := map[uint64]*gethwrappers.ManyChainMultiSig{ - c.Chain.Selector: contractSet.ProposerMcm, + proposerMCMSes := map[uint64]string{ + c.Chain.Selector: contractSet.ProposerMcm.Address().Hex(), } - - proposal, err := proposalutils.BuildProposalFromBatches( + inspector, err := proposalutils.McmsInspectorForChain(env, req.RegistryChainSel) + if err != nil { + return deployment.ChangesetOutput{}, err + } + inspectorPerChain := map[uint64]mcmssdk.Inspector{ + req.RegistryChainSel: inspector, + } + proposal, err := proposalutils.BuildProposalFromBatchesV2( + env.GetContext(), timelocksPerChain, proposerMCMSes, - []timelock.BatchChainOperation{*r.Ops}, + inspectorPerChain, + []types.BatchOperation{*r.Ops}, "proposal to set update node capabilities", req.MCMSConfig.MinDuration, ) if err != nil { return out, fmt.Errorf("failed to build proposal: %w", err) } - out.Proposals = []timelock.MCMSWithTimelockProposal{*proposal} + out.MCMSTimelockProposals = []mcms.TimelockProposal{*proposal} } return out, nil } diff --git a/deployment/keystone/changeset/update_node_capabilities_test.go b/deployment/keystone/changeset/update_node_capabilities_test.go index b96f32f716d..60b5508ff18 100644 --- a/deployment/keystone/changeset/update_node_capabilities_test.go +++ b/deployment/keystone/changeset/update_node_capabilities_test.go @@ -69,7 +69,7 @@ func TestUpdateNodeCapabilities(t *testing.T) { csOut, err := changeset.UpdateNodeCapabilities(te.Env, &cfg) require.NoError(t, err) - require.Empty(t, csOut.Proposals) + require.Empty(t, csOut.MCMSTimelockProposals) require.Nil(t, csOut.AddressBook) validateCapabilityUpdates(t, te, capabiltiesToSet) @@ -106,9 +106,9 @@ func TestUpdateNodeCapabilities(t *testing.T) { csOut, err := changeset.UpdateNodeCapabilities(te.Env, &cfg) require.NoError(t, err) - require.Len(t, csOut.Proposals, 1) - require.Len(t, csOut.Proposals[0].Transactions, 1) - require.Len(t, csOut.Proposals[0].Transactions[0].Batch, 2) // add capabilities, update nodes + require.Len(t, csOut.MCMSTimelockProposals, 1) + require.Len(t, csOut.MCMSTimelockProposals[0].Operations, 1) + require.Len(t, csOut.MCMSTimelockProposals[0].Operations[0].Transactions, 2) // add capabilities, update nodes require.Nil(t, csOut.AddressBook) // now apply the changeset such that the proposal is signed and execed diff --git a/deployment/keystone/changeset/update_nodes.go b/deployment/keystone/changeset/update_nodes.go index cc7c1c08eb7..a09a2b86ced 100644 --- a/deployment/keystone/changeset/update_nodes.go +++ b/deployment/keystone/changeset/update_nodes.go @@ -5,10 +5,10 @@ import ( "fmt" "time" - "github.com/ethereum/go-ethereum/common" - "github.com/smartcontractkit/ccip-owner-contracts/pkg/gethwrappers" - "github.com/smartcontractkit/ccip-owner-contracts/pkg/proposal/timelock" chainsel "github.com/smartcontractkit/chain-selectors" + "github.com/smartcontractkit/mcms" + "github.com/smartcontractkit/mcms/sdk" + "github.com/smartcontractkit/mcms/types" "github.com/smartcontractkit/chainlink/deployment" "github.com/smartcontractkit/chainlink/deployment/common/proposalutils" @@ -55,7 +55,7 @@ func (r UpdateNodesRequest) UseMCMS() bool { type NodeUpdate = internal.NodeUpdate -// UpdateNodes updates the a set of nodes. +// UpdateNodes updates a set of nodes. // The nodes and capabilities in the request must already exist in the registry contract. func UpdateNodes(env deployment.Environment, req *UpdateNodesRequest) (deployment.ChangesetOutput, error) { // extract the registry contract and chain from the environment @@ -90,24 +90,33 @@ func UpdateNodes(env deployment.Environment, req *UpdateNodesRequest) (deploymen if resp.Ops == nil { return out, errors.New("expected MCMS operation to be non-nil") } - timelocksPerChain := map[uint64]common.Address{ - req.RegistryChainSel: contracts.Timelock.Address(), + timelocksPerChain := map[uint64]string{ + req.RegistryChainSel: contracts.Timelock.Address().Hex(), } - proposerMCMSes := map[uint64]*gethwrappers.ManyChainMultiSig{ - req.RegistryChainSel: contracts.ProposerMcm, + proposerMCMSes := map[uint64]string{ + req.RegistryChainSel: contracts.ProposerMcm.Address().Hex(), + } + inspector, err := proposalutils.McmsInspectorForChain(env, req.RegistryChainSel) + if err != nil { + return deployment.ChangesetOutput{}, err + } + inspectorPerChain := map[uint64]sdk.Inspector{ + req.RegistryChainSel: inspector, } - proposal, err := proposalutils.BuildProposalFromBatches( + proposal, err := proposalutils.BuildProposalFromBatchesV2( + env.GetContext(), timelocksPerChain, proposerMCMSes, - []timelock.BatchChainOperation{*resp.Ops}, + inspectorPerChain, + []types.BatchOperation{*resp.Ops}, "proposal to set update nodes", req.MCMSConfig.MinDuration, ) if err != nil { return out, fmt.Errorf("failed to build proposal: %w", err) } - out.Proposals = []timelock.MCMSWithTimelockProposal{*proposal} + out.MCMSTimelockProposals = []mcms.TimelockProposal{*proposal} } return out, nil diff --git a/deployment/keystone/changeset/update_nodes_test.go b/deployment/keystone/changeset/update_nodes_test.go index aa921821b84..1117bd8da65 100644 --- a/deployment/keystone/changeset/update_nodes_test.go +++ b/deployment/keystone/changeset/update_nodes_test.go @@ -82,7 +82,7 @@ func TestUpdateNodes(t *testing.T) { csOut, err := changeset.UpdateNodes(te.Env, &cfg) require.NoError(t, err) - require.Len(t, csOut.Proposals, 1) + require.Len(t, csOut.MCMSTimelockProposals, 1) require.Nil(t, csOut.AddressBook) // now apply the changeset such that the proposal is signed and execed diff --git a/deployment/keystone/changeset/workflowregistry/strategies.go b/deployment/keystone/changeset/workflowregistry/strategies.go index 617d6e6e8dc..22acf46c9cb 100644 --- a/deployment/keystone/changeset/workflowregistry/strategies.go +++ b/deployment/keystone/changeset/workflowregistry/strategies.go @@ -6,10 +6,9 @@ import ( "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" - - "github.com/smartcontractkit/ccip-owner-contracts/pkg/gethwrappers" - "github.com/smartcontractkit/ccip-owner-contracts/pkg/proposal/mcms" - "github.com/smartcontractkit/ccip-owner-contracts/pkg/proposal/timelock" + mcmslib "github.com/smartcontractkit/mcms" + "github.com/smartcontractkit/mcms/sdk" + mcmstypes "github.com/smartcontractkit/mcms/types" "github.com/smartcontractkit/chainlink/deployment" "github.com/smartcontractkit/chainlink/deployment/common/proposalutils" @@ -40,6 +39,7 @@ type mcmsTransaction struct { Address common.Address ChainSel uint64 ContractSet *changeset.ContractSet + Env deployment.Environment } func (m *mcmsTransaction) Apply(callFn func(opts *bind.TransactOpts) (*types.Transaction, error)) (deployment.ChangesetOutput, error) { @@ -50,28 +50,35 @@ func (m *mcmsTransaction) Apply(callFn func(opts *bind.TransactOpts) (*types.Tra return deployment.ChangesetOutput{}, err } - op := timelock.BatchChainOperation{ - ChainIdentifier: mcms.ChainIdentifier(m.ChainSel), - Batch: []mcms.Operation{ - { - Data: tx.Data(), - To: m.Address, - Value: big.NewInt(0), - }, - }, + transaction, err := proposalutils.TransactionForChain(m.ChainSel, m.Address.Hex(), tx.Data(), big.NewInt(0), "", nil) + if err != nil { + return deployment.ChangesetOutput{}, err + } + op := mcmstypes.BatchOperation{ + ChainSelector: mcmstypes.ChainSelector(m.ChainSel), + Transactions: []mcmstypes.Transaction{transaction}, } - timelocksPerChain := map[uint64]common.Address{ - m.ChainSel: m.ContractSet.Timelock.Address(), + timelocksPerChain := map[uint64]string{ + m.ChainSel: m.ContractSet.Timelock.Address().Hex(), + } + proposerMCMSes := map[uint64]string{ + m.ChainSel: m.ContractSet.ProposerMcm.Address().Hex(), + } + inspector, err := proposalutils.McmsInspectorForChain(m.Env, m.ChainSel) + if err != nil { + return deployment.ChangesetOutput{}, err } - proposerMCMSes := map[uint64]*gethwrappers.ManyChainMultiSig{ - m.ChainSel: m.ContractSet.ProposerMcm, + inspectorPerChain := map[uint64]sdk.Inspector{ + m.ChainSel: inspector, } - proposal, err := proposalutils.BuildProposalFromBatches( + proposal, err := proposalutils.BuildProposalFromBatchesV2( + m.Env.GetContext(), timelocksPerChain, proposerMCMSes, - []timelock.BatchChainOperation{op}, + inspectorPerChain, + []mcmstypes.BatchOperation{op}, m.Description, m.Config.MinDuration, ) @@ -80,6 +87,6 @@ func (m *mcmsTransaction) Apply(callFn func(opts *bind.TransactOpts) (*types.Tra } return deployment.ChangesetOutput{ - Proposals: []timelock.MCMSWithTimelockProposal{*proposal}, + MCMSTimelockProposals: []mcmslib.TimelockProposal{*proposal}, }, nil } diff --git a/deployment/keystone/changeset/workflowregistry/update_allowed_dons.go b/deployment/keystone/changeset/workflowregistry/update_allowed_dons.go index 5001370b552..8295a140f87 100644 --- a/deployment/keystone/changeset/workflowregistry/update_allowed_dons.go +++ b/deployment/keystone/changeset/workflowregistry/update_allowed_dons.go @@ -63,6 +63,7 @@ func UpdateAllowedDons(env deployment.Environment, req *UpdateAllowedDonsRequest Address: registry.Address(), ChainSel: req.RegistryChainSel, ContractSet: &cs, + Env: env, } } else { s = &simpleTransaction{ diff --git a/deployment/keystone/changeset/workflowregistry/update_allowed_dons_test.go b/deployment/keystone/changeset/workflowregistry/update_allowed_dons_test.go index dfac7e418a3..15231780478 100644 --- a/deployment/keystone/changeset/workflowregistry/update_allowed_dons_test.go +++ b/deployment/keystone/changeset/workflowregistry/update_allowed_dons_test.go @@ -89,7 +89,7 @@ func Test_UpdateAllowedDons_WithMCMS(t *testing.T) { out, err := workflowregistry.UpdateAllowedDons(te.Env, req) require.NoError(t, err) - require.Len(t, out.Proposals, 1) + require.Len(t, out.MCMSTimelockProposals, 1) require.Nil(t, out.AddressBook) contracts := te.ContractSets()[te.RegistrySelector] diff --git a/deployment/keystone/changeset/workflowregistry/update_authorized_addresses.go b/deployment/keystone/changeset/workflowregistry/update_authorized_addresses.go index b2d5ffcce1e..bfab247a165 100644 --- a/deployment/keystone/changeset/workflowregistry/update_authorized_addresses.go +++ b/deployment/keystone/changeset/workflowregistry/update_authorized_addresses.go @@ -88,6 +88,7 @@ func UpdateAuthorizedAddresses(env deployment.Environment, req *UpdateAuthorized Address: registry.Address(), ChainSel: chain.Selector, ContractSet: &cs, + Env: env, } } else { s = &simpleTransaction{ diff --git a/deployment/keystone/changeset/workflowregistry/update_authorized_addresses_test.go b/deployment/keystone/changeset/workflowregistry/update_authorized_addresses_test.go index 694e59811bd..41a4064c82a 100644 --- a/deployment/keystone/changeset/workflowregistry/update_authorized_addresses_test.go +++ b/deployment/keystone/changeset/workflowregistry/update_authorized_addresses_test.go @@ -92,7 +92,7 @@ func Test_UpdateAuthorizedAddresses_WithMCMS(t *testing.T) { out, err := workflowregistry.UpdateAuthorizedAddresses(te.Env, req) require.NoError(t, err) - require.Len(t, out.Proposals, 1) + require.Len(t, out.MCMSTimelockProposals, 1) require.Nil(t, out.AddressBook) contracts := te.ContractSets()[te.RegistrySelector]