Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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 '```'
Expand Down
23 changes: 23 additions & 0 deletions docs/pen-migration-internal-review.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
28 changes: 24 additions & 4 deletions docs/pen-migration-runbooks.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Loading