From b8444449f1140f51dbdd0621ddbfa17d4fb8b4cf Mon Sep 17 00:00:00 2001 From: Marcel Ebert Date: Tue, 8 Sep 2026 16:23:15 +0200 Subject: [PATCH 1/3] docs: Record the published spec-26 artifact and its drills --- docs/pen-migration-internal-review.md | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/docs/pen-migration-internal-review.md b/docs/pen-migration-internal-review.md index 8d5e2b15d..ba18d429a 100644 --- a/docs/pen-migration-internal-review.md +++ b/docs/pen-migration-internal-review.md @@ -848,6 +848,29 @@ ships-paused with no storage written. **RB-5 passed 5/5**: the wasm written to attestor decoded post-upgrade blocks without a restart and rode a node restart. Dev-machine benchmark weights were accepted as production weights. +### Published spec-26 artifact (2026-09-08) + +Built reproducibly by the new `Release Runtime` workflow (srtool v0.17.0, +rustc 1.81.0) from the tagged commit `14eb720` and published as +[pendulum-release-26](https://github.com/pendulum-chain/pendulum/releases/tag/pendulum-release-26) +together with the srtool report. Verified locally: the downloaded wasm's +sha256 equals the report's, and the embedded version is spec 26 / +transaction_version 11. + +| | | +|---|---| +| `pendulum_runtime.compact.compressed.wasm` | 2,177,219 bytes | +| sha256 | `370ac425e69125ac3d23971a1d2eba7966b15c7026621dd6a778c099432eb66d` | +| blake2_256 (code hash) | `0x6a19a408826fb4d2ab04886c864714dda188df2a1bfa11f27b1b2d0c0192e896` | +| democracy proposal hash | `0x830dd2349bf421f430b068e1361010b33dfaf8d38e8c9465cd95ee7cd378a0bf` | +| `parachainSystem.authorizeUpgrade` hash | `0xf6cd1f4a600906a31f305ea0a8401ca31f84afa52b9fa31d31d35cde406b6ebf` | + +Against **this** binary — the thing to be shipped, not a local build — the +fork reports spec 26, **phase 2 passed 14/14** and **RB-5 passed 5/5**. +Anyone can reproduce the hashes from the same commit with +`paritytech/srtool:1.81.0`. The referendum text should carry the code hash +and the proposal hash above. + ## Residual risks and standing practices (no external audit — risk accepted) - Every change to the fund-release path (vault release/approve/sweep logic, pallet burn path) gets a fresh independent adversarial review round before From 1f9763bf111138259690292bca14c7fe5b1be76e Mon Sep 17 00:00:00 2001 From: Marcel Ebert Date: Mon, 14 Sep 2026 17:06:19 +0200 Subject: [PATCH 2/3] docs: Add the enactAuthorizedUpgrade step and hash guidance to RB-5 The referendum only authorizes the code hash; the upgrade happens when anyone submits parachainSystem.enactAuthorizedUpgrade with the published wasm. Record that step, the verification after it, the preimage deposit reclaim, and which of the release report's hashes is the one the chain checks. --- docs/pen-migration-runbooks.md | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/docs/pen-migration-runbooks.md b/docs/pen-migration-runbooks.md index 34ffec5e4..a7dfab676 100644 --- a/docs/pen-migration-runbooks.md +++ b/docs/pen-migration-runbooks.md @@ -154,12 +154,32 @@ Before the upgrade is enacted: migration touching `NextNonce` storage must preserve it; reject one that doesn't. -After enactment: -4. Watch the fleet: all four daemons progressing past the upgrade block, test - migration of a small amount end-to-end, monitor `ok` lines resuming. -5. If daemons exit on the upgrade block: they hold position (checkpoint stays +When the referendum enacts (`parachainSystem.authorizeUpgrade(code_hash, +check_version = true)` executes — this only *authorizes* the hash): +4. **Enact it.** Anyone submits `parachainSystem.enactAuthorizedUpgrade(code)` + with the full published wasm (`pendulum_runtime.compact.compressed.wasm` + from the GitHub release, ~2.2 MB; the length fee is well under 1 PEN). The + call verifies `blake2_256(code)` against the authorized hash and, with + `check_version`, that the new `spec_version` is higher; it then signals the + upgrade to the relay chain, which applies it after its validation delay. + Nothing happens until this call is sent. Verify afterwards: + `system.lastRuntimeUpgrade` reports the new spec, `tokenMigration.paused()` + is `true`, and `parachainSystem.authorizedUpgrade` is cleared. +5. Reclaim the preimage deposit: `preimage.unnotePreimage(hash)` from the + account that noted it (the deposit is returned once the preimage is unused). +6. Watch the fleet: all four daemons progressing past the upgrade block, test + migration of a small amount end-to-end (only after the governance unpause), + monitor `ok` lines resuming. +7. If daemons exit on the upgrade block: they hold position (checkpoint stays put) — fix decoding, redeploy, they resume without loss. +**Which hash goes where.** The release's srtool report lists several hashes. +`parachainSystem.authorizeUpgrade` takes the **code hash** — `blake2_256` of +the wasm file (the value `enactAuthorizedUpgrade` recomputes from the bytes). +The report's `proposal_hash` is the preimage hash of a `system.setCode` call +and its `parachain_authorize_upgrade_hash` is derived from the authorize +*call*; neither is what the pallet checks at enactment. + ## RB-7: Window close and remainder sweep **Trigger:** the migration window is closing (per decision D5) and governance From e4e8cb3496a2d6b540e12a9ed86dcc8c85584094 Mon Sep 17 00:00:00 2001 From: Marcel Ebert Date: Mon, 14 Sep 2026 17:06:19 +0200 Subject: [PATCH 3/3] ci: Say which release hash authorizeUpgrade takes The srtool report lists three hashes; only blake2_256 of the wasm is what enactAuthorizedUpgrade recomputes. Spell that out in the generated notes. --- .github/workflows/release.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 8ee997a4d..0dfa3a589 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -80,6 +80,8 @@ jobs: echo echo "Commit: \`${{ github.sha }}\` · srtool image: \`paritytech/srtool:1.81.0\` · reproduce with the same commit and image." echo + echo "For \`parachainSystem.authorizeUpgrade\` use **\`blake2_256\`** below (the code hash the chain recomputes from the wasm at enactment); \`proposal_hash\` is the preimage hash of a \`system.setCode\` call and \`parachain_authorize_upgrade_hash\` is derived from the authorize call — neither is the value to authorize." + echo echo '```json' jq '.runtimes.compressed.subwasm // .' srtool-${{ steps.meta.outputs.chain }}.json echo '```'