Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion mcms/evm/set-config/operation.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ type OpEVMSetConfigInput struct {
}

// OpEVMSetConfigMCM sets MCMS config on an EVM MCM contract via the MCMS SDK configurer.
// TODO: this may be removed if we generate operations via operations gen tool.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

after discussion, we decided to not use operations-gen cli for setconfig but instead use the mcms sdk

var OpEVMSetConfigMCM = operations.NewOperation(
"evm-mcm-set-config",
semver.MustParse("1.0.0"),
Expand Down
132 changes: 50 additions & 82 deletions mcms/evm/set-config/sequence.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package evmsetconfig
import (
"fmt"
"math/big"
"strconv"

"github.com/Masterminds/semver/v3"
"github.com/ethereum/go-ethereum/common"
Expand All @@ -11,75 +12,11 @@ import (
cldf "github.com/smartcontractkit/chainlink-deployments-framework/deployment"
cldfproposalutils "github.com/smartcontractkit/chainlink-deployments-framework/engine/cld/mcms/proposalutils"
"github.com/smartcontractkit/chainlink-deployments-framework/operations"
mcmsTypes "github.com/smartcontractkit/mcms/types"
mcmstypes "github.com/smartcontractkit/mcms/types"

setconfig "github.com/smartcontractkit/cld-changesets/mcms/changesets/set-config"
)

// SeqEVMSetConfigInput is the input for the generic EVM set-config sequence.
type SeqEVMSetConfigInput struct {

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

flattening this sequence into the parent sequence as this adds unnecessary extra layer of sequence

ChainSelector uint64 `json:"chainSelector"`
NoSend bool `json:"noSend"`
GasBoostConfig *cldfproposalutils.GasBoostConfig `json:"gasBoostConfig,omitempty"`
Targets []MCMSetConfigTarget `json:"targets"`
}

// SeqEVMSetConfig sets config on each provided MCM contract via OpEVMSetConfigMCM.
var SeqEVMSetConfig = operations.NewSequence(
"seq-evm-mcm-set-config",
semver.MustParse("1.0.0"),
"Sets MCMS config on one or more MCM contracts",
func(b operations.Bundle, deps cldf_evm.Chain, in SeqEVMSetConfigInput) (sequenceutils.OnChainOutput, error) {
if in.ChainSelector != deps.Selector {
return sequenceutils.OnChainOutput{}, fmt.Errorf("mismatch between inputted chain selector and selector defined within dependencies: %d != %d", in.ChainSelector, deps.Selector)
}

var outs []EVMCallOutput
if in.NoSend {
outs = make([]EVMCallOutput, 0, len(in.Targets))
}

for _, target := range in.Targets {
opReport, err := operations.ExecuteOperation(
b,
OpEVMSetConfigMCM,
deps,
OpEVMSetConfigInput{
Target: target,
NoSend: in.NoSend,
},
retrySetConfigWithGasBoost(in.GasBoostConfig),
)
if err != nil {
return sequenceutils.OnChainOutput{}, err
}

if !in.NoSend {
continue
}

out := opReport.Output
out.ContractType = target.ContractType
outs = append(outs, out)
}

out := sequenceutils.OnChainOutput{}
if !in.NoSend {
return out, nil
}

batch, err := evmCallOutputsToBatch(in.ChainSelector, outs)
if err != nil {
return sequenceutils.OnChainOutput{}, err
}
if len(batch.Transactions) > 0 {
out.BatchOps = []mcmsTypes.BatchOperation{batch}
}

return out, nil
},
)

var seqSetConfig = operations.NewSequence(
"seq-evm-set-config-mcms",
semver.MustParse("1.0.0"),
Expand All @@ -102,21 +39,52 @@ func runEVMSetConfig(
return sequenceutils.OnChainOutput{}, err
}

seqReport, err := operations.ExecuteSequence(
b,
SeqEVMSetConfig,
chain,
SeqEVMSetConfigInput{
ChainSelector: in.ChainSelector,
NoSend: in.MCMS != nil,
Targets: targets,
},
)
useMCMS := in.MCMS != nil

var outs []EVMCallOutput
if useMCMS {
outs = make([]EVMCallOutput, 0, len(targets))
}

for _, target := range targets {
opReport, execErr := operations.ExecuteOperation(
b,
OpEVMSetConfigMCM,
chain,
OpEVMSetConfigInput{
Target: target,
NoSend: useMCMS,
},
retrySetConfigWithGasBoost(nil),
operations.WithIdempotencyKey[OpEVMSetConfigInput, cldf_evm.Chain](strconv.FormatUint(chain.Selector, 10)+":"+target.Address.Hex()),
)
if execErr != nil {
return sequenceutils.OnChainOutput{}, execErr
}

if !useMCMS {
continue
}

out := opReport.Output
out.ContractType = target.ContractType
outs = append(outs, out)
}

out := sequenceutils.OnChainOutput{}
if !useMCMS {
return out, nil
}

batch, err := evmCallOutputsToBatch(in.ChainSelector, outs)
if err != nil {
return sequenceutils.OnChainOutput{}, fmt.Errorf("failed to execute EVM set config sequence: %w", err)
return sequenceutils.OnChainOutput{}, err
}
if len(batch.Transactions) > 0 {
out.BatchOps = []mcmstypes.BatchOperation{batch}
}

return seqReport.Output, nil
return out, nil
}

func setConfigTargets(e cldf.Environment, configs []setconfig.ContractSetConfig) ([]MCMSetConfigTarget, error) {
Expand All @@ -141,10 +109,10 @@ func setConfigTargets(e cldf.Environment, configs []setconfig.ContractSetConfig)
return targets, nil
}

func evmCallOutputsToBatch(chainSelector uint64, outs []EVMCallOutput) (mcmsTypes.BatchOperation, error) {
result := mcmsTypes.BatchOperation{
ChainSelector: mcmsTypes.ChainSelector(chainSelector),
Transactions: []mcmsTypes.Transaction{},
func evmCallOutputsToBatch(chainSelector uint64, outs []EVMCallOutput) (mcmstypes.BatchOperation, error) {
result := mcmstypes.BatchOperation{
ChainSelector: mcmstypes.ChainSelector(chainSelector),
Transactions: []mcmstypes.Transaction{},
}

for _, out := range outs {
Expand All @@ -161,7 +129,7 @@ func evmCallOutputsToBatch(chainSelector uint64, outs []EVMCallOutput) (mcmsType
[]string{},
)
if err != nil {
return mcmsTypes.BatchOperation{}, fmt.Errorf("failed to create batch operation for chain %d: %w", chainSelector, err)
return mcmstypes.BatchOperation{}, fmt.Errorf("failed to create batch operation for chain %d: %w", chainSelector, err)
}
result.Transactions = append(result.Transactions, batchOperation.Transactions...)
}
Expand Down
80 changes: 34 additions & 46 deletions mcms/evm/set-config/sequence_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ import (
cldftesthelpers "github.com/smartcontractkit/chainlink-deployments-framework/engine/cld/mcms/proposalutils/testhelpers"
"github.com/smartcontractkit/chainlink-deployments-framework/engine/test/environment"
"github.com/smartcontractkit/chainlink-deployments-framework/engine/test/runtime"
"github.com/smartcontractkit/chainlink-deployments-framework/operations"
"github.com/smartcontractkit/chainlink-deployments-framework/operations/optest"
"github.com/smartcontractkit/chainlink-deployments-framework/pkg/logger"
mcmsevm "github.com/smartcontractkit/mcms/sdk/evm"
Expand All @@ -37,15 +36,15 @@ import (
evmreaders "github.com/smartcontractkit/cld-changesets/mcms/evm/readers"
)

func TestSeqEVMSetConfig(t *testing.T) {
func TestRunEVMSetConfig(t *testing.T) {
t.Parallel()

tests := []struct {
name string
noSend bool
name string
transferToMCMS bool
}{
{name: "direct send", noSend: false},
{name: "MCMS proposal", noSend: true},
{name: "direct send", transferToMCMS: false},
{name: "MCMS proposal", transferToMCMS: true},
}

for _, tt := range tests {
Expand All @@ -57,7 +56,7 @@ func TestSeqEVMSetConfig(t *testing.T) {
refs := evmSetConfigRefs(t, rt.Environment(), selector)
chain := rt.Environment().BlockChains.EVMChains()[selector]

if tt.noSend {
if tt.transferToMCMS {
transferEVMMCMSToTimelock(t, rt, selector, refs)
}

Expand All @@ -73,53 +72,58 @@ func TestSeqEVMSetConfig(t *testing.T) {
cancellerCfg.Signers = append(cancellerCfg.Signers, refs.Bypasser)
cancellerCfg.Quorum = 2

targets := []MCMSetConfigTarget{
targets := []setconfig.ContractSetConfig{
{
Address: refs.Proposer,
Config: proposerCfg,
ContractType: mcmscontracts.ProposerManyChainMultisig,
Ref: refkey.New(selector, datastore.ContractType(mcmscontracts.ProposerManyChainMultisig), &semvers.V1_0_0, ""),
Config: proposerCfg,
},
{
Address: refs.Bypasser,
Config: bypasserCfg,
ContractType: mcmscontracts.BypasserManyChainMultisig,
Ref: refkey.New(selector, datastore.ContractType(mcmscontracts.BypasserManyChainMultisig), &semvers.V1_0_0, ""),
Config: bypasserCfg,
},
}
if tt.noSend {
targets = []MCMSetConfigTarget{
var mcmsInput *cldf.MCMSTimelockProposalInput
if tt.transferToMCMS {
targets = []setconfig.ContractSetConfig{
{
Address: refs.Canceller,
Config: cancellerCfg,
ContractType: mcmscontracts.CancellerManyChainMultisig,
Ref: refkey.New(selector, datastore.ContractType(mcmscontracts.CancellerManyChainMultisig), &semvers.V1_0_0, ""),
Config: cancellerCfg,
},
}
mcmsInput = &cldf.MCMSTimelockProposalInput{
TimelockAction: mcmstypes.TimelockActionBypass,
ValidUntil: uint32(time.Now().Add(2 * time.Hour).UTC().Unix()), //nolint:gosec // test timestamp
TimelockDelay: mcmstypes.NewDuration(0),
}
}

report, err := operations.ExecuteSequence(
out, err := runEVMSetConfig(
rt.Environment().OperationsBundle,
SeqEVMSetConfig,
chain,
SeqEVMSetConfigInput{
setconfig.Deps{
BlockChains: rt.Environment().BlockChains,
DataStore: rt.Environment().DataStore,
},
setconfig.ChainInput{
ChainSelector: selector,
NoSend: tt.noSend,
Targets: targets,
MCMS: mcmsInput,
},
)
require.NoError(t, err)

if tt.noSend {
require.Len(t, report.Output.BatchOps, 1)
require.Len(t, report.Output.BatchOps[0].Transactions, 1)
if tt.transferToMCMS {
require.Len(t, out.BatchOps, 1)
require.Len(t, out.BatchOps[0].Transactions, 1)
require.NoError(t, rt.Exec(
newTimelockProposalTask(report.Output.BatchOps, "set config sequence test"),
newTimelockProposalTask(out.BatchOps, "set config sequence test"),
runtime.SignAndExecuteProposalsTask([]*ecdsa.PrivateKey{cldftesthelpers.TestXXXMCMSSigner}),
))
} else {
require.Empty(t, report.Output.BatchOps)
require.Empty(t, out.BatchOps)
}

inspector := mcmsevm.NewInspector(chain.Client)
if tt.noSend {
if tt.transferToMCMS {
assertEVMConfigEquals(t, inspector, refs.Canceller, cancellerCfg)
} else {
assertEVMConfigEquals(t, inspector, refs.Proposer, proposerCfg)
Expand Down Expand Up @@ -243,22 +247,6 @@ func assertEVMConfigEquals(t *testing.T, inspector *mcmsevm.Inspector, address c
require.Equal(t, want.Quorum, got.Quorum)
}

func TestSeqEVMSetConfig_chainSelectorMismatch(t *testing.T) {
t.Parallel()

selector := chainselectors.TEST_90000001.Selector
_, err := operations.ExecuteSequence(
optest.NewBundle(t),
SeqEVMSetConfig,
cldf_evm.Chain{Selector: selector},
SeqEVMSetConfigInput{
ChainSelector: chainselectors.TEST_90000002.Selector,
NoSend: true,
},
)
require.ErrorContains(t, err, "mismatch between inputted chain selector")
}

func TestSetConfigTargets(t *testing.T) {
t.Parallel()

Expand Down
2 changes: 1 addition & 1 deletion mcms/solana/set-config/operation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import (
//nolint:paralleltest // global mcm.SetProgramID state; serialized via soltestutils.PreloadMCMS lock
func TestSolanaSetConfig(t *testing.T) {
t.Run("operation", testOpSolanaSetConfigMCM)
t.Run("sequence", testSeqSolanaSetConfig)
t.Run("sequence", testRunSolanaSetConfig)
}

func testOpSolanaSetConfigMCM(t *testing.T) {
Expand Down
Loading
Loading