Skip to content

Commit

Permalink
fix(mcms): update keystones changesets to new MCMS
Browse files Browse the repository at this point in the history
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
  • Loading branch information
graham-chainlink committed Feb 18, 2025
1 parent d96c444 commit 3c8d951
Show file tree
Hide file tree
Showing 27 changed files with 275 additions and 203 deletions.
17 changes: 14 additions & 3 deletions deployment/common/changeset/test_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -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{
Expand Down
33 changes: 25 additions & 8 deletions deployment/common/proposalutils/mcms_test_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package proposalutils

import (
"crypto/ecdsa"
"fmt"
"math/big"
"testing"
"time"
Expand Down Expand Up @@ -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()
Expand Down Expand Up @@ -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)
Expand All @@ -237,15 +240,19 @@ 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)
}
}
}

// execute each operation sequentially
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)
Expand All @@ -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
Expand Down Expand Up @@ -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)
Expand All @@ -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 {
Expand Down
29 changes: 19 additions & 10 deletions deployment/keystone/changeset/add_capabilities.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand Down Expand Up @@ -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
}
2 changes: 1 addition & 1 deletion deployment/keystone/changeset/add_capabilities_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
31 changes: 20 additions & 11 deletions deployment/keystone/changeset/add_nodes.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -236,28 +236,37 @@ 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,
)
if err != nil {
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
}
4 changes: 2 additions & 2 deletions deployment/keystone/changeset/add_nodes_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
29 changes: 19 additions & 10 deletions deployment/keystone/changeset/append_node_capabilities.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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
Expand Down
29 changes: 19 additions & 10 deletions deployment/keystone/changeset/deploy_ocr3.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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
}
Loading

0 comments on commit 3c8d951

Please sign in to comment.