Skip to content

Commit 6a6d08a

Browse files
committed
MCMS support
1 parent 559f5fe commit 6a6d08a

File tree

1 file changed

+95
-20
lines changed

1 file changed

+95
-20
lines changed

deployment/ccip/changeset/ccip_attestation/cs_ops_solana.go

Lines changed: 95 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,58 @@ import (
88
"github.com/gagliardetto/solana-go"
99
signer_registry "github.com/smartcontractkit/ccip-base/chains/solana/go_bindings"
1010
"github.com/smartcontractkit/chainlink/deployment/common/proposalutils"
11+
"github.com/smartcontractkit/mcms"
12+
mcmsTypes "github.com/smartcontractkit/mcms/types"
1113

14+
cldf_solana "github.com/smartcontractkit/chainlink-deployments-framework/chain/solana"
1215
cldf "github.com/smartcontractkit/chainlink-deployments-framework/deployment"
1316
cs_solana "github.com/smartcontractkit/chainlink/deployment/ccip/changeset/solana_v0_1_1"
1417
"github.com/smartcontractkit/chainlink/deployment/ccip/shared"
1518
solanastateview "github.com/smartcontractkit/chainlink/deployment/ccip/shared/stateview/solana"
1619
)
1720

21+
// ExecuteOrBuildMCMSProposal handles the decision to execute instructions directly or build an MCMS proposal.
22+
// If mcmsConfig is nil, it executes the instructions directly on the chain.
23+
// If mcmsConfig is provided, it builds MCMS transactions and creates a proposal.
24+
func ExecuteOrBuildMCMSProposal(
25+
e cldf.Environment,
26+
chain *cldf_solana.Chain,
27+
instructions []solana.Instruction,
28+
programID string,
29+
contractType cldf.ContractType,
30+
mcmsConfig *proposalutils.TimelockConfig,
31+
proposalDescription string,
32+
) (cldf.ChangesetOutput, error) {
33+
if mcmsConfig == nil {
34+
// Direct execution - confirm each instruction individually to avoid Tx size limits
35+
for i, ixn := range instructions {
36+
if err := chain.Confirm([]solana.Instruction{ixn}); err != nil {
37+
return cldf.ChangesetOutput{}, fmt.Errorf("failed to confirm instruction %d: %w", i, err)
38+
}
39+
}
40+
return cldf.ChangesetOutput{}, nil
41+
}
42+
43+
mcmsTxns := make([]mcmsTypes.Transaction, 0, len(instructions))
44+
for _, ixn := range instructions {
45+
tx, err := cs_solana.BuildMCMSTxn(ixn, programID, contractType)
46+
if err != nil {
47+
return cldf.ChangesetOutput{}, fmt.Errorf("failed to create MCMS transaction: %w", err)
48+
}
49+
mcmsTxns = append(mcmsTxns, *tx)
50+
}
51+
52+
proposal, err := cs_solana.BuildProposalsForTxns(
53+
e, chain.Selector, proposalDescription, mcmsConfig.MinDelay, mcmsTxns)
54+
if err != nil {
55+
return cldf.ChangesetOutput{}, fmt.Errorf("failed to build proposal: %w", err)
56+
}
57+
58+
return cldf.ChangesetOutput{
59+
MCMSTimelockProposals: []mcms.TimelockProposal{*proposal},
60+
}, nil
61+
}
62+
1863
// use this changeset to rotate NOPs (entirely remove addresses or add new ones)
1964
var _ cldf.ChangeSet[RotateBaseSignerNopsConfig] = RotateBaseSignerNopsChangeset
2065

@@ -54,7 +99,8 @@ type PromoteKeysConfig struct {
5499
type SetUpgradeAuthorityConfig struct {
55100
ChainSelector uint64
56101
NewUpgradeAuthority solana.PublicKey
57-
MCMS *proposalutils.TimelockConfig // if set, assumes current upgrade authority is the timelock
102+
// if set, assumes current upgrade authority is the timelock
103+
MCMS *proposalutils.TimelockConfig
58104
}
59105

60106
func RotateBaseSignerNopsChangeset(e cldf.Environment, c RotateBaseSignerNopsConfig) (cldf.ChangesetOutput, error) {
@@ -66,29 +112,35 @@ func RotateBaseSignerNopsChangeset(e cldf.Environment, c RotateBaseSignerNopsCon
66112
signersPda, _, _ := solana.FindProgramAddress([][]byte{[]byte("signers")}, signer_registry.ProgramID)
67113
eventAuthorityPda, _, _ := solana.FindProgramAddress([][]byte{[]byte("__event_authority")}, signer_registry.ProgramID)
68114

115+
var instructions []solana.Instruction
116+
69117
for _, hexKey := range c.NopKeysToRemove {
70118
key, _ := parseEVMAddress(hexKey)
71119

72120
ix, err := signer_registry.NewRemoveSignerInstruction(key, chain.DeployerKey.PublicKey(), configPda, signersPda, eventAuthorityPda, signer_registry.ProgramID)
73121
if err != nil {
74122
return cldf.ChangesetOutput{}, fmt.Errorf("Failed to remove signer: %w", err)
75123
}
76-
if err := chain.Confirm([]solana.Instruction{ix}); err != nil {
77-
return cldf.ChangesetOutput{}, fmt.Errorf("Failed to remove signer: %w", err)
78-
}
124+
instructions = append(instructions, ix)
79125
}
80126
for _, hexKey := range c.NopKeysToAdd {
81127
key, _ := parseEVMAddress(hexKey)
82128
ix, err := signer_registry.NewAddSignerInstruction(key, chain.DeployerKey.PublicKey(), configPda, signersPda, eventAuthorityPda, signer_registry.ProgramID)
83129
if err != nil {
84130
return cldf.ChangesetOutput{}, fmt.Errorf("Failed to add signer: %w", err)
85131
}
86-
if err := chain.Confirm([]solana.Instruction{ix}); err != nil {
87-
return cldf.ChangesetOutput{}, fmt.Errorf("Failed to add signer: %w", err)
88-
}
132+
instructions = append(instructions, ix)
89133
}
90134

91-
return cldf.ChangesetOutput{}, nil
135+
return ExecuteOrBuildMCMSProposal(
136+
e,
137+
&chain,
138+
instructions,
139+
signer_registry.ProgramID.String(),
140+
cldf.ContractType("BaseSignerRegistry"),
141+
c.MCMS,
142+
"proposal to rotate attestation signer NOPs in Solana",
143+
)
92144
}
93145

94146
func (c RotateBaseSignerNopsConfig) Validate(e cldf.Environment) error {
@@ -160,6 +212,8 @@ func AddGreenKeysChangeset(e cldf.Environment, c AddGreenKeysConfig) (cldf.Chang
160212
signersPda, _, _ := solana.FindProgramAddress([][]byte{[]byte("signers")}, signer_registry.ProgramID)
161213
eventAuthorityPda, _, _ := solana.FindProgramAddress([][]byte{[]byte("__event_authority")}, signer_registry.ProgramID)
162214

215+
var instructions []solana.Instruction
216+
163217
for _, keyPair := range c.BlueGreenKeys {
164218
blue, _ := parseEVMAddress(keyPair[0])
165219
green, _ := parseEVMAddress(keyPair[1])
@@ -168,12 +222,18 @@ func AddGreenKeysChangeset(e cldf.Environment, c AddGreenKeysConfig) (cldf.Chang
168222
if err != nil {
169223
return cldf.ChangesetOutput{}, fmt.Errorf("Failed to add green key: %w", err)
170224
}
171-
if err := chain.Confirm([]solana.Instruction{ix}); err != nil {
172-
return cldf.ChangesetOutput{}, fmt.Errorf("Failed to add green key: %w", err)
173-
}
225+
instructions = append(instructions, ix)
174226
}
175227

176-
return cldf.ChangesetOutput{}, nil
228+
return ExecuteOrBuildMCMSProposal(
229+
e,
230+
&chain,
231+
instructions,
232+
signer_registry.ProgramID.String(),
233+
cldf.ContractType("BaseSignerRegistry"),
234+
c.MCMS,
235+
"proposal to add green keys for rotation in Solana",
236+
)
177237
}
178238

179239
func (c AddGreenKeysConfig) Validate(e cldf.Environment) error {
@@ -239,19 +299,27 @@ func PromoteKeysChangeset(e cldf.Environment, c PromoteKeysConfig) (cldf.Changes
239299
signersPda, _, _ := solana.FindProgramAddress([][]byte{[]byte("signers")}, signer_registry.ProgramID)
240300
eventAuthorityPda, _, _ := solana.FindProgramAddress([][]byte{[]byte("__event_authority")}, signer_registry.ProgramID)
241301

302+
var instructions []solana.Instruction
303+
242304
for _, keyHex := range c.KeysToPromote {
243305
key, _ := parseEVMAddress(keyHex)
244306

245307
ix, err := signer_registry.NewPromoteSignerAddressInstruction(key, chain.DeployerKey.PublicKey(), configPda, signersPda, eventAuthorityPda, signer_registry.ProgramID)
246308
if err != nil {
247309
return cldf.ChangesetOutput{}, fmt.Errorf("Failed to promote key: %w", err)
248310
}
249-
if err := chain.Confirm([]solana.Instruction{ix}); err != nil {
250-
return cldf.ChangesetOutput{}, fmt.Errorf("Failed to promote key: %w", err)
251-
}
311+
instructions = append(instructions, ix)
252312
}
253313

254-
return cldf.ChangesetOutput{}, nil
314+
return ExecuteOrBuildMCMSProposal(
315+
e,
316+
&chain,
317+
instructions,
318+
signer_registry.ProgramID.String(),
319+
cldf.ContractType("BaseSignerRegistry"),
320+
c.MCMS,
321+
"proposal to promote green keys in Solana",
322+
)
255323
}
256324

257325
func (c PromoteKeysConfig) Validate(e cldf.Environment) error {
@@ -303,11 +371,18 @@ func SetUpgradeAuthorityChangeset(
303371
chain := e.BlockChains.SolanaChains()[config.ChainSelector]
304372
currentAuthority := chain.DeployerKey.PublicKey()
305373
e.Logger.Infow("Setting upgrade authority", "newUpgradeAuthority", config.NewUpgradeAuthority.String())
374+
306375
ixn := cs_solana.SetUpgradeAuthority(&e, &chain, signer_registry.ProgramID, currentAuthority, config.NewUpgradeAuthority, false)
307-
if err := chain.Confirm([]solana.Instruction{ixn}); err != nil {
308-
return cldf.ChangesetOutput{}, fmt.Errorf("failed to confirm instructions: %w", err)
309-
}
310-
return cldf.ChangesetOutput{}, nil
376+
377+
return ExecuteOrBuildMCMSProposal(
378+
e,
379+
&chain,
380+
[]solana.Instruction{ixn},
381+
solana.BPFLoaderUpgradeableProgramID.String(),
382+
cldf.ContractType(solana.BPFLoaderUpgradeableProgramID.String()),
383+
config.MCMS,
384+
"proposal to SetUpgradeAuthority in Solana",
385+
)
311386
}
312387

313388
func parseEVMAddress(addr string) ([20]uint8, error) {

0 commit comments

Comments
 (0)