feat: adds tasks to sign and execute MCMS proposals#445
Conversation
🦋 Changeset detectedLatest commit: a53123a The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
0f7f2c0 to
9e35cf0
Compare
9e35cf0 to
ed86252
Compare
bytesizedroll
left a comment
There was a problem hiding this comment.
Its late and took a quick first pass at this. Will dive back in tomorrow morning.
engine/test/runtime/task_mcms.go
Outdated
|
|
||
| // Update the proposal state with the signed proposal | ||
| if err := state.UpdateProposalJSON(t.proposalID, propJSON); err != nil { | ||
| return fmt.Errorf("failed toupdate proposal state: %w", err) |
There was a problem hiding this comment.
| return fmt.Errorf("failed toupdate proposal state: %w", err) | |
| return fmt.Errorf("failed to update proposal state: %w", err) |
| t.Parallel() | ||
|
|
||
| // Generate a test private key | ||
| privateKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) |
There was a problem hiding this comment.
| privateKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) | |
| privateKey, err := ecdsa.GenerateKey(btcec.S256(), rand.Reader) |
I assume mcms accepts P256 for tests but should we maybe have it be secp256k1 just to keep consistency with prod?
There was a problem hiding this comment.
Looked into the mcms lib and it uses the go ethereum crypto library to perform signing, and their tests use private keys generated from the same crypto library. I've updated the tests to use this same method
| t.Parallel() | ||
|
|
||
| // Generate a test private key | ||
| privateKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) |
There was a problem hiding this comment.
Same question as above
There was a problem hiding this comment.
This has been changed to use the go ethereum crypto library, same reasoning as above
| if err != nil { | ||
| return err | ||
| } | ||
|
|
There was a problem hiding this comment.
| if propState.IsExecuted { | |
| return fmt.Errorf("proposal already executed: %s", t.proposalID) | |
| } | |
Is there benefit in adding a guard here? So that we are actually using the IsExecuted attribute and protecting against re-runs, proposals should only be ran once.
There was a problem hiding this comment.
Can add a test for this as well
This adds two new tasks to the test engine runtime - SignProposalTask - Signs a MCMS or Timelock proposal - ExecuteProposalTask - Executes a signed MCMS or Timelock proposal Proposals that are generated from a changeset output are stored in the proposal and assigned an id. A user can use the proposal id to sign and execute the proposal by calling Exec with the newly provided tasks. Future iterations may add more tasks to support automating the signing and execution process.
ed86252 to
a53123a
Compare
|
There was a problem hiding this comment.
Pull Request Overview
Adds new MCMS (Multi-Chain Multi-Sig) proposal signing and execution functionality to the test engine runtime, enabling automated management of blockchain proposals.
- Implements SignProposalTask for cryptographically signing MCMS and Timelock proposals
- Implements ExecuteProposalTask for executing signed proposals on target blockchains
- Adds comprehensive proposal state management with JSON serialization and execution tracking
Reviewed Changes
Copilot reviewed 34 out of 34 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| engine/test/runtime/task_mcms.go | Core implementation of MCMS signing and execution tasks |
| engine/test/runtime/task_mcms_test.go | Comprehensive test coverage for both task types with mocking |
| engine/test/runtime/state.go | Extended state management to track proposals with unique IDs |
| engine/test/runtime/state_test.go | Tests for proposal state operations and management |
| engine/test/internal/mcmsutils/ | New utilities package providing MCMS operations across blockchain families |
| chain/blockchain.go | Added GetBySelector method for chain lookup functionality |
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
| // ignored as cryptographic randomness is not critical for test salt generation. | ||
| func randomHash() *common.Hash { | ||
| b := make([]byte, 32) | ||
| _, _ = rand.Read(b) // Assignment for errcheck. Only used in tests so we can ignore. |
There was a problem hiding this comment.
The comment suggests this is acceptable because it's test-only code, but this function could be called in production contexts. Consider returning an error or using a more explicit approach like crypto/rand package that would panic on failure instead of silently ignoring errors.
| _, _ = rand.Read(b) // Assignment for errcheck. Only used in tests so we can ignore. | |
| if _, err := rand.Read(b); err != nil { | |
| panic(fmt.Sprintf("failed to generate random hash: %v", err)) | |
| } |
| // The signer is configured to use simulated EVM backends by default, which affects | ||
| // how encoders are generated for signing EVM proposals. | ||
| func NewSigner() (*Signer, error) { | ||
| return &Signer{ | ||
| isEVMSim: true, // This is always true for until we can find a way to allow the user to specify the type of EVM backend they are using. |
There was a problem hiding this comment.
The hardcoded true value with a TODO-style comment indicates incomplete functionality. Consider adding a parameter to NewSigner() or using an environment variable to make this configurable rather than hardcoding the value.
| // The signer is configured to use simulated EVM backends by default, which affects | |
| // how encoders are generated for signing EVM proposals. | |
| func NewSigner() (*Signer, error) { | |
| return &Signer{ | |
| isEVMSim: true, // This is always true for until we can find a way to allow the user to specify the type of EVM backend they are using. | |
| // The isEVMSim parameter controls whether to use simulated EVM backends, which affects | |
| // how encoders are generated for signing EVM proposals. | |
| func NewSigner(isEVMSim bool) (*Signer, error) { | |
| return &Signer{ | |
| isEVMSim: isEVMSim, |
| return nil, fmt.Errorf("invalid action [%s]: must be one of %v", | ||
| f.action, slices.Collect(maps.Keys(actionToAptosRole)), | ||
| ) |
There was a problem hiding this comment.
The error message uses %v to format the slice which will display in Go slice format like [item1 item2]. Consider joining the keys with commas or using a more user-friendly format like strings.Join() for better readability.
This PR was opened by the [Changesets release](https://github.com/changesets/action) GitHub action. When you're ready to do a release, you can merge this and the packages will be published to npm automatically. If you're not ready to do a release yet, that's fine, whenever you add more changesets to main, this PR will be updated. # Releases ## chainlink-deployments-framework@0.50.0 ### Minor Changes - [#452](#452) [`41464d4`](41464d4) Thanks [@jkongie](https://github.com/jkongie)! - Add `runtime.New()` convenience function for runtime initialization Provides a simpler way to create runtime instances using functional options for environment configuration. - [#445](#445) [`967a01b`](967a01b) Thanks [@jkongie](https://github.com/jkongie)! - Adds tasks to the test engine runtime to sign and execute MCMS proposals - [#451](#451) [`0e64684`](0e64684) Thanks [@jkongie](https://github.com/jkongie)! - Adds new convenience method `environment.New` to the test engine to bring up a new test environment The `environment.New` method is a wrapper around the environment loading struct and allows the user to load a new environment without having to instantiate the `Loader` struct themselves. The `testing.T` argument has been removed and it's dependencies have been replaced with: - A `context.Context` argument to the `Load` and `New` functions - A new functional option `WithLogger` which overrides the default noop logger. While this is a breaking change, the test environment is still in development and is not in actual usage yet. ### Patch Changes - [#454](#454) [`d87d8ef`](d87d8ef) Thanks [@DimitriosNaikopoulos](https://github.com/DimitriosNaikopoulos)! - Bump CTF to fix docker security dependency - [#455](#455) [`4788ba4`](4788ba4) Thanks [@gustavogama-cll](https://github.com/gustavogama-cll)! - fix: update ValidUntil when running "mcmsv2 reset-proposal" --------- Co-authored-by: app-token-issuer-engops[bot] <144731339+app-token-issuer-engops[bot]@users.noreply.github.com>




This adds two new tasks to the test engine runtime
Proposals that are generated from a changeset output are stored in the
proposal and assigned an id. A user can use the proposal id to sign and
execute the proposal by calling Exec with the newly provided tasks.
Future iterations may add more tasks to support automating the signing
and execution process.