Add differential upgrade compatibility gate - #1
Open
devchant wants to merge 2 commits into
Open
Conversation
devchant
force-pushed
the
fix/issue-upgrade-compatibility-gate
branch
from
August 23, 2026 11:52
37d8078 to
bea9412
Compare
devchant
force-pushed
the
fix/issue-upgrade-compatibility-gate
branch
from
August 23, 2026 11:54
bea9412 to
2cd3f35
Compare
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.
Problem
A successful WASM upload or compilation does not prove that a contract upgrade preserves live storage interpretation, authorization decisions, error behavior, event contracts, or accounting invariants. The existing execution path checked only the proposal hash, admin authorization, and cooldown before replacing the WASM.
Closes: Hub-of-Evolution#1008
Solution
This PR adds a fail-closed compatibility gate at the irreversible upgrade boundary.
UpgradeCompatibilityManifest, keyed by the exact proposed WASM hash.UpgradeStateSnapshotandget_upgrade_state_commitmentfor deterministic representative-state commitments covering contract version, escrow count, recurring escrow allocation, signer threshold, paused state, and onboarding configuration.submit_upgrade_compatibility_manifestandget_upgrade_compatibility_manifest.update_current_contract_wasmis called.UpgradeHistoryand removes the manifest only after successful version/history updates.Files Changed
craft-nexus-contract/src/lib.rs: compatibility types, storage key, snapshot/manifest APIs, execution gate, error codes, and audit metadata.craft-nexus-contract/src/test.rs: missing-manifest rejection and successful manifest consumption/history assertions.craft-nexus-contract/docs/versioned-state-migration.md: operator workflow and CI/release expectations.Technical Decisions
The manifest is stored separately from
WasmUpgradeProposalto preserve compatibility with existing proposal records and callers. The chain validates the manifest against the current version and live snapshot commitment, while isolated tooling remains responsible for running the old/new artifacts and producing interface, authorization, invariant, event, and error evidence. A non-zero checkpoint and explicitmanual_records == 0make incomplete migration handling visible and fail closed.Validation
git diff --check: passed.cargo,rustc, andrustupare not installed. The repository commands are documented incraft-nexus-contract/scripts/test.shandcraft-nexus-contract/scripts/build.sh.Limitations and Follow-up
The on-chain contract cannot execute two WASM artifacts in an isolated simulation. The manifest therefore commits the results of external differential tooling rather than attempting to reproduce that environment on-chain. CI should wire the differential fixture/invariant runner to fail artifact publication when those commitments are not produced. Existing legacy records still require the migration runner to generate truthful commitments; the contract intentionally does not infer compatibility from storage shape alone.
No issue number was supplied with the request, so no issue-closing tag is included.
Closes Hub-of-Evolution#1008