Skip to content

Commit 0e60a11

Browse files
feat: check MCM state before calling SetRoot or Execute (#556)
Modify the setRootCommand and executeCommand logic so that the mcm state is probed before calling the `setRoot` or `execute` methods. This means we shouldn't need to check for the revert messages issued by the contract when a `setRoot` or `execute` call is retried by the GHA workflows.
1 parent c6f7a1b commit 0e60a11

File tree

7 files changed

+486
-72
lines changed

7 files changed

+486
-72
lines changed

.changeset/gentle-waves-appear.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"chainlink-deployments-framework": minor
3+
---
4+
5+
feat(mcms): check MCM state before calling SetRoot or Execute

engine/cld/legacy/cli/mcmsv2/mcms_v2.go

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,11 @@ func buildExecuteOperationv2Cmd(lggr logger.Logger, domain cldf_domain.Domain, p
200200
if err != nil {
201201
return fmt.Errorf("error converting proposal to executable: %w", err)
202202
}
203+
inspector, err := getInspectorFromChainSelector(*cfg)
204+
if err != nil {
205+
return fmt.Errorf("failed to get inspector: %w", err)
206+
}
207+
203208
if cfg.fork {
204209
lggr.Info("Fork mode is on, all transactions will be executed on a forked chain")
205210
}
@@ -213,6 +218,23 @@ func buildExecuteOperationv2Cmd(lggr logger.Logger, domain cldf_domain.Domain, p
213218
return fmt.Errorf("operation %d is not for chain %d", index, cfg.chainSelector)
214219
}
215220

221+
opCount, err := inspector.GetOpCount(cmd.Context(), cfg.proposal.ChainMetadata[types.ChainSelector(cfg.chainSelector)].MCMAddress)
222+
if err != nil {
223+
return fmt.Errorf("failed to get opcount for chain %d: %w", cfg.chainSelector, err)
224+
}
225+
txNonce, err := executable.TxNonce(index)
226+
if err != nil {
227+
return fmt.Errorf("failed to get TxNonce for chain %d: %w", cfg.chainSelector, err)
228+
}
229+
if txNonce < opCount {
230+
lggr.Infow("operation already executed", "index", index, "txNonce", txNonce, "opCount", opCount)
231+
return nil
232+
}
233+
if txNonce > opCount {
234+
lggr.Warnw("txNonce too large", "index", index, "txNonce", txNonce, "opCount", opCount)
235+
return fmt.Errorf("txNonce too large (%d; expected %d)", txNonce, opCount)
236+
}
237+
216238
tx, err := executable.Execute(cmd.Context(), index)
217239
if err != nil {
218240
err = cldf.DecodeErr(bindings.ManyChainMultiSigABI, err)
@@ -1177,6 +1199,11 @@ func executeChainCommand(ctx context.Context, lggr logger.Logger, cfg *cfgv2, sk
11771199
if err != nil {
11781200
return fmt.Errorf("error converting proposal to executable: %w", err)
11791201
}
1202+
inspector, err := getInspectorFromChainSelector(*cfg)
1203+
if err != nil {
1204+
return fmt.Errorf("failed to get inspector: %w", err)
1205+
}
1206+
11801207
if cfg.fork {
11811208
lggr.Info("Fork mode is on, all transactions will be executed on a forked chain")
11821209
}
@@ -1187,6 +1214,23 @@ func executeChainCommand(ctx context.Context, lggr logger.Logger, cfg *cfgv2, sk
11871214
continue
11881215
}
11891216

1217+
opCount, err := inspector.GetOpCount(ctx, cfg.proposal.ChainMetadata[types.ChainSelector(cfg.chainSelector)].MCMAddress)
1218+
if err != nil {
1219+
return fmt.Errorf("failed to get opcount for chain %d: %w", cfg.chainSelector, err)
1220+
}
1221+
txNonce, err := executable.TxNonce(i)
1222+
if err != nil {
1223+
return fmt.Errorf("failed to get TxNonce for chain %d: %w", cfg.chainSelector, err)
1224+
}
1225+
if txNonce < opCount {
1226+
lggr.Infow("operation already executed", "index", i, "txNonce", txNonce, "opCount", opCount)
1227+
continue
1228+
}
1229+
if txNonce > opCount {
1230+
lggr.Warnw("txNonce too large", "index", i, "txNonce", txNonce, "opCount", opCount)
1231+
break
1232+
}
1233+
11901234
tx, err := executable.Execute(ctx, i)
11911235
if err != nil {
11921236
lggr.Errorf("error executing operation %d: %s", i, err)
@@ -1229,6 +1273,27 @@ func setRootCommand(ctx context.Context, lggr logger.Logger, cfg *cfgv2) error {
12291273
lggr.Info("Fork mode is on, all transactions will be executed on a forked chain")
12301274
}
12311275

1276+
inspector, err := getInspectorFromChainSelector(*cfg)
1277+
if err != nil {
1278+
return fmt.Errorf("failed to get inspector: %w", err)
1279+
}
1280+
1281+
proposalMerkleTree, err := cfg.proposal.MerkleTree()
1282+
if err != nil {
1283+
return fmt.Errorf("failed to compute the proposal's merkle tree: %w", err)
1284+
}
1285+
1286+
mcmAddress := cfg.proposal.ChainMetadata[types.ChainSelector(cfg.chainSelector)].MCMAddress
1287+
mcmRoot, _, err := inspector.GetRoot(ctx, mcmAddress)
1288+
if err != nil {
1289+
return fmt.Errorf("failed to get the merkle tree root from the MCM contract (%v): %w", mcmAddress, err)
1290+
}
1291+
1292+
if mcmRoot == proposalMerkleTree.Root {
1293+
lggr.Infof("Root %v already set in MCM contract %v", mcmRoot, mcmAddress)
1294+
return nil
1295+
}
1296+
12321297
executable, err := createExecutable(cfg)
12331298
if err != nil {
12341299
return fmt.Errorf("error converting proposal to executable: %w", err)

0 commit comments

Comments
 (0)