Skip to content

feat(scripts): dev cluster contract upgrade - #4101

Draft
SimonRastikian wants to merge 2 commits into
3934-dev-cluster-node-upgradefrom
3934-dev-cluster-contract-upgrade
Draft

feat(scripts): dev cluster contract upgrade#4101
SimonRastikian wants to merge 2 commits into
3934-dev-cluster-node-upgradefrom
3934-dev-cluster-contract-upgrade

Conversation

@SimonRastikian

Copy link
Copy Markdown
Contributor

Deals partly with #3934 namely the contract upgrade on the dev cluster. This concludes phase 2.

@SimonRastikian
SimonRastikian changed the base branch from main to 3934-dev-cluster-node-upgrade August 7, 2026 15:35
@claude

claude Bot commented Aug 7, 2026

Copy link
Copy Markdown

PR title type suggestion: This PR adds operational scripts and configuration for dev cluster management, which is infrastructure/maintenance work rather than user-facing functionality. Consider changing the type from feat: to chore:.

Suggested title: chore(scripts): dev cluster contract upgrade

@claude

claude Bot commented Aug 7, 2026

Copy link
Copy Markdown

Pull request overview

Adds the contract-upgrade step to the dev-cluster ops flow, completing phase 2 of #3934. A new upgrade-dev-contract.sh fetches the contract WASM (published release tarball or a local cargo near build), hand-rolls the borsh encoding of ProposeUpdateArgs { code: Some(..), config: None }, calls propose_update, and then walks the cluster member accounts through vote_update. dev-menu.sh runs it as "Step 2" after the node rollout and verification, and the closing summary now reports whether the contract was touched.

Changes:

  • New scripts/ops/dev-cluster/upgrade-dev-contract.sh: WASM acquisition (release download or local build), borsh serialization to serialized.bin, propose_update, interactive UpdateId entry, per-member vote_update.
  • dev-menu.sh: new "Step 2 — contract" behind a confirmation, plus a CONTRACT_RESULT string folded into the final message.
  • dev-common.sh: PROPOSE_DEPOSIT="16 NEAR" set in resolve_dev_cluster, and a near_view helper for read-only contract calls.
  • RELEASES.md: ops-tooling section describes the new runbook order.

I verified the borsh layout against ProposeUpdateArgs (crates/near-mpc-contract-interface/src/types/updates.rs:59) — 0x01 + u32-LE len + code + 0x00, and the WASM_SIZE + 6 assertion, are both correct — and the release asset names against .github/workflows/release.yml:170-171.

Reviewed changes

Per-file summary
File Description
RELEASES.md Ops-tooling section now describes the nodes then verify then contract order.
scripts/ops/dev-cluster/dev-common.sh Adds PROPOSE_DEPOSIT to resolve_dev_cluster and a near_view read-only query helper.
scripts/ops/dev-cluster/dev-menu.sh Adds the contract step after verification and reports its outcome in the closing summary.
scripts/ops/dev-cluster/upgrade-dev-contract.sh New: fetch/build WASM, borsh-encode, propose_update, vote_update per member account.

Findings

Blocking (must fix before merge):

  • scripts/ops/dev-cluster/dev-menu.sh:78CONTRACT_RESULT="upgraded" is set on any zero exit from the child, but upgrade-dev-contract.sh exits 0 on every non-upgrade path: the operator declining propose_update (upgrade-dev-contract.sh:106), declining every vote (:124), every vote failing (:125 swallows the failure into an echo), and the trailing near_view version || true (:129) forcing a 0 exit regardless. So a run can print Done (contract: upgraded) when nothing was proposed or nothing was voted in — and that line is exactly what gates the mainnet dev-cluster rollout. Make the child exit status mean something, e.g.:

    # in upgrade-dev-contract.sh
    confirm "Send propose_update?" || { echo "Aborted before proposing."; exit 2; }
    ...
    votes_ok=0
    for account in $MEMBER_ACCOUNTS; do
        ...
        if "${vote_cmd[@]}"; then votes_ok=$((votes_ok + 1)); else warn "    vote failed for ${account}."; fi
    done
    step "==> Contract version (expect ${VERSION}):"
    near_view version || true
    (( votes_ok > 0 )) || die "No vote succeeded — the update was not applied."

    and have dev-menu.sh map exit 2 to skipped — aborted and anything else non-zero to FAILED. Right now the only outcome the menu can distinguish is a die().

  • scripts/ops/dev-cluster/upgrade-dev-contract.sh:68 — the local-build branch writes to ${dir}/mpc-contract-v${version}.wasm, which is the exact path the release branch treats as "already downloaded" at :47. Sequence: answer b once to smoke-test a local build, re-run and answer r → the script prints ==> Reusing … and proposes the locally built, non-reproducible WASM (from whatever the working tree happens to be at, not the $VERSION tag) as if it were the published release artifact. Nothing downstream catches it: the sha256 at :83 is printed but never compared to anything. Use distinct names per source, and do not reuse local builds:

    local wasm="${dir}/mpc-contract-v${version}.wasm"          # release
    local wasm="${dir}/mpc-contract-v${version}-local.wasm"    # build, always rebuilt

Non-blocking (nits, follow-ups, suggestions):

  • scripts/ops/dev-cluster/upgrade-dev-contract.sh:33,46 — an unrecognized MPC_WASM_SOURCE (say released) skips the interactive branch and its die at :42, then fails the == release test and silently falls into the local-build else. Validate the env value up front with the same die.
  • scripts/ops/dev-cluster/upgrade-dev-contract.sh:83 — the sha256 is printed but never checked. The release notes already publish CONTRACT_HASH (.github/workflows/release.yml:172); comparing against it (or at minimum labelling the line "compare with the release notes") turns this from decoration into the integrity check it looks like.
  • scripts/ops/dev-cluster/upgrade-dev-contract.sh:116 — a fat-fingered UpdateId calls die after the irreversible propose_update has already been sent, forcing a re-propose. dev-menu.sh:21 establishes the opposite convention for exactly this reason ("Validated here so a typo re-prompts instead of hitting die()"); re-prompt in a loop here too.
  • scripts/ops/dev-cluster/upgrade-dev-contract.sh:125 — vote failures use plain echo while the rest of the file uses warn for the same purpose, so a failed vote scrolls past uncoloured and on stdout.
  • scripts/ops/dev-cluster/dev-common.sh:29-31 — "Read by upgrade-dev-contract.sh" duplicates the function header list (Sets CONTRACT, ..., PROPOSE_DEPOSIT) and will rot; per the comment policy in CLAUDE.md it should go. What is non-obvious is where 16 comes from: (PROPOSE_UPDATE_ENTRY_OVERHEAD_BYTES + payload) * STORAGE_BYTE_COST_YOCTONEAR (crates/near-mpc-contract-interface/src/deposits.rs:14-22) = (32768 + N) * 1e-5 NEAR, so 16 NEAR covers N <= 1_567_232 — above the 1_235_000-byte cap in scripts/check-contract-wasm-size.sh:18, but only barely above the 1.5 MiB max_transaction_size. Either say that, or derive the deposit from WASM_SIZE at :86 so it cannot drift. Separately, the value is identical for both networks, so it reads oddly inside resolve_dev_cluster — a top-level constant next to SIGN_WITH (dev-common.sh:10) would fit better.
  • scripts/ops/dev-cluster/upgrade-dev-contract.sh:119 — the loop votes with the two hardcoded MEMBER_ACCOUNTS. If the cluster threshold is higher than the number of listed accounts the loop just ends and (given the blocking issue above) the run reports success. Worth surfacing explicitly rather than leaving it to the version view the operator has to eyeball.
  • scripts/ops/dev-cluster/dev-menu.sh:71 — the test signature runs against the old contract, before Step 2. A second test_sign after a successful contract update is the check that actually gates the mainnet rollout.
  • RELEASES.md:183 — the section enumerates the NOMAD_*_DEV_* / MPC_NODE_ADDRS_DEV_* knobs but not the new MPC_WASM_SOURCE / MPC_OPS_CACHE. Also worth stating the new prerequisites for Step 2: the member accounts keys in the keychain, and enough NEAR on the proposer to cover the deposit.

⚠️ Issues found

@SimonRastikian
SimonRastikian marked this pull request as draft August 9, 2026 09:33
@SimonRastikian
SimonRastikian force-pushed the 3934-dev-cluster-contract-upgrade branch from c622649 to 34cf545 Compare August 10, 2026 10:20
@SimonRastikian
SimonRastikian force-pushed the 3934-dev-cluster-contract-upgrade branch from 9c4884a to 5912d76 Compare August 10, 2026 11:44
@SimonRastikian SimonRastikian self-assigned this Aug 13, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant