evmigration(multisig): catch --nosort destination mismatch at sign time + operator-facing docs#176
Merged
mateeullahmalik merged 2 commits intoJun 23, 2026
Conversation
Cosmos SDK's `keys add --multisig` sorts sub-pubkeys by bytes by default. Legacy secp256k1 and new eth_secp256k1 pubkeys sort differently, so a destination multisig built without --nosort lands its members at different signer indices than the legacy multisig. This breaks the mirror-source invariant and a co-signer's both-sides partial fails with a terse 'signer index N vs M' error from the binary - leaving the operator to figure out that they need to rebuild the destination key with --nosort. This change adds a pre-check in `migrate-multisig.sh sign`: when both --from and --new-key are passed, compute each pubkey's index in the proof file's sub_pub_keys, and if they disagree print an actionable remediation including the exact 'lumerad keys add ... --nosort' command to rebuild the destination. Exit 11. Also adds: - A '0. Build the destination EVM multisig' section to migration-scripts.md with the explicit --nosort recipe (was previously omitted from the scripts walkthrough entirely). - A prominent --nosort callout to migration.md alongside the existing member-order note (was a single sentence buried in a bullet). Discovered during the local rc5 rehearsal that re-ran the full 31-account foundation migration; without --nosort 11/26 batch multisigs failed on sign-proof. No protocol or state-machine change. Script + docs only. Signed-off-by: Matee ullah Malik <mateeullahmalik@hotmail.com>
1bc5b29 to
bd8dcbe
Compare
Contributor
There was a problem hiding this comment.
Pull request overview
This PR reduces multisig-migration operator errors by detecting destination multisig member-order mismatches at sign time (commonly caused by omitting --nosort) and by making the required --nosort workflow prominent in the operator docs.
Changes:
- Add a signer-index alignment pre-check in
migrate-multisig.sh sign(when both--fromand--new-keyare provided) with an actionable remediation path and distinct exit code. - Update migration docs to prominently call out
--nosortand provide copy/pasteable destination multisig build instructions. - Add a new “Step 0: Build the destination EVM multisig” section to the scripts guide.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
scripts/migrate-multisig.sh |
Adds sign-time signer-index mismatch detection and operator-facing remediation instructions. |
docs/evm-integration/user-guides/migration.md |
Promotes --nosort requirement into a prominent callout with an example command. |
docs/evm-integration/user-guides/migration-scripts.md |
Adds an explicit Step 0 for building the destination multisig with --nosort and adds a critical warning callout. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
…ookup Copilot review pointed out that 'sub_pub_keys | to_entries[] | select(.value==$pk) | .key' emits multiple lines if duplicates exist, which would corrupt from_idx/new_idx as multi-line strings and break the string-compare mismatch check. While real multisigs don't carry duplicate sub-pubkeys, 'index($pk) // empty' is the deterministic primitive: returns the first (single) index or empty on no match. Simpler and robust to hypothetical degenerate input. Behavior on the happy path is identical; touches only the two new jq lookups added in 1bc5b29.
j-rafique
approved these changes
Jun 23, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Eliminates the most common multisig-migration operator footgun: building the destination EVM multisig without
--nosort, which breaks the mirror-source signer-index invariant and currently fails late with a cryptic CLI error.Adds (1) a pre-check in
migrate-multisig.sh signthat catches the mismatch and prints an exact rebuild recipe, and (2) prominent--nosortcallouts + a new "Step 0: Build the destination EVM multisig" section in the operator docs.No protocol / state-machine / consensus change. Script + docs only.
Background
generate-proof-payloadpreserves the order in which--new-sub-pub-keysis passed (does not sort). However, Cosmos SDK'slumerad keys add --multisigdoes sort sub-pubkeys by bytes by default. Because legacysecp256k1and neweth_secp256k1pubkey bytes sort differently, the default sort produces a destination multisig whose members land at different signer indices than the legacy side. The on-chain mirror-source rule then rejects the proof, andmigrate-multisig.sh sign(when a co-signer holds both halves) errors out with:…leaving the operator to figure out that they need to delete the destination key, rebuild it with
--nosort, and have the coordinator regenerateproof.json.This was hit live during a local rc5 rehearsal that ran the full 31-account foundation migration; 11/26 multisigs failed on
sign-proofbefore the--nosortroot cause was identified. With--nosortthe same batch succeeded first-try, end to end.Changes
1.
scripts/migrate-multisig.sh— sign-time index-alignment pre-checkWhen a co-signer passes both
--fromand--new-key, compute each pubkey's index in the proof file'ssub_pub_keysarrays. If they disagree, exit 11 with an actionable error including the exactlumerad keys add ... --nosortrebuild command and the full 4-step remediation. Avoids round-tripping through the binary's terse error.2.
docs/evm-integration/user-guides/migration-scripts.md--nosortrecipe (was completely missing — operators following only the scripts walkthrough would hit the trap with zero warning).⚠️ Criticalcallout at the top of the section pointing to Step 0.3.
docs/evm-integration/user-guides/migration.md--nosortsentence (previously a single line buried at the end of a bullet) to a prominent⚠️callout block with the copy-pasteablelumerad keys addcommand.Risk / Rollback
11is distinct from existing codes (1, 3, 8, 9, 10) — no collision with downstream tooling.Verification
bash -ncleanshellcheckcleanmigrate-multisig.sh sign --helpstill renders--nosort+ canonical signer order, 26/26 batch multisig migrations succeed; without--nosort(the trap path) the pre-check now fires at the right moment with the right remediation.Definition of Done
--nosortat every entry point operators readshellcheck+bash -ncleanOperator-facing diff (the new error)