Skip to content

feat(ledger): backport the ledger 8->9 hardfork to release/node-2.1.0 - #2019

Closed
ozgb wants to merge 13 commits into
release/node-2.1.0from
ozgb-backport-ledger-hf
Closed

feat(ledger): backport the ledger 8->9 hardfork to release/node-2.1.0#2019
ozgb wants to merge 13 commits into
release/node-2.1.0from
ozgb-backport-ledger-hf

Conversation

@ozgb

@ozgb ozgb commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

Overview

Backports the ledger 8 -> 9 hardfork onto the 2.1.0 release line.

The auditors are reviewing the tip of the release branch, so this is a cherry-pick
rather than a merge from main. That is the whole point of the shape of this PR:

files +/-
Merging main 526 +28,675 / −11,936
This PR 38 +1,884 / −142

No new external dependencies. Cargo.lock moves three patch versions and nothing
else enters the graph: midnight-ledger 8.1.0 → 8.1.1, midnight-storage 2.0.1 → 2.0.2
(gains the state-translation feature), midnight-zswap 8.1.0 → 8.1.1.

Feature-gating the Q3 work behind #[cfg(feature = "audit-q3")] was considered and
rejected — it would still put 526 files in front of the auditors, plus ~500 new attributes
and a second build configuration.

Commits

Three commits are verbatim cherry-picks (each carries (cherry picked from commit …), so
they can be diffed against the version already reviewed on main):

commit upstream
66b6d3552 #1925 — ledger 8→9 on-chain migration
e940464ff #2001 — ledger 8.1.1 / storage 2.0.2 bump
75019d450 #1985 — serve ledger state reads at the hardfork set_code block

#2012 was picked, then reverted — it is not in this backport

a5310e468 (squashed #2012 — reset Dust state and re-apply cNIGHT UTxOs) and its
follow-up 5b6bdc1fc are still in the branch history, but 6c9d80c39 reverts both.
#2012 is still open on main and lands there instead; this backport carries only the
ledger 8→9 state translation. Review the net diff, not commit-by-commit — the four
files #2012 added (ledger/src/host_api/dust_generation.rs,
pallets/cnight-observation/src/migrations/v2.rs, its tests, and its change file) do
not exist at the tip.

Consequences of the revert, all reflected in the tree:

  • cnight-observation STORAGE_VERSION stays at 1 — no v2 MBM, and process_tokens
    is not gated behind one.
  • RecordPreForkState is gone from Migrations/Executive; the runtime's only ledger
    migration is pallet_midnight::migrations::v2::MigrateV1ToV2.
  • Metadata was rebuilt in 7736a887e to drop the three storage items and four events
    feat: reset Dust state and re-apply cNight UTxOs during migration #2012 had added.

Deviations from the upstream PRs — please review these two closely

  1. 41196f7e3 (its own commit) — feat(ledger): ledger 8->9 hardfork on-chain migration #1925 threads a &WalletSchemes through
    fork_8_to_9_if_needed / replay_blocks_9. That parameter comes from the ECDSA work on
    main (feat(toolkit): ecdsa support #1837, feat(toolkit): ECDSA contract maintenance & deploy committees #1861), which is not on this branch. The cherry-pick merges textually
    clean
    and only fails at compile; the parameter and its three call sites are dropped.
  2. Inside 75019d450fix(ledger): serve ledger state reads at the ledger-hardfork set_code block #1985 adds a serve_pre_migration_v8_read! guard to
    get_bridge_receiving_amount. That host fn does not exist on this branch (it arrived via
    feat(c-to-m bridge): benchmarks for the bridge #1635 / feat(runtime): add Op variant for claim bridge transfers #1727), so the hunk is dropped. The other seven guarded accessors are all present
    and unchanged.

🗹 TODO before merging

  • 2.1.0 version bump — not in this PR, and required. It is all-or-nothing: spec_version
    002_001_000 needs a matching RuntimeVersion::V2_1_0 arm in
    util/toolkit/src/fetcher/runtimes.rs, which needs a MidnightMetadata2_1_0 module,
    which needs metadata/static/midnight_metadata_2.1.0.scale. Bumping only spec_version
    leaves the toolkit fetcher rejecting 002_001_000 blocks as UnsupportedBlockVersion.
    Sequence: /bot rebuild-metadata, then one commit mirroring 301ee5035.
    Without a spec_version bump the migration never fires on a live 2.0.0 chain.
  • main already occupies the 2.1.0 name — its midnight_metadata_2.1.0.scale is a
    different runtime (BABE, consensus-engine). Needs renaming as part of the main → 3.0.0
    renumber, or the two files collide by name and disagree by content.
  • Regenerate metadata on this branch — done twice: 2ff2b4406 with feat: reset Dust state and re-apply cNight UTxOs during migration #2012 in the tree,
    then 7736a887e after the revert.
  • Decide on genesis/chainspec. Nothing here touches res/. pallet-midnight
    STORAGE_VERSION 1 → 2 only affects fresh build_state genesis; the raw stagenet
    chainspecs still encode version 1, so they take the migration path.
  • Ready

📌 Submission Checklist

  • All commits are signed off (git commit -s) for the DCO — all are also GPG-signed
  • Changes are backward-compatible (or flagged if breaking) — flagged: this is a hardfork.
    MigrateV1ToV2 translates the on-chain LedgerState v13 → v18 and .expect()s on
    failure, aborting the upgrade rather than leaving a ledger-9 runtime pointing at a v8 root.
  • Pull request description explains why the change is needed
  • Self-reviewed the diff
  • I have included a change file, or skipped for this reason: three change files came across
    with the cherry-picks (the fourth left with the feat: reset Dust state and re-apply cNight UTxOs during migration #2012 revert)
  • If the changes introduce a new feature, I have bumped the node minor version — see TODO
  • Update documentation (if relevant)
  • Updated AGENTS.md if build commands, architecture, or workflows changed — n/a
  • No new todos introduced

🧪 Testing Evidence

On the post-revert tree:

  • cargo check --workspace --tests — clean

On the earlier tree of a5310e468 (i.e. with #2012 still applied — the ledger 8→9 code
under review here is unchanged since, but the cNIGHT tests it ran are gone):

  • cargo check --workspace --all-targets (SKIP_WASM_BUILD=1) — clean
  • cargo test -p pallet-midnight -p pallet-cnight-observation -p midnight-node-ledger
    168 passed, 0 failed, across 3 runs

Not yet verified:

  • The test suite has not been re-run since the revert — only cargo check. CI covers it.
  • WASM runtime build — the local attempt died on a wasm-opt-sys disk-quota error, not a
    code error. Needs a real cargo build --release. CI covers this.
  • hardfork_e2e — needs Docker plus the 1.0.1 fork-from image. feat(ledger): ledger 8->9 hardfork on-chain migration #1925 un-ignores this test
    and repoints the default FORK_FROM_NODE_IMAGE from 0.21.0 to 1.0.1; all the Earthfile
    plumbing was already present on the release branch.
  • Native-vs-WASM host-function ABI for the new migrate_state_v8_to_v9 entry.

One flake to be aware of: pallet-midnight --lib failed once on a cold build, then passed on
three subsequent runs including the identical invocation. Likely the process-global ledger
arena. Worth confirming it also flakes on unmodified release/node-2.0.0 before chasing it.

  • Additional tests are provided (if possible)

🔱 Fork Strategy

This is the fork strategy: a governance set_code on a ledger-8 chain, with the v8 → v9
state translation running as a VersionedMigration<1, 2> in the following block's
initialize_block.

Rebuilding the cNIGHT dust generating set behind it (#2012) is not part of this backport —
it needs to land separately, and until it does a forked chain comes out of the hardfork with
the ledger's dust state wiped.

  • Node Runtime Update
  • Node Client Update — new host functions and version-aware genesis arena seeding
  • Other:
  • N/A

Links

Backport of:

Deliberately excluded:

Not intentionally closing any issue — the upstream PRs already did.

Assisted-by: Claude:claude-opus-5

ozgb and others added 5 commits August 12, 2026 12:10
* feat(ledger): add v8->v9 storage migration for the ledger 8->9 hardfork

Port the v8->v9 state translation table from midnight-ledger PR #539 into
`midnight_node_ledger::state_translation_v8_to_v9`, and wire it into the
runtime as a single-block storage migration:

- New host function `Ledger9Bridge::migrate_state_v8_to_v9` reads the v8
  arena root (pallet-midnight `StateKey`), walks/translates the v8
  `LedgerState` into the v9 shape, re-persists it, and returns the new v9
  root. v8 and v9 share one storage backend, so the arena is shared.
- `pallet_midnight::migrations::v2::MigrateV1ToV2` (VersionedMigration 1->2)
  calls the host function and re-points `StateKey`. Bumped pallet-midnight
  STORAGE_VERSION 1 -> 2 and added it to the runtime `Migrations` tuple.
- Un-ignore the `hardfork_single_tx` e2e test and point its fork-from image
  at the ledger-8 release `midnightntwrk/midnight-node:1.0.1`.

Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Oscar Bailey <79094698+ozgb@users.noreply.github.com>

* test(ledger): add v8->v9 state translation table + smoke tests

- table_is_closed / table_tags_match_types guard the translation table
  against tag drift on the node's rc.3 crate versions.
- empty_state_translates_and_round_trips exercises an end-to-end v8->v9
  translation and a v9 serialize round-trip.
- Enable the helpers `can-panic` feature for ledger dev builds so the
  crate's `#[cfg(test)]` modules compile standalone.

Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Oscar Bailey <79094698+ozgb@users.noreply.github.com>

* fix(node): version-aware ledger genesis seeding for the 8->9 hardfork

A ledger-9 node booting on a ledger-8 chain-spec (the hardfork fork-from
case) panicked at startup: the arena seeder hardcoded the ledger-9
deserializer and rejected the v8 genesis (`expected ledger-state[v18], got
ledger-state[v13]`). The genesis block runs under the old WASM, so the arena
must be seeded in the genesis version.

- Add `genesis_matches_this_version` (per-version tag check) to common storage.
- Add `init_ledger_storage_{separate,unified}` dispatchers that pick the
  ledger_8 vs ledger_9 seeder by the genesis `ledger-state[vN]` tag; v8 and v9
  share one backend so a v8-seeded arena is what the post-migration v9 reads.
- Route `custom_parity_db` through the dispatchers.
- Add a dev test proving the v8-seeded root matches the fork-from chain-spec's
  genesisStateKey (no `Ledger`-wrapper drift vs release 1.0.1).

Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Oscar Bailey <79094698+ozgb@users.noreply.github.com>

* refactor(ledger): use serialize peek_tag for genesis version detection

Replace the substring header scan in `genesis_matches_this_version` with
`midnight_serialize::peek_tag`, matching the pattern used by
`contract_operation_versioned_verifier_key`. Compares the peeked header tag
against this version's `LedgerState::tag()` (no hardcoded version numbers).

Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Oscar Bailey <79094698+ozgb@users.noreply.github.com>

* fix(ledger): restore ledger-8 construct_distribute_treasury host fn

A ledger-9 node could not instantiate the ledger-8 runtime WASM (the
hardfork fork-from case): the WASM imports
`ext_ledger_8_bridge_construct_distribute_treasury_system_tx_version_1`,
which was dropped from the current ledger-8 bridge (renamed to
reserve/unlock-to-treasury for v9). Re-add it so the current node can
execute the ledger-8 runtime across the 8->9 boundary.

- ledger_8 builds `SystemTransaction::PayBlockRewardsToTreasury { amount }`
  (matching release 1.0.1); v7/v9 helpers are error stubs (only the ledger-8
  bridge exposes the host fn).
- Wire through the common Bridge and the Ledger8Bridge runtime interface.

Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Oscar Bailey <79094698+ozgb@users.noreply.github.com>

* fix(toolkit): runtime-upgrade robust to the ledger 8->9 metadata switch

`runtime-upgrade` used subxt's `wait_for_finalized_success()`, which eagerly
decodes the apply block's events. Across the 8->9 hardfork the client's
metadata follows the code swap to the new runtime, so decoding the old
runtime's `System.CodeUpdated` event fails ("Can't decode field hash ...").

Wait only for finalization (`wait_for_finalized`, no event decode) and confirm
the upgrade enacted by polling `state_getRuntimeVersion` for the spec_version
bump — no metadata-dependent decoding across the boundary.

Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Oscar Bailey <79094698+ozgb@users.noreply.github.com>

* feat(toolkit): real v8->v9 fork translation at the tx-generation boundary

The toolkit built a ledger-8 transaction for the post-hardfork (ledger-9)
chain, which the node rejected (Deserialization(Transaction):
transaction[v9]/signature[v1] vs expected transaction[v12]/signature[v2]).
Its fork-aware replay never transitioned the context ledger-8 -> ledger-9.

- Move StateTranslationTable into `midnight-node-ledger-helpers` (so both the
  runtime migration in `ledger` and the toolkit fork can use it), adding the
  onchain-state deps there.
- `fork_context_8_to_9` now runs the real `TypedTranslationState` translation
  (Db8 == Db9, one shared arena) instead of the tag-reuse `old_to_new_sp`.
- Wire the ledger-8 -> ledger-9 transition into `replay_blocks` (new
  `fork_8_to_9_if_needed`) and relax the "not supported yet" assert.
- runtime-upgrade now waits for the spec bump at the FINALIZED head (toolkit
  fetch reads only finalized blocks), so the post-fork fetch sees the ledger-9
  blocks and the replay forks to ledger 9.

Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Oscar Bailey <79094698+ozgb@users.noreply.github.com>

* chore(toolkit): TEMP hardfork_debug log for replay_blocks partition

Temporary diagnostic to see the l7/l8/l9 block partition + initial context
version during the post-fork tx build. Remove once the fork boundary is fixed.

Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Oscar Bailey <79094698+ozgb@users.noreply.github.com>

* fix(toolkit): runtime-upgrade waits for the new runtime to EXECUTE, not just apply

state_getRuntimeVersion(finalized) reports the *stored* code, which flips to the
new runtime at the apply_authorized_upgrade block — but that block still
*executes* under the old runtime (its MNSV digest, which the fetcher uses to
classify ledger version, is the old spec). The first block to run the new
runtime is apply+1. The prior poll returned at the apply block, so a downstream
fetch (bounded by finalized height) reached the apply block (still classified
ledger-8) but not apply+1, and the toolkit built a ledger-8 tx post-fork.

Track the finalized height where the stored spec first bumps, then wait for the
finalized height to advance past it (apply+1 finalized) before reporting success.

Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Oscar Bailey <79094698+ozgb@users.noreply.github.com>

* chore(toolkit): remove TEMP hardfork_debug replay_blocks log

The v8->v9 fork boundary is fixed and hardfork_e2e passes; drop the diagnostic.

Assisted-by: Claude:claude-opus-4-8
Signed-off-by: Oscar Bailey <79094698+ozgb@users.noreply.github.com>

* docs: add change files for the ledger 8->9 hardfork migration

Assisted-by: Claude:claude-sonnet-5
Signed-off-by: Oscar Bailey <79094698+ozgb@users.noreply.github.com>

* chore: cargo fmt

Signed-off-by: Oscar Bailey <79094698+ozgb@users.noreply.github.com>

* chore: fix clippy errors

Signed-off-by: Oscar Bailey <79094698+ozgb@users.noreply.github.com>

* chore: npm audit fix (toolkit-js)

Signed-off-by: Oscar Bailey <79094698+ozgb@users.noreply.github.com>

* feat: add perf prints to track migration time elapsed

Signed-off-by: Oscar Bailey <79094698+ozgb@users.noreply.github.com>

* feat: use ledger cost model for storage migration

Signed-off-by: Oscar Bailey <79094698+ozgb@users.noreply.github.com>

* chore(local-environment): npm audit fix

Signed-off-by: Oscar Bailey <79094698+ozgb@users.noreply.github.com>

* fix: no-op ledger v8->v9 migration when state is already ledger-9

The 2.0.0 runtime runs ledger-9 but shipped pallet-midnight at storage
version 1 (it had no v1->v2 migration), so a network upgrading 2.0.0 ->
this runtime still fires VersionedMigration<1,2> over an already-v9
StateKey. Feeding that v9 root to the v8 decode path fails on the tag
mismatch and the pallet's expect() panics, bricking the upgrade block.

Guard migrate_state_v8_to_v9 so it no-ops when the StateKey already
references a ledger-9 state: detect it by the arena root's serialized tag
(distinct between ledger-state[v13] and [v18]) and return the key
unchanged with zero synthetic cost, leaving only the storage-version bump.

Assisted-by: Claude:claude-fable-5
Signed-off-by: Oscar Bailey <79094698+ozgb@users.noreply.github.com>

* docs: update change file

Signed-off-by: Oscar Bailey <79094698+ozgb@users.noreply.github.com>

---------

Signed-off-by: Oscar Bailey <79094698+ozgb@users.noreply.github.com>
Co-authored-by: Squirrel <giles.cope@shielded.io>
(cherry picked from commit 74a9115)
Assisted-by: Claude:claude-opus-5
Signed-off-by: Oscar Bailey <79094698+ozgb@users.noreply.github.com>
#1925 threads a `&WalletSchemes` through `fork_8_to_9_if_needed` and
`replay_blocks_9`. That parameter comes from the ECDSA work on main
(#1837, #1861), which is not on release/node-2.0.0, so the cherry-pick
merges textually clean and only fails at compile. Drop the parameter and
its three call sites; wallet-scheme selection does not exist on this
branch and nothing else in the fork path reads it.

Adaptation of the cherry-pick, not an upstream change.

Assisted-by: Claude:claude-opus-5
Signed-off-by: Oscar Bailey <79094698+ozgb@users.noreply.github.com>
Signed-off-by: Giles Cope <gilescope@gmail.com>
Signed-off-by: Oscar Bailey <79094698+ozgb@users.noreply.github.com>

# Conflicts:
#	Cargo.lock
#	Cargo.toml

Co-authored-by: Giles Cope <gilescope@gmail.com>
(cherry picked from commit 6fb0cc0)
Assisted-by: Claude:claude-opus-5
Signed-off-by: Oscar Bailey <79094698+ozgb@users.noreply.github.com>
… block (#1985)

* fix(ledger): serve ledger state reads at the ledger-hardfork set_code block

On a chain that hardforks ledger 8 -> 9 via a governance `set_code`, exactly one
historical block is permanently unreadable: every ledger state read at that hash
fails with `Deserialization(TypedArenaKey)` (GH #1959). The pre-fork runtime
ships `system_version: 1`, so `frame_system` overwrites `:code` *inside* the
`set_code` block, while pallet-midnight's v8 -> v9 state translation only runs in
the next block's `initialize_block`. That block's committed state therefore pairs
ledger-9 `:code` with a ledger-8 `StateKey` forever, and reading it executes
ledger-9 code against a ledger-8 arena root.

The read-only accessors of the ledger-9 host API now check the
tagged-serialization header of the `state_key` they are handed and, when it is a
ledger-8 arena root, serve the read from the ledger-8 bridge — which is what the
state at that block actually is. v8 and v9 share one storage crate and hence one
arena, so this is a pure dispatch with no data movement. The `StateKey` tag is
the signal rather than the pallet storage version, because the 2.0.0 runtime
already ran ledger 9 while still reporting pallet-midnight storage version 1.

Guarded accessors: get_contract_state, get_zswap_chain_state,
get_zswap_state_root, get_ledger_state_root, get_ledger_parameters,
get_c_to_m_bridge_min_amount, get_unclaimed_amount,
get_bridge_receiving_amount.

Placing the dispatch in the host function rather than in the node's JSON-RPC
layer covers every caller at once: the `midnight_*` RPCs, `MidnightRuntimeApi`
through `state_call`, and subxt-based tooling such as chain-indexer (GH #1969),
none of which touch the node's RPC handlers. The transaction paths are
deliberately left alone — at the skew block they concern ledger-9-format
transactions that ledger-8 code cannot deserialize in any case, and they resolve
on their own one block later; this is documented at `get_transaction_cost`.

hardfork_e2e now walks the fork boundary and asserts both the `midnight_*` RPCs
and a raw `state_call` answer at `applied - 1`, `applied` and `applied + 1`.

Assisted-by: Claude:claude-opus-5
Signed-off-by: Oscar Bailey <79094698+ozgb@users.noreply.github.com>

* chore: point change file at the new PR

Assisted-by: Claude:claude-opus-5
Signed-off-by: Oscar Bailey <79094698+ozgb@users.noreply.github.com>

* docs: tighten doc comment

Signed-off-by: Oscar Bailey <79094698+ozgb@users.noreply.github.com>

* docs: newline

Signed-off-by: Oscar Bailey <79094698+ozgb@users.noreply.github.com>

---------

Signed-off-by: Oscar Bailey <79094698+ozgb@users.noreply.github.com>
(cherry picked from commit 54dffa0)
Assisted-by: Claude:claude-opus-5
Signed-off-by: Oscar Bailey <79094698+ozgb@users.noreply.github.com>
)

Squashed backport of the ozgb-cnight-mbm branch (PR #2012), which is
still open on main. The ledger 8->9 state translation wipes the ledger's
dust state; this rebuilds cNIGHT's slice of the dust generating set as a
multi-block migration driven from `UtxoOwners` plus the retained v8
arena root, backdating each replayed ctime to the DUST cap.

Squashed rather than cherry-picked commit-by-commit because the branch
contains a merge from main (16f07a8) that would drag in unrelated
changes.

PR: #2012

Assisted-by: Claude:claude-opus-5
Signed-off-by: Oscar Bailey <79094698+ozgb@users.noreply.github.com>
@ozgb
ozgb requested a review from a team as a code owner August 12, 2026 11:19
@ozgb ozgb added the bot:ai-assisted Authored or substantially edited by an AI agent label Aug 12, 2026
The change file came across from the still-open #2012, which left the
`PR:` field as a placeholder.

Assisted-by: Claude:claude-opus-5
Signed-off-by: Oscar Bailey <79094698+ozgb@users.noreply.github.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a5310e4685

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread runtime/src/lib.rs
@datadog-official

This comment has been minimized.

ozgb added 2 commits August 12, 2026 14:51
Signed-off-by: Oscar Bailey <79094698+ozgb@users.noreply.github.com>
Signed-off-by: Oscar Bailey <79094698+ozgb@users.noreply.github.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f6b1d1f801

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread pallets/cnight-observation/src/migrations/v2.rs Outdated
Comment thread pallets/cnight-observation/src/migrations/v2.rs Outdated
ozgb added 4 commits August 13, 2026 11:30
Signed-off-by: Oscar Bailey <79094698+ozgb@users.noreply.github.com>
Reverts a5310e4 ("feat: reset Dust state and re-apply cNight UTxOs
during migration (#2012)") and its follow-up 5b6bdc1, backing the
cNIGHT dust generation replay out of the ledger-hardfork backport.
PR #2012 is still open on main, so it lands there rather than here.

Note: `metadata/static/midnight_metadata*.scale` were regenerated in
2ff2b44 while the reverted storage items (`PreForkStateKey`,
`DustReapplyCtime`, `DustReapplyProgress`) were present, so metadata
needs a rebuild.

Assisted-by: Claude:claude-opus-5
Signed-off-by: Oscar Bailey <79094698+ozgb@users.noreply.github.com>
Signed-off-by: Oscar Bailey <79094698+ozgb@users.noreply.github.com>
Signed-off-by: Oscar Bailey <79094698+ozgb@users.noreply.github.com>
* chore: update npm to fix toolkit SBOM error

Signed-off-by: Oscar Bailey <79094698+ozgb@users.noreply.github.com>

* docs: add change file

Signed-off-by: Oscar Bailey <79094698+ozgb@users.noreply.github.com>

---------

Signed-off-by: Oscar Bailey <79094698+ozgb@users.noreply.github.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 5da44a54e6

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

&mut self,
state_key: PassFatPointerAndRead<&[u8]>,
) -> AllocateAndReturnByCodec<Result<Vec<u8>, LedgerApiError>> {
serve_pre_migration_v8_read!(*self, state_key, get_ledger_parameters(state_key));

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Keep ledger-version reads fork-aware

When this branch is taken at the ledger 8→9 code-applied block, get_ledger_parameters returns the ledger-8 bridge's v8-tagged bytes, but MidnightRuntimeApi_get_ledger_version / midnight_getLedgerVersion(at) still use the unchanged ledger-9 get_version() path because it has no state-key guard. Callers that query the version API at that same hash to choose decoders will be told ledger 9 and then fail to decode these v8-tagged responses; make version reporting inspect StateKey or the block's execution-version digest for the skew block too.

Useful? React with 👍 / 👎.

@ozgb

ozgb commented Aug 17, 2026

Copy link
Copy Markdown
Contributor Author

Closing in favour of #2023

@ozgb ozgb closed this Aug 17, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bot:ai-assisted Authored or substantially edited by an AI agent skip-changes-check-all

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants