node-2.1.0-rc.3
Pre-releaseGit tag: node-2.1.0-rc.3
Components
- 📦
node-2.1.0 - 🧰
toolkit-2.1.0 - ⚙️
runtime-2.1.0
Added
Add Initial CI for fork testing (#1353)
Adds a CI action for forking a known network using a node snapshot, and spinning up equal nodes for that network safely using mock keys
PR: #1353
Changed
Bound GRANDPA and BEEFY finality subscription fan-out (#1075, PM-19967) (#node)
Add per-connection and global subscription limits with bounded notification
channels for GRANDPA and BEEFY RPC handlers. Prevents resource exhaustion
from unbounded fan-out of consensus notifications.
Fixes: #1319
PR: #1075
JIRA: https://shielded.atlassian.net/browse/PM-19967
Enforce derivation path role validation in wallet constructors (#1076, PM-20015) (#toolkit)
Add regression tests verifying that DustWallet::from_path() and
ShieldedWallet::from_path() reject derivation paths with mismatched
roles. Addresses Least Authority audit Issue AN.
Issue: #1327
PR: #1076
JIRA: https://shielded.atlassian.net/browse/PM-20015
Enforce TLS certificate and hostname validation for DB connections (#1104, PM-22023) (#node)
Set ssl_mode to PgSslMode::VerifyFull in get_connection and reject
insecure SSL modes (Prefer, Disable) to prevent plaintext database
transport and unauthenticated TLS connections.
Fixes: #1320
PR: #1104
JIRA: https://shielded.atlassian.net/browse/PM-22023
Verify removal of WalletSeed Default implementation (#1109, PM-22024) (#ledger)
Verify the audit finding (A2 Issue D) remediation from PR #804 that removed
the all-zero Default implementation for WalletSeed. Confirms no residual
zero-seed usage in key derivation paths.
PR: #1109
Issue: https://github.com/midnight-security/midnight-security/issues/112
JIRA: https://shielded.atlassian.net/browse/PM-22024
Configuration for Cardano-to-Midnight bridge (#1333) (#node, #runtime)
Enables chain-spec build / genesis block creation to include subminimal transfers config.
Adds subminimal transfer config to runtime api that sets bridge configuration.
Enables Bridge operations in the local-environment.
Fixes Reserve Transfer classification (#1513) (#node, #runtime)
Before this change Bridge was using transaction metadata as criterium of classifying transfers.
It would allow attack on M.R pool.
This PR modifies observability to distinguish Reserve Validator and ICS Validator inputs of the transaction to correctly classify transfer.
In the edge case one Cardano Tx can be ReserveTransfer and User Transfer at same time.
When node with this update is deployed, it will not be able to read MainChainScripts of the bridge pallet and inherent data provider will report Inert variant of IDP.
Bridge is not complete and non environment should have it configured, so everywhere the IDP should be Inert as well.
Governance action setting these addresses and data checkpoint will be required to enable the bridge.
Add commands for initiating bridge transfers. (#1340) (#toolkit)
Adds bridge-transfer command that submits transaction to Cardano. Transaction is from user wallet to ICS address and has metadata that encodes either: transfer to specified Midnight UserAddress, to reserve or invalid one (will end up in Treasury).
Route bot PRs to the canonical bot:* labels (#2025)
Dependabot now applies bot:github-actions or bot:dependencies per ecosystem instead of the tool defaults, and the changes checks exempt the canonical names as well as the legacy ones.
Return ContractNotPresent error for missing contracts (#916) (#node)
Return an explicit ContractNotPresent error when querying the state of a non-existent contract address, instead of returning a default empty state. This allows callers to distinguish between an empty contract and a missing one.
Make CNight observation mock deterministic for multi-node networks (#1870) (#node, #runtime)
The CNight observation data source mock now generates deterministic data based on block number instead of random data. This ensures all nodes in a multi-node network produce identical inherent data, preventing block verification failures.
Changes:
- Replaced random UTXO generation with deterministic generation seeded by block number
- All nodes with the same block number now generate identical mock CNight observations
- Prevents "inherent data mismatch" errors in multi-node development setups
Technical Details:
- Deterministic hash generation based on block number and salt
- Consistent reward addresses and dust public keys across all nodes
- Maintains compatibility with single-node development mode
This fix enables running local multi-node networks in development mode without Cardano infrastructure.
PR: #1870
Fix environments configuration files and genesis state generation process to prevent empty locked pool (#1675) (#toolkit, #runtime)
Makes all /res Reserve and ICS configs valid (non zero values). All genesis files and chain-specs, with known exception for Preview, have non empty locked pool amount.
Removes logic that assigned MAX_SUPPLY - treasury to the reserve_pool leaving locked_pool empty in absence of reserve config.
Now, if reserve config is absent, the reserve pool would be empty. Genesis state will likely fail in such a case, because
funding seeds would fail.
Therefore there will be --allow-empty-pools flag required if any pool or treasury is empty.
Future chain-spec generation should not create specs with empty locked pool if some config was omitted.
All environments are now configured to mimic mainnet amounts configuration in regards to Midnight Genesis reserve, locked and treasury pools.
Durable environments genesis states and chain-specs are not re-created. We keep chain-spec as on environment and genesis-state consistent with chain-specs. This is way CI likes.
Currently there is discrepancy between pool amounts in config for Preview environment only. Preview needs reset and new chain-spec will be correct if generated from current config files.
Replace panic with error handling in cnight-observation inherent data decoding (#1234, PM-21799) (#node, #runtime)
The get_data_from_inherent_data function in the cnight-observation pallet
used .expect() on inherent data decoding, which could cause all validators
to panic simultaneously on malformed data, halting the chain. This replaces
the panic with typed Result<Option<...>, InherentError> error handling
using a new DecodeFailed variant, matching the pattern already established
in the sibling federated-authority-observation pallet.
Fixes: #1317
PR: #1234
JIRA: https://shielded.atlassian.net/browse/PM-21799
Fix motion removal on failed dispatch in federated-authority pallet (#938, PM-22085) (#audit, #runtime)
The motion_close extrinsic previously propagated the dispatch error via
motion_result?, causing Substrate's transactional storage layer to roll
back motion_remove when the dispatched call failed. Approved-but-failed
motions became permanently stuck in on-chain storage with no recovery path.
The fix removes dispatch error propagation so motion_close always succeeds
once the motion is approved, with the dispatch outcome captured in the
MotionDispatched event. Also removes three unused error variants
(MotionTooEarlyToClose, MotionAlreadyExists, MotionExpired).
Fixes: #1318
PR: #938
JIRA: https://shielded.atlassian.net/browse/PM-22085
Run local-environment natively on arm64 (#1874)
Makes the local-environment stack run fully native on arm64 hosts:
- Adds a
busybox-initservice that copies an arch-matching static busybox from the
multi-archbusyboximage into the shared volume, replacing the previously vendored
amd64-only binary (which crashedcardano-node-1with "Exec format error" on arm64
once the container ran native). Docker resolves the arch, so no per-arch binaries
are committed. - Switches
db-syncto the multi-archcardano-db-syncimage and itsplatform
to${ARCHITECTURE}, so it runs native instead of under emulation. This uses a
temporary branch build (db-sync 13.7.2.1) until a multi-arch release ships.
Add local-files secrets mode for mock authorities (#1287)
Support reading validator seed files from disk (generated by the mock-authorities tool)
instead of fetching secrets from Kubernetes pods. Also resolves boot node statefulset
name and PVC name from network config for the snapshot command.
PR: #1287
Remove internal Kubernetes and AWS coupling from local-environment (#1470)
Cleans up the local-environment/ tooling so it can be run without
Kubernetes or AWS access. Removes the snapshot command and its
supporting modules (connectToPostgres, getSecretsForEnv, keystore,
portForwardWatchdog, previewProxy, snapshotEnv), which fetched
secrets from cluster pods and uploaded archives to S3. Adds
mockAuthorities and mockComposeOverride so well-known networks can
be forked locally from a snapshot URI using mock validators instead.
▹ Ledger 9 support (#1604) (#node, #runtime, #toolkit)
▹ Removal of unused partner chains pallets and related commands (#1562) (#runtime, #node)
Remove local-env and e2e-tests in partner-chains (#1351) (#partner-chains)
Local-env and e2e-tests has been removed. These were not run in CI and are (or should be) redundant,
because Midnight node e2e-tests ought to test all functionalities.
▹ Update Rust toolchain to 1.98.1 (#2166) (#node, #toolkit, #runtime)
▹ Improve wallet seed, key pair, and address code quality (#1217, PM-22038) (#toolkit, #ledger)
📦 Node
Git tag: node-2.1.0-rc.3
Docker Images
DockerHub
$ docker pull ghcr.io/midnightntwrk/midnight-node:2.1.0-rc.3Added
▹ Add e2e regression coverage for genesis_extrinsics parsing (#1516) (#audit, #tests, #ci)
▹ Add indexer-side assertions to c2m_bridge e2e tests (opt-in) (#1718) (#tests, #c2m-bridge, #indexer)
▹ Log on each session change whether this validator is in the committee (#1534) (#node)
▹ Add per-test tracing logger to the e2e suite (#1564) (#tests)
▹ Non-validator archive node in the local-env stack (#2058) (#local-env)
▹ Let downstream repos run against a local-environment fork (#1920) (#node, #local-env)
▹ Add local fork-testing support for the 1.0.0 release train (#1522)
▹ Restore from-genesis bring-up for well-known networks in local-env tooling (#1807)
▹ Add --num-validators to run a smaller mock authority set in local-env forks (#2008) (#node, #local-env)
▹ Add local network for the local-environment, bridge-funded at runtime (#1796) (#node, #local-env)
▹ Add Midnight-specific reference hardware profile for benchmark machine checks (#1511) (#node)
▹ Add CI guard protecting frozen res/ network config (#1732) (#ci)
▹ Add stagenet network genesis and chain specs (#1707) (#node)
Changed
▹ Eliminate deadlock in LedgerContext::with_wallets_from_seeds (R-059) (#1471, PM-21800) (#ledger, #helpers)
▹ Return BeneficiaryNotFound for absent beneficiaries in get_unclaimed_amount (#1359, PM-21801) (#ledger, #rpc)
▹ Use ledger 9 apply_guaranteed_only for guaranteed-segment validation (#1454) (#node)
▹ Surface ContractNotPresent through midnight_contractState RPC (#1475) (#audit, #rpc)
Restore the preview chain-spec that live preview actually runs (#node)
Preview was reset in June 2026 (#1690) to fix an empty Locked pool, and the regenerated
chain-spec and genesis state landed in #1699 — but only on release/node-1.0.1. The 2.x line
branched before that, so release/node-2.1.0 still shipped the pre-reset artifacts.
A preview node brought up from an empty disk using res/preview/ computed genesis
0x801d…b880 instead of live preview's 0x3c096de2…6dd13796, was rejected by every bootnode as
a different chain, and sat at block #0 with no peers. Nodes already running were unaffected —
their genesis is on disk.
Forward-ports the five artifacts from release/node-1.0.1, leaving res/preview/ byte-identical
to the branch preview runs. The input configs (ics-config.json, reserve-config.json) already
matched and are untouched.
Issue: #1690
▹ Default block_stability_margin to 30 across all config presets (#1914) (#node, #config)
▹ Bump AL2023 base image to clear critical unbound CVE (#2207) (#node, #docker, #security)
▹ Bump ledger 8 version to 8.1.2 (#2096)
▹ Bump ledger 9 version to 9.1.0.0-rc.5 (#2096) (#node, #runtime, #toolkit)
▹ Improve cnight-observation genesis panic diagnostics (#1466, PM-19896) (#audit, #hardening)
▹ Order observed cNIGHT UTXOs by data variant, gated on spec_version (#2123) (#node, #cnight, #consensus)
▹ Skip committee-membership logs when SessionInfoApi is absent (#2204) (#node)
▹ Restore cNIGHT observation coverage against Cardano Preview (#1578, #1613) (#tests)
▹ Decouple qanet e2e tests from local-env docker artefacts (#1666) (#node, #tests)
▹ Read e2e test contract values from runtime-values instead of hardcoded CBOR (#1348) (#node, #tests)
▹ Implement e2e tests for C-to-M bridge (#1654) (#tests)
▹ Split e2e test suite into per-topic module files (#1565) (#tests)
▹ Handling ledger transaction execution errors (#1980) (#node, #c2m-bridge)
▹ Fix handling of c2m-bridge transaction that have recipient address too short (#2185) (#node, #c2m-bridge)
▹ Make fork-network full-upgrade mode resolve a reachable RPC endpoint (#2032)
▹ Add governance runtime upgrade option to fork-network workflow (#1676)
▹ Add node upgrade option to fork-network workflow (#1469)
Fix fork-network runtime upgrade hang connecting to the forked node
The fork-network workflow's runtime upgrade mode could hang until the
45-minute job timeout at "Connecting to node at ws://localhost:9950". The forked
chain is healthy the whole time (all validators up, RPC bound, producing and
finalizing blocks) — the problem is that on some self-hosted runners the host
loopback -> docker-published-port path is black-holed (e.g. Docker started with
userland-proxy disabled): the SYN is silently dropped, so the polkadot-js
WsProvider — which has no connect timeout of its own — never establishes and
never errors. image mode is unaffected because it never opens a WsProvider.
The runtime step now brings the fork up first, then connects to whichever RPC
endpoint actually answers — preferring the published port but falling back to
node1's docker bridge IP, which is routable from the runner regardless of the
loopback/DNAT setup — and reuses that endpoint for the finality-wait and
:code verification steps. As defense-in-depth, createApi in the
local-environment tooling now fails fast with an actionable error after a bounded
connect timeout (API_CONNECT_TIMEOUT_MS), and its DEFAULT_RPC_URL uses an
explicit IPv4 host. full mode
brings the fork up internally (no --skip-run) so it still relies on the
published port; making it robust needs a follow-up tooling change.
PR:
Issue:
▹ Surface nested ledger error variants in flat error enums (#1449) (#node)
▹ Serve ledger state reads at the ledger-hardfork set_code block (#1985) (#node, #ledger)
▹ Stop duplicating binaries and res/ in a second image layer (#2048) (#node, #toolkit, #docker)
▹ Incomplete zeroization after conversion to ordinary buffers (PM-22034, #1379) (#node, #toolkit)
▹ Bump ledger to 9.1.0.0-rc.2 (#1692) (#node, #runtime, #toolkit)
▹ Bump ledger to 9.1.0.0-rc.3 (#1738) (#node, #runtime, #toolkit)
▹ Bump ledger to 9.1.0.0-rc.4 (#2022) (#node, #runtime, #toolkit)
▹ Pin ledger 9.1.0.0-rc.5 per crate instead of by the workspace tag (#2134) (#node, #runtime, #toolkit)
▹ Add get_bridge_receiving_amount ledger host API (#1766) (#ledger)
▹ Patch cnight mapping_validator_address from freshly compiled contracts (#1653) (#node, #local-env)
▹ Fix GRANDPA finality stall when forking a >=2.0.0 network in local-env (#2008) (#node, #local-env)
▹ Enable qanet --from-genesis by exposing its validator seed references (#2032)
▹ Cache repeated mainchain-follower inherent reads during node sync (#1551) (#node)
▹ Do not ban peers when local Cardano observation lags during block verification (#1472) (#node)
▹ Reject block headers carrying duplicate main chain reference hash digests (#1617) (#node)
▹ Run nightly cNIGHT e2e job inside a container (#1658) (#tests, #ci)
▹ parity-db: Midnight fork, lower flush threshold, ahash (#1, #2, #1478) (#node)
▹ Switch polkadot-sdk to the shieldedtech fork of stable2606 with TCP_NODELAY on RPC sockets (#2200) (#rpc, #dependencies)
▹ Update Polkadot SDK toward polkadot-stable2606 (#1790) (#node, #runtime)
▹ Prevalidate post-block-update after each ledger 9 transaction (#1448) (#node, #runtime)
▹ Log transaction rejection reasons via Display rather than Debug (#2105) (#logging, #hygiene)
▹ Remove unused and outdated network ddosnet (#1343) (#chainspec)
▹ Remove gdb from the node and hardfork-test-upgrader images (#2187) (#node, #docker, #security)
▹ Remove ledger 7 support (#1999) (#node, #toolkit, #runtime)
▹ Fix reserve-contracts CLI governance-update txs on local-env (Ogmios 3002) (#1934) (#fix, #tooling)
▹ Revert the cNIGHT observation sliding-window cache (#2030) (#node)
▹ Revert the 16x reduction in cNIGHT observation UTXO over-fetch (#1367) (#node, #runtime)
▹ Silence cNIGHT observation logs for unregistered and non-base Cardano addresses (#1324) (#node)
▹ Reject incoherent mainchain timing configuration (PM-20013, #1656) (#audit, #node, #hardening)
▹ Give each ledger version its own copy of the ledger helpers (#2074) (#node, #refactor)
▹ Give each ledger version its own copy of the wrapper code (#2059) (#node, #refactor)
▹ Run hardware benchmarks on node startup (#1394) (#node)
▹ Log sanitized db-sync startup probe results (#1411) (#node)
▹ New storage_separation config option to use a single ParityDb instance (#1278) (#storage)
▹ Edge-case tests for c2m-bridge subminimal-transfer accumulation (#1677) (#tests)
▹ Tune autovacuum on db-sync hot tables for stable query plans (#1434) (#node)
▹ Use the upstream ledger v8->v9 state translation crate (#2054) (#hardfork, #ledger)
⚙️ Runtime
Git tag: runtime-2.1.0-rc.3
Added
▹ Added benchmarks and weights of pallet_c2m_bridge and pallet_partner_chains_bridge (#1635) (#runtime)
▹ Add optional approved_txs to c2m-bridge genesis config (#1809) (#runtime, #c2m-bridge)
▹ Added c2m-bridge pallet (#1386) (#runtime)
▹ Add root extrinsics to set cNIGHT contract identifiers (#1602) (#runtime)
▹ Re-apply cNIGHT dust generation after the ledger 8 -> 9 hardfork (#2012) (#cnight, #dust, #migration)
▹ Log an error on session change when the D-parameter is below the permissioned candidate count (#1506) (#runtime)
▹ Add SessionInfoApi runtime API exposing the substrate session index (#1534) (#runtime)
Changed
▹ Close runtime benchmark coverage gaps before the 2.1.0 weights run (#2160) (#runtime)
Use `apply_post_block_update` in `pallet_midnight` `on_finalize` (#runtime)
This change makes on_finalize use function that has theoretically one way less to fail.
In practice the error couldn't happen becase block fullness is checked for each included transaction.
▹ C-to-M bridge pre-approvals filter (#1477) (#runtime)
▹ C-to-M bridge holds subminimal transfers (#1393) (#runtime)
▹ Ad Op variant for ClaimBridgeTransfer (#1727) (#runtime, #node)
▹ Fix unbounded allocation in cNight Observation pallet (#1423) (#cnight)
▹ 'devnet' genesis state/block and chain-spec recreated (#1698) (#runtime)
▹ Handling ledger transaction execution errors (#1980) (#runtime, #c2m-bridge)
▹ Fix unnecessary denomination in C-to-M bridge (#1608) (#c2m-bridge)
▹ Expose granular ledger error variants in pallet error reporting (#1449) (#runtime)
▹ On-chain ledger 8->9 hardfork state migration (#1925) (#node, #runtime, #ledger)
▹ Enter safe mode instead of freezing the chain on a failed multi-block migration (#2079) (#runtime)
▹ Per-pallet allow-listed system transaction executors (#2080) (#runtime)
▹ Bump system_version to 3 (#6029, #1900) (#runtime)
▹ Gate the tblock correction on a runtime upgrade instead of a date (#2002) (#node, #runtime)
▹ Refactor throttle account usage storage migration (#1526) (#runtime)
🧰 Toolkit
Git tag: toolkit-2.1.0-rc.3
Docker Images
DockerHub
$ docker pull ghcr.io/midnightntwrk/midnight-node-toolkit:2.1.0-rc.3Added
▹ Add --output-events to generate-intent circuit (#1910) (#toolkit)
▹ Add --coin-selection flag to coin-selecting commands (#1457) (#toolkit)
▹ Add compact 0.33.0-rc.1 support (Ledger 9 compatible) (#1711) (#toolkit, #compactc, #ledger9)
▹ Port counter contract E2E test + compact-contract-tests workflow (#1852) (#toolkit, #tests)
▹ Add batched dust_balance::execute_many for multi-seed wallet cache warmup (#1603) (#toolkit)
▹ ECDSA contract maintenance & deploy committees (#1861) (#toolkit, #ledger, #ecdsa, #contract-maintenance)
▹ ECDSA toolkit end-to-end coverage (#1861) (#toolkit, #ledger, #ecdsa, #e2e, #contract-maintenance)
▹ Toolkit ECDSA unshielded signature support (#1837) (#toolkit, #ledger, #unshielded, #ecdsa)
▹ Add show-night-pools command (#1726) (#toolkit)
▹ Per-destination amounts and token types in generate-txs single-tx (#1560) (#toolkit, #generate-txs)
▹ Pin specific UTXOs as inputs to generate-txs single-tx (#1404) (#toolkit, #generate-txs)
▹ Add tic-tac-toe contract e2e test (#1940) (#toolkit)
▹ Toolkit: opt-in wallet-cache checkpoints during long ledger replays (#1968)
▹ Add per-phase timing logs for transaction generation (#1912) (#toolkit, #perf)
▹ Add --print-system-tx-hex flag to update-ledger-parameters (#1473) (#toolkit)
▹ Add welcome contract e2e test (#1940) (#toolkit)
Changed
▹ Harden arithmetic in coin selection with checked operations (#1293, PM-22018) (#toolkit, #security)
▹ Enforce EOF on untagged CLI parser path; document ADR-0022 untagged contract (#1437, PM-22028) (#toolkit, #audit)
▹ Resolve ledger versions from Cargo.lock at build time (#1793) (#toolkit, #security)
▹ Abstract toolkit transaction builders over a BuilderContext trait (#1605) (#toolkit, #refactor)
▹ Bump AL2023 base image to clear critical unbound CVE (#2207) (#toolkit, #docker, #security)
▹ Cache runtime metadata across blocks when fetching (#2111) (#toolkit, #performance)
▹ generate-txs claim-rewards supports --claim-kind (#1697) (#toolkit)
▹ Build compactc from the compact submodule for local development (#1662) (#toolkit, #build)
▹ Tidy contract-address --untagged flag handling (#1486, PM-19934) (#toolkit)
▹ Fix dust-balance wallet/ledger snapshot saved at block_height = 0 when dust_warp is enabled (#1574) (#toolkit)
▹ Accept ecdsa: seeds on chains forked from ledger 8 (#2181, #2183) (#toolkit, #ecdsa, #hardfork)
▹ toolkit-js deploy authority seed accepts the scheme prefix (ECDSA rejected) (#1861) (#toolkit, #ledger, #ecdsa, #contract-maintenance, #toolkit-js)
▹ Fix toolkit-js compactc-resolver on Node 24+ (#1711) (#toolkit)
▹ Fix v6/v7 verifier-key dispatch in ledger-9 contract maintenance (#1711) (#toolkit, #ledger9)
▹ Don't abort context replay on a well_formed failure the chain itself tolerated (#2098) (#toolkit, #bugfix)
▹ Fix self-funded register-dust-address for wallets with multiple NIGHT UTXOs (#1922) (#toolkit, #bugfix)
▹ Rename StandardTrasactionInfo to StandardTransactionInfo (#2016) (#toolkit, #refactor)
▹ Fix update-ledger-parameters command re-using the same param across multiple limits (#2073) (#toolkit)
▹ Do not create genesis state with Reserve having less than in reserve-config.json (#1791) (#toolkit)
▹ Fork-aware transaction generation across the ledger 8->9 hardfork (#1925) (#toolkit, #ledger9)
▹ Adapt toolkit to ledger 9.1.0.0-rc.2 crypto-stack split (#1692) (#toolkit)
▹ Adapt toolkit to ledger 9.1.0.0-rc.3 (#1738) (#toolkit)
▹ Lock redb fetch cache against concurrent toolkit processes (#1493) (#toolkit)
▹ Override toml to 4.3.0 to clear the npm audit gate (#2139) (#toolkit)
▹ Remove gdb from the toolkit image (#2187) (#toolkit, #docker, #security)
Clear the backlog of pending major dependency updates (#toolkit, #ci, #local-env)
CI base image: actions/cache to v6.1.0 and azure/setup-kubectl to v5.1.0,
both pinned by commit. Docker Compose moves to v5.5.0, which required installing
the buildx plugin alongside it - compose v5 removed its internal buildkit
builder and delegates build: to Docker Bake, so without buildx the
contract-compiler service in local-env's compose file no longer builds.
The paritytech/srtool "v1" offer was a false positive: published tags are
<rust version>-<srtool version>, and splitting that across an ARG and a
hard-coded prefix made Renovate read the rust half as the image version and
offer a tag that does not exist. The whole tag is now one ARG, so deterministic
runtime builds keep resolving.
Local environment: the contract-compiler base moves to node:24-slim (still
Debian bookworm, so the pinned apt package set is unaffected), and eslint moves
to v10. eslint 10 drops @eslint/eslintrc, which removes js-yaml from the tree
entirely - the only way the js-yaml major was ever going to resolve, since
eslintrc caps it at 4.x. Two things fell out: globals was a phantom dependency
that only resolved through eslint 9's transitive tree, and eslint 10's
preserve-caught-error rule caught a config-parse failure being re-thrown with
the original error discarded, which now attaches it as cause.
Toolkit: @types/node moves to 24 in util/toolkit-js, which already targeted
@tsconfig/node24. The redundant nanoid and js-yaml overrides entries are
removed - both were npm-audit remediations whose consumers have since raised
their own ranges, so they pinned exactly what npm would pick unaided, and
removing them leaves the lockfiles byte-identical.
▹ Fix sender reporting FAILED_TO_FINALIZE for txs whose including block finalized (#1943) (#toolkit)
▹ --no-watch-progress sends now fail when the pool rejects the transaction (#2138) (#toolkit)
▹ show-wallet reports claimable block-reward and bridge-transfer amounts (#1766) (#toolkit)
▹ Return errors instead of panicking in single-tx and fetcher (#1822) (#toolkit)
▹ Split midnight-ledger-helpers crate (#2106) (#toolkit)
▹ Give each ledger version its own copy of the builders (#2075) (#toolkit, #refactor)
▹ Store circuit zkir on-chain in test contract deploys (#1692) (#toolkit, #ledger9)
▹ Accept spec version 1.0.300 when replaying chain history (#2161) (#toolkit)
▹ Faster, resilient chain sync and wallet replay with working caching on mainnet (#1938) (#toolkit, #performance)
▹ Toolkit wallet-cache: snapshot GC retention floor and cache observability (#1968)
▹ Toolkit sender handles transaction errors with terminal-status messages. (#1323) (#toolkit)
▹ Dispatch toolkit-js variants by compactc version instead of ledger version (#1555) (#toolkit)
▹ Recognise the 1.0.3 runtime when fetching blocks (#2002) (#toolkit)
▹ Fix stack overflow in trusted_deserialize_tagged on long-running chains (#1576) (#toolkit)
▹ Update default CompactC version to 0.31.0 (#1555) (#toolkit)
▹ version subcommand reports the latest supported ledger version (#1649) (#toolkit)
Tagged Changes
#audit
Changed
Fix motion removal on failed dispatch in federated-authority pallet (#938, PM-22085) (#audit, #runtime)
The motion_close extrinsic previously propagated the dispatch error via
motion_result?, causing Substrate's transactional storage layer to roll
back motion_remove when the dispatched call failed. Approved-but-failed
motions became permanently stuck in on-chain storage with no recovery path.
The fix removes dispatch error propagation so motion_close always succeeds
once the motion is approved, with the dispatch outcome captured in the
MotionDispatched event. Also removes three unused error variants
(MotionTooEarlyToClose, MotionAlreadyExists, MotionExpired).
Fixes: #1318
PR: #938
JIRA: https://shielded.atlassian.net/browse/PM-22085
📦 Node
Added
▹ Add e2e regression coverage for genesis_extrinsics parsing (#1516) (#audit, #tests, #ci)
Changed
▹ Surface ContractNotPresent through midnight_contractState RPC (#1475) (#audit, #rpc)
▹ Improve cnight-observation genesis panic diagnostics (#1466, PM-19896) (#audit, #hardening)
▹ Reject incoherent mainchain timing configuration (PM-20013, #1656) (#audit, #node, #hardening)
🧰 Toolkit
Changed
▹ Enforce EOF on untagged CLI parser path; document ADR-0022 untagged contract (#1437, PM-22028) (#toolkit, #audit)
#bugfix
🧰 Toolkit
Changed
▹ Don't abort context replay on a well_formed failure the chain itself tolerated (#2098) (#toolkit, #bugfix)
▹ Fix self-funded register-dust-address for wallets with multiple NIGHT UTXOs (#1922) (#toolkit, #bugfix)
#build
🧰 Toolkit
Changed
▹ Build compactc from the compact submodule for local development (#1662) (#toolkit, #build)
#c2m-bridge
📦 Node
Added
▹ Add indexer-side assertions to c2m_bridge e2e tests (opt-in) (#1718) (#tests, #c2m-bridge, #indexer)
Changed
▹ Handling ledger transaction execution errors (#1980) (#node, #c2m-bridge)
▹ Fix handling of c2m-bridge transaction that have recipient address too short (#2185) (#node, #c2m-bridge)
⚙️ Runtime
Added
▹ Add optional approved_txs to c2m-bridge genesis config (#1809) (#runtime, #c2m-bridge)
Changed
▹ Handling ledger transaction execution errors (#1980) (#runtime, #c2m-bridge)
▹ Fix unnecessary denomination in C-to-M bridge (#1608) (#c2m-bridge)
#ci
📦 Node
Added
▹ Add e2e regression coverage for genesis_extrinsics parsing (#1516) (#audit, #tests, #ci)
▹ Add CI guard protecting frozen res/ network config (#1732) (#ci)
Changed
▹ Run nightly cNIGHT e2e job inside a container (#1658) (#tests, #ci)
🧰 Toolkit
Changed
Clear the backlog of pending major dependency updates (#toolkit, #ci, #local-env)
CI base image: actions/cache to v6.1.0 and azure/setup-kubectl to v5.1.0,
both pinned by commit. Docker Compose moves to v5.5.0, which required installing
the buildx plugin alongside it - compose v5 removed its internal buildkit
builder and delegates build: to Docker Bake, so without buildx the
contract-compiler service in local-env's compose file no longer builds.
The paritytech/srtool "v1" offer was a false positive: published tags are
<rust version>-<srtool version>, and splitting that across an ARG and a
hard-coded prefix made Renovate read the rust half as the image version and
offer a tag that does not exist. The whole tag is now one ARG, so deterministic
runtime builds keep resolving.
Local environment: the contract-compiler base moves to node:24-slim (still
Debian bookworm, so the pinned apt package set is unaffected), and eslint moves
to v10. eslint 10 drops @eslint/eslintrc, which removes js-yaml from the tree
entirely - the only way the js-yaml major was ever going to resolve, since
eslintrc caps it at 4.x. Two things fell out: globals was a phantom dependency
that only resolved through eslint 9's transitive tree, and eslint 10's
preserve-caught-error rule caught a config-parse failure being re-thrown with
the original error discarded, which now attaches it as cause.
Toolkit: @types/node moves to 24 in util/toolkit-js, which already targeted
@tsconfig/node24. The redundant nanoid and js-yaml overrides entries are
removed - both were npm-audit remediations whose consumers have since raised
their own ranges, so they pinned exactly what npm would pick unaided, and
removing them leaves the lockfiles byte-identical.
#cnight
📦 Node
Changed
▹ Order observed cNIGHT UTXOs by data variant, gated on spec_version (#2123) (#node, #cnight, #consensus)
⚙️ Runtime
Added
▹ Re-apply cNIGHT dust generation after the ledger 8 -> 9 hardfork (#2012) (#cnight, #dust, #migration)
Changed
▹ Fix unbounded allocation in cNight Observation pallet (#1423) (#cnight)
#compactc
🧰 Toolkit
Added
▹ Add compact 0.33.0-rc.1 support (Ledger 9 compatible) (#1711) (#toolkit, #compactc, #ledger9)
#config
📦 Node
Changed
▹ Default block_stability_margin to 30 across all config presets (#1914) (#node, #config)
#consensus
📦 Node
Changed
▹ Order observed cNIGHT UTXOs by data variant, gated on spec_version (#2123) (#node, #cnight, #consensus)
#contract-maintenance
🧰 Toolkit
Added
▹ ECDSA contract maintenance & deploy committees (#1861) (#toolkit, #ledger, #ecdsa, #contract-maintenance)
▹ ECDSA toolkit end-to-end coverage (#1861) (#toolkit, #ledger, #ecdsa, #e2e, #contract-maintenance)
Changed
▹ toolkit-js deploy authority seed accepts the scheme prefix (ECDSA rejected) (#1861) (#toolkit, #ledger, #ecdsa, #contract-maintenance, #toolkit-js)
#dependencies
📦 Node
Changed
▹ Switch polkadot-sdk to the shieldedtech fork of stable2606 with TCP_NODELAY on RPC sockets (#2200) (#rpc, #dependencies)
#docker
📦 Node
Changed
▹ Bump AL2023 base image to clear critical unbound CVE (#2207) (#node, #docker, #security)
▹ Stop duplicating binaries and res/ in a second image layer (#2048) (#node, #toolkit, #docker)
▹ Remove gdb from the node and hardfork-test-upgrader images (#2187) (#node, #docker, #security)
🧰 Toolkit
Changed
▹ Bump AL2023 base image to clear critical unbound CVE (#2207) (#toolkit, #docker, #security)
▹ Remove gdb from the toolkit image (#2187) (#toolkit, #docker, #security)
#dust
⚙️ Runtime
Added
▹ Re-apply cNIGHT dust generation after the ledger 8 -> 9 hardfork (#2012) (#cnight, #dust, #migration)
#e2e
🧰 Toolkit
Added
▹ ECDSA toolkit end-to-end coverage (#1861) (#toolkit, #ledger, #ecdsa, #e2e, #contract-maintenance)
#ecdsa
🧰 Toolkit
Added
▹ ECDSA contract maintenance & deploy committees (#1861) (#toolkit, #ledger, #ecdsa, #contract-maintenance)
▹ ECDSA toolkit end-to-end coverage (#1861) (#toolkit, #ledger, #ecdsa, #e2e, #contract-maintenance)
▹ Toolkit ECDSA unshielded signature support (#1837) (#toolkit, #ledger, #unshielded, #ecdsa)
Changed
▹ Accept ecdsa: seeds on chains forked from ledger 8 (#2181, #2183) (#toolkit, #ecdsa, #hardfork)
▹ toolkit-js deploy authority seed accepts the scheme prefix (ECDSA rejected) (#1861) (#toolkit, #ledger, #ecdsa, #contract-maintenance, #toolkit-js)
#fix
📦 Node
Changed
▹ Fix reserve-contracts CLI governance-update txs on local-env (Ogmios 3002) (#1934) (#fix, #tooling)
#generate-txs
🧰 Toolkit
Added
▹ Per-destination amounts and token types in generate-txs single-tx (#1560) (#toolkit, #generate-txs)
▹ Pin specific UTXOs as inputs to generate-txs single-tx (#1404) (#toolkit, #generate-txs)
#hardening
📦 Node
Changed
▹ Improve cnight-observation genesis panic diagnostics (#1466, PM-19896) (#audit, #hardening)
▹ Reject incoherent mainchain timing configuration (PM-20013, #1656) (#audit, #node, #hardening)
#hardfork
📦 Node
Changed
▹ Use the upstream ledger v8->v9 state translation crate (#2054) (#hardfork, #ledger)
🧰 Toolkit
Changed
▹ Accept ecdsa: seeds on chains forked from ledger 8 (#2181, #2183) (#toolkit, #ecdsa, #hardfork)
#helpers
📦 Node
Changed
▹ Eliminate deadlock in LedgerContext::with_wallets_from_seeds (R-059) (#1471, PM-21800) (#ledger, #helpers)
#hygiene
📦 Node
Changed
▹ Log transaction rejection reasons via Display rather than Debug (#2105) (#logging, #hygiene)
#indexer
📦 Node
Added
▹ Add indexer-side assertions to c2m_bridge e2e tests (opt-in) (#1718) (#tests, #c2m-bridge, #indexer)
#ledger
Changed
Verify removal of WalletSeed Default implementation (#1109, PM-22024) (#ledger)
Verify the audit finding (A2 Issue D) remediation from PR #804 that removed
the all-zero Default implementation for WalletSeed. Confirms no residual
zero-seed usage in key derivation paths.
PR: #1109
Issue: https://github.com/midnight-security/midnight-security/issues/112
JIRA: https://shielded.atlassian.net/browse/PM-22024
▹ Improve wallet seed, key pair, and address code quality (#1217, PM-22038) (#toolkit, #ledger)
📦 Node
Changed
▹ Eliminate deadlock in LedgerContext::with_wallets_from_seeds (R-059) (#1471, PM-21800) (#ledger, #helpers)
▹ Return BeneficiaryNotFound for absent beneficiaries in get_unclaimed_amount (#1359, PM-21801) (#ledger, #rpc)
▹ Serve ledger state reads at the ledger-hardfork set_code block (#1985) (#node, #ledger)
▹ Add get_bridge_receiving_amount ledger host API (#1766) (#ledger)
▹ Use the upstream ledger v8->v9 state translation crate (#2054) (#hardfork, #ledger)
⚙️ Runtime
Changed
▹ On-chain ledger 8->9 hardfork state migration (#1925) (#node, #runtime, #ledger)
🧰 Toolkit
Added
▹ ECDSA contract maintenance & deploy committees (#1861) (#toolkit, #ledger, #ecdsa, #contract-maintenance)
▹ ECDSA toolkit end-to-end coverage (#1861) (#toolkit, #ledger, #ecdsa, #e2e, #contract-maintenance)
▹ Toolkit ECDSA unshielded signature support (#1837) (#toolkit, #ledger, #unshielded, #ecdsa)
Changed
▹ toolkit-js deploy authority seed accepts the scheme prefix (ECDSA rejected) (#1861) (#toolkit, #ledger, #ecdsa, #contract-maintenance, #toolkit-js)
#ledger9
🧰 Toolkit
Added
▹ Add compact 0.33.0-rc.1 support (Ledger 9 compatible) (#1711) (#toolkit, #compactc, #ledger9)
Changed
▹ Fix v6/v7 verifier-key dispatch in ledger-9 contract maintenance (#1711) (#toolkit, #ledger9)
▹ Fork-aware transaction generation across the ledger 8->9 hardfork (#1925) (#toolkit, #ledger9)
▹ Store circuit zkir on-chain in test contract deploys (#1692) (#toolkit, #ledger9)
#local-env
📦 Node
Added
▹ Non-validator archive node in the local-env stack (#2058) (#local-env)
▹ Let downstream repos run against a local-environment fork (#1920) (#node, #local-env)
▹ Add --num-validators to run a smaller mock authority set in local-env forks (#2008) (#node, #local-env)
▹ Add local network for the local-environment, bridge-funded at runtime (#1796) (#node, #local-env)
Changed
▹ Patch cnight mapping_validator_address from freshly compiled contracts (#1653) (#node, #local-env)
▹ Fix GRANDPA finality stall when forking a >=2.0.0 network in local-env (#2008) (#node, #local-env)
🧰 Toolkit
Changed
Clear the backlog of pending major dependency updates (#toolkit, #ci, #local-env)
CI base image: actions/cache to v6.1.0 and azure/setup-kubectl to v5.1.0,
both pinned by commit. Docker Compose moves to v5.5.0, which required installing
the buildx plugin alongside it - compose v5 removed its internal buildkit
builder and delegates build: to Docker Bake, so without buildx the
contract-compiler service in local-env's compose file no longer builds.
The paritytech/srtool "v1" offer was a false positive: published tags are
<rust version>-<srtool version>, and splitting that across an ARG and a
hard-coded prefix made Renovate read the rust half as the image version and
offer a tag that does not exist. The whole tag is now one ARG, so deterministic
runtime builds keep resolving.
Local environment: the contract-compiler base moves to node:24-slim (still
Debian bookworm, so the pinned apt package set is unaffected), and eslint moves
to v10. eslint 10 drops @eslint/eslintrc, which removes js-yaml from the tree
entirely - the only way the js-yaml major was ever going to resolve, since
eslintrc caps it at 4.x. Two things fell out: globals was a phantom dependency
that only resolved through eslint 9's transitive tree, and eslint 10's
preserve-caught-error rule caught a config-parse failure being re-thrown with
the original error discarded, which now attaches it as cause.
Toolkit: @types/node moves to 24 in util/toolkit-js, which already targeted
@tsconfig/node24. The redundant nanoid and js-yaml overrides entries are
removed - both were npm-audit remediations whose consumers have since raised
their own ranges, so they pinned exactly what npm would pick unaided, and
removing them leaves the lockfiles byte-identical.
#logging
📦 Node
Changed
▹ Log transaction rejection reasons via Display rather than Debug (#2105) (#logging, #hygiene)
#migration
⚙️ Runtime
Added
▹ Re-apply cNIGHT dust generation after the ledger 8 -> 9 hardfork (#2012) (#cnight, #dust, #migration)
#node
Changed
Bound GRANDPA and BEEFY finality subscription fan-out (#1075, PM-19967) (#node)
Add per-connection and global subscription limits with bounded notification
channels for GRANDPA and BEEFY RPC handlers. Prevents resource exhaustion
from unbounded fan-out of consensus notifications.
Fixes: #1319
PR: #1075
JIRA: https://shielded.atlassian.net/browse/PM-19967
Enforce TLS certificate and hostname validation for DB connections (#1104, PM-22023) (#node)
Set ssl_mode to PgSslMode::VerifyFull in get_connection and reject
insecure SSL modes (Prefer, Disable) to prevent plaintext database
transport and unauthenticated TLS connections.
Fixes: #1320
PR: #1104
JIRA: https://shielded.atlassian.net/browse/PM-22023
Configuration for Cardano-to-Midnight bridge (#1333) (#node, #runtime)
Enables chain-spec build / genesis block creation to include subminimal transfers config.
Adds subminimal transfer config to runtime api that sets bridge configuration.
Enables Bridge operations in the local-environment.
Fixes Reserve Transfer classification (#1513) (#node, #runtime)
Before this change Bridge was using transaction metadata as criterium of classifying transfers.
It would allow attack on M.R pool.
This PR modifies observability to distinguish Reserve Validator and ICS Validator inputs of the transaction to correctly classify transfer.
In the edge case one Cardano Tx can be ReserveTransfer and User Transfer at same time.
When node with this update is deployed, it will not be able to read MainChainScripts of the bridge pallet and inherent data provider will report Inert variant of IDP.
Bridge is not complete and non environment should have it configured, so everywhere the IDP should be Inert as well.
Governance action setting these addresses and data checkpoint will be required to enable the bridge.
Return ContractNotPresent error for missing contracts (#916) (#node)
Return an explicit ContractNotPresent error when querying the state of a non-existent contract address, instead of returning a default empty state. This allows callers to distinguish between an empty contract and a missing one.
Make CNight observation mock deterministic for multi-node networks (#1870) (#node, #runtime)
The CNight observation data source mock now generates deterministic data based on block number instead of random data. This ensures all nodes in a multi-node network produce identical inherent data, preventing block verification failures.
Changes:
- Replaced random UTXO generation with deterministic generation seeded by block number
- All nodes with the same block number now generate identical mock CNight observations
- Prevents "inherent data mismatch" errors in multi-node development setups
Technical Details:
- Deterministic hash generation based on block number and salt
- Consistent reward addresses and dust public keys across all nodes
- Maintains compatibility with single-node development mode
This fix enables running local multi-node networks in development mode without Cardano infrastructure.
PR: #1870
Replace panic with error handling in cnight-observation inherent data decoding (#1234, PM-21799) (#node, #runtime)
The get_data_from_inherent_data function in the cnight-observation pallet
used .expect() on inherent data decoding, which could cause all validators
to panic simultaneously on malformed data, halting the chain. This replaces
the panic with typed Result<Option<...>, InherentError> error handling
using a new DecodeFailed variant, matching the pattern already established
in the sibling federated-authority-observation pallet.
Fixes: #1317
PR: #1234
JIRA: https://shielded.atlassian.net/browse/PM-21799
▹ Ledger 9 support (#1604) (#node, #runtime, #toolkit)
▹ Removal of unused partner chains pallets and related commands (#1562) (#runtime, #node)
▹ Update Rust toolchain to 1.98.1 (#2166) (#node, #toolkit, #runtime)
📦 Node
Added
▹ Log on each session change whether this validator is in the committee (#1534) (#node)
▹ Let downstream repos run against a local-environment fork (#1920) (#node, #local-env)
▹ Add --num-validators to run a smaller mock authority set in local-env forks (#2008) (#node, #local-env)
▹ Add local network for the local-environment, bridge-funded at runtime (#1796) (#node, #local-env)
▹ Add Midnight-specific reference hardware profile for benchmark machine checks (#1511) (#node)
▹ Add stagenet network genesis and chain specs (#1707) (#node)
Changed
▹ Use ledger 9 apply_guaranteed_only for guaranteed-segment validation (#1454) (#node)
Restore the preview chain-spec that live preview actually runs (#node)
Preview was reset in June 2026 (#1690) to fix an empty Locked pool, and the regenerated
chain-spec and genesis state landed in #1699 — but only on release/node-1.0.1. The 2.x line
branched before that, so release/node-2.1.0 still shipped the pre-reset artifacts.
A preview node brought up from an empty disk using res/preview/ computed genesis
0x801d…b880 instead of live preview's 0x3c096de2…6dd13796, was rejected by every bootnode as
a different chain, and sat at block #0 with no peers. Nodes already running were unaffected —
their genesis is on disk.
Forward-ports the five artifacts from release/node-1.0.1, leaving res/preview/ byte-identical
to the branch preview runs. The input configs (ics-config.json, reserve-config.json) already
matched and are untouched.
Issue: #1690
▹ Default block_stability_margin to 30 across all config presets (#1914) (#node, #config)
▹ Bump AL2023 base image to clear critical unbound CVE (#2207) (#node, #docker, #security)
▹ Bump ledger 9 version to 9.1.0.0-rc.5 (#2096) (#node, #runtime, #toolkit)
▹ Order observed cNIGHT UTXOs by data variant, gated on spec_version (#2123) (#node, #cnight, #consensus)
▹ Skip committee-membership logs when SessionInfoApi is absent (#2204) (#node)
▹ Decouple qanet e2e tests from local-env docker artefacts (#1666) (#node, #tests)
▹ Read e2e test contract values from runtime-values instead of hardcoded CBOR (#1348) (#node, #tests)
▹ Handling ledger transaction execution errors (#1980) (#node, #c2m-bridge)
▹ Fix handling of c2m-bridge transaction that have recipient address too short (#2185) (#node, #c2m-bridge)
▹ Surface nested ledger error variants in flat error enums (#1449) (#node)
▹ Serve ledger state reads at the ledger-hardfork set_code block (#1985) (#node, #ledger)
▹ Stop duplicating binaries and res/ in a second image layer (#2048) (#node, #toolkit, #docker)
▹ Incomplete zeroization after conversion to ordinary buffers (PM-22034, #1379) (#node, #toolkit)
▹ Bump ledger to 9.1.0.0-rc.2 (#1692) (#node, #runtime, #toolkit)
▹ Bump ledger to 9.1.0.0-rc.3 (#1738) (#node, #runtime, #toolkit)
▹ Bump ledger to 9.1.0.0-rc.4 (#2022) (#node, #runtime, #toolkit)
▹ Pin ledger 9.1.0.0-rc.5 per crate instead of by the workspace tag (#2134) (#node, #runtime, #toolkit)
▹ Patch cnight mapping_validator_address from freshly compiled contracts (#1653) (#node, #local-env)
▹ Fix GRANDPA finality stall when forking a >=2.0.0 network in local-env (#2008) (#node, #local-env)
▹ Cache repeated mainchain-follower inherent reads during node sync (#1551) (#node)
▹ Do not ban peers when local Cardano observation lags during block verification (#1472) (#node)
▹ Reject block headers carrying duplicate main chain reference hash digests (#1617) (#node)
▹ parity-db: Midnight fork, lower flush threshold, ahash (#1, #2, #1478) (#node)
▹ Update Polkadot SDK toward polkadot-stable2606 (#1790) (#node, #runtime)
▹ Prevalidate post-block-update after each ledger 9 transaction (#1448) (#node, #runtime)
▹ Remove gdb from the node and hardfork-test-upgrader images (#2187) (#node, #docker, #security)
▹ Remove ledger 7 support (#1999) (#node, #toolkit, #runtime)
▹ Revert the cNIGHT observation sliding-window cache (#2030) (#node)
▹ Revert the 16x reduction in cNIGHT observation UTXO over-fetch (#1367) (#node, #runtime)
▹ Silence cNIGHT observation logs for unregistered and non-base Cardano addresses (#1324) (#node)
▹ Reject incoherent mainchain timing configuration (PM-20013, #1656) (#audit, #node, #hardening)
▹ Give each ledger version its own copy of the ledger helpers (#2074) (#node, #refactor)
▹ Give each ledger version its own copy of the wrapper code (#2059) (#node, #refactor)
▹ Run hardware benchmarks on node startup (#1394) (#node)
▹ Log sanitized db-sync startup probe results (#1411) (#node)
▹ Tune autovacuum on db-sync hot tables for stable query plans (#1434) (#node)
⚙️ Runtime
Changed
▹ Ad Op variant for ClaimBridgeTransfer (#1727) (#runtime, #node)
▹ On-chain ledger 8->9 hardfork state migration (#1925) (#node, #runtime, #ledger)
▹ Gate the tblock correction on a runtime upgrade instead of a date (#2002) (#node, #runtime)
#partner-chains
Changed
#perf
🧰 Toolkit
Added
▹ Add per-phase timing logs for transaction generation (#1912) (#toolkit, #perf)
#performance
🧰 Toolkit
Changed
▹ Cache runtime metadata across blocks when fetching (#2111) (#toolkit, #performance)
▹ Faster, resilient chain sync and wallet replay with working caching on mainnet (#1938) (#toolkit, #performance)
#refactor
📦 Node
Changed
▹ Give each ledger version its own copy of the ledger helpers (#2074) (#node, #refactor)
▹ Give each ledger version its own copy of the wrapper code (#2059) (#node, #refactor)
🧰 Toolkit
Changed
▹ Abstract toolkit transaction builders over a BuilderContext trait (#1605) (#toolkit, #refactor)
▹ Rename StandardTrasactionInfo to StandardTransactionInfo (#2016) (#toolkit, #refactor)
▹ Give each ledger version its own copy of the builders (#2075) (#toolkit, #refactor)
#rpc
📦 Node
Changed
▹ Return BeneficiaryNotFound for absent beneficiaries in get_unclaimed_amount (#1359, PM-21801) (#ledger, #rpc)
▹ Surface ContractNotPresent through midnight_contractState RPC (#1475) (#audit, #rpc)
▹ Switch polkadot-sdk to the shieldedtech fork of stable2606 with TCP_NODELAY on RPC sockets (#2200) (#rpc, #dependencies)
#runtime
Changed
Configuration for Cardano-to-Midnight bridge (#1333) (#node, #runtime)
Enables chain-spec build / genesis block creation to include subminimal transfers config.
Adds subminimal transfer config to runtime api that sets bridge configuration.
Enables Bridge operations in the local-environment.
Fixes Reserve Transfer classification (#1513) (#node, #runtime)
Before this change Bridge was using transaction metadata as criterium of classifying transfers.
It would allow attack on M.R pool.
This PR modifies observability to distinguish Reserve Validator and ICS Validator inputs of the transaction to correctly classify transfer.
In the edge case one Cardano Tx can be ReserveTransfer and User Transfer at same time.
When node with this update is deployed, it will not be able to read MainChainScripts of the bridge pallet and inherent data provider will report Inert variant of IDP.
Bridge is not complete and non environment should have it configured, so everywhere the IDP should be Inert as well.
Governance action setting these addresses and data checkpoint will be required to enable the bridge.
Make CNight observation mock deterministic for multi-node networks (#1870) (#node, #runtime)
The CNight observation data source mock now generates deterministic data based on block number instead of random data. This ensures all nodes in a multi-node network produce identical inherent data, preventing block verification failures.
Changes:
- Replaced random UTXO generation with deterministic generation seeded by block number
- All nodes with the same block number now generate identical mock CNight observations
- Prevents "inherent data mismatch" errors in multi-node development setups
Technical Details:
- Deterministic hash generation based on block number and salt
- Consistent reward addresses and dust public keys across all nodes
- Maintains compatibility with single-node development mode
This fix enables running local multi-node networks in development mode without Cardano infrastructure.
PR: #1870
Fix environments configuration files and genesis state generation process to prevent empty locked pool (#1675) (#toolkit, #runtime)
Makes all /res Reserve and ICS configs valid (non zero values). All genesis files and chain-specs, with known exception for Preview, have non empty locked pool amount.
Removes logic that assigned MAX_SUPPLY - treasury to the reserve_pool leaving locked_pool empty in absence of reserve config.
Now, if reserve config is absent, the reserve pool would be empty. Genesis state will likely fail in such a case, because
funding seeds would fail.
Therefore there will be --allow-empty-pools flag required if any pool or treasury is empty.
Future chain-spec generation should not create specs with empty locked pool if some config was omitted.
All environments are now configured to mimic mainnet amounts configuration in regards to Midnight Genesis reserve, locked and treasury pools.
Durable environments genesis states and chain-specs are not re-created. We keep chain-spec as on environment and genesis-state consistent with chain-specs. This is way CI likes.
Currently there is discrepancy between pool amounts in config for Preview environment only. Preview needs reset and new chain-spec will be correct if generated from current config files.
Replace panic with error handling in cnight-observation inherent data decoding (#1234, PM-21799) (#node, #runtime)
The get_data_from_inherent_data function in the cnight-observation pallet
used .expect() on inherent data decoding, which could cause all validators
to panic simultaneously on malformed data, halting the chain. This replaces
the panic with typed Result<Option<...>, InherentError> error handling
using a new DecodeFailed variant, matching the pattern already established
in the sibling federated-authority-observation pallet.
Fixes: #1317
PR: #1234
JIRA: https://shielded.atlassian.net/browse/PM-21799
Fix motion removal on failed dispatch in federated-authority pallet (#938, PM-22085) (#audit, #runtime)
The motion_close extrinsic previously propagated the dispatch error via
motion_result?, causing Substrate's transactional storage layer to roll
back motion_remove when the dispatched call failed. Approved-but-failed
motions became permanently stuck in on-chain storage with no recovery path.
The fix removes dispatch error propagation so motion_close always succeeds
once the motion is approved, with the dispatch outcome captured in the
MotionDispatched event. Also removes three unused error variants
(MotionTooEarlyToClose, MotionAlreadyExists, MotionExpired).
Fixes: #1318
PR: #938
JIRA: https://shielded.atlassian.net/browse/PM-22085
▹ Ledger 9 support (#1604) (#node, #runtime, #toolkit)
▹ Removal of unused partner chains pallets and related commands (#1562) (#runtime, #node)
▹ Update Rust toolchain to 1.98.1 (#2166) (#node, #toolkit, #runtime)
📦 Node
Changed
▹ Bump ledger 9 version to 9.1.0.0-rc.5 (#2096) (#node, #runtime, #toolkit)
▹ Bump ledger to 9.1.0.0-rc.2 (#1692) (#node, #runtime, #toolkit)
▹ Bump ledger to 9.1.0.0-rc.3 (#1738) (#node, #runtime, #toolkit)
▹ Bump ledger to 9.1.0.0-rc.4 (#2022) (#node, #runtime, #toolkit)
▹ Pin ledger 9.1.0.0-rc.5 per crate instead of by the workspace tag (#2134) (#node, #runtime, #toolkit)
▹ Update Polkadot SDK toward polkadot-stable2606 (#1790) (#node, #runtime)
▹ Prevalidate post-block-update after each ledger 9 transaction (#1448) (#node, #runtime)
▹ Remove ledger 7 support (#1999) (#node, #toolkit, #runtime)
▹ Revert the 16x reduction in cNIGHT observation UTXO over-fetch (#1367) (#node, #runtime)
⚙️ Runtime
Added
▹ Added benchmarks and weights of pallet_c2m_bridge and pallet_partner_chains_bridge (#1635) (#runtime)
▹ Add optional approved_txs to c2m-bridge genesis config (#1809) (#runtime, #c2m-bridge)
▹ Added c2m-bridge pallet (#1386) (#runtime)
▹ Add root extrinsics to set cNIGHT contract identifiers (#1602) (#runtime)
▹ Log an error on session change when the D-parameter is below the permissioned candidate count (#1506) (#runtime)
▹ Add SessionInfoApi runtime API exposing the substrate session index (#1534) (#runtime)
Changed
▹ Close runtime benchmark coverage gaps before the 2.1.0 weights run (#2160) (#runtime)
Use `apply_post_block_update` in `pallet_midnight` `on_finalize` (#runtime)
This change makes on_finalize use function that has theoretically one way less to fail.
In practice the error couldn't happen becase block fullness is checked for each included transaction.
▹ C-to-M bridge pre-approvals filter (#1477) (#runtime)
▹ C-to-M bridge holds subminimal transfers (#1393) (#runtime)
▹ Ad Op variant for ClaimBridgeTransfer (#1727) (#runtime, #node)
▹ 'devnet' genesis state/block and chain-spec recreated (#1698) (#runtime)
▹ Handling ledger transaction execution errors (#1980) (#runtime, #c2m-bridge)
▹ Expose granular ledger error variants in pallet error reporting (#1449) (#runtime)
▹ On-chain ledger 8->9 hardfork state migration (#1925) (#node, #runtime, #ledger)
▹ Enter safe mode instead of freezing the chain on a failed multi-block migration (#2079) (#runtime)
▹ Per-pallet allow-listed system transaction executors (#2080) (#runtime)
▹ Bump system_version to 3 (#6029, #1900) (#runtime)
▹ Gate the tblock correction on a runtime upgrade instead of a date (#2002) (#node, #runtime)
▹ Refactor throttle account usage storage migration (#1526) (#runtime)
#security
📦 Node
Changed
▹ Bump AL2023 base image to clear critical unbound CVE (#2207) (#node, #docker, #security)
▹ Remove gdb from the node and hardfork-test-upgrader images (#2187) (#node, #docker, #security)
🧰 Toolkit
Changed
▹ Harden arithmetic in coin selection with checked operations (#1293, PM-22018) (#toolkit, #security)
▹ Resolve ledger versions from Cargo.lock at build time (#1793) (#toolkit, #security)
▹ Bump AL2023 base image to clear critical unbound CVE (#2207) (#toolkit, #docker, #security)
▹ Remove gdb from the toolkit image (#2187) (#toolkit, #docker, #security)
#storage
📦 Node
Changed
▹ New storage_separation config option to use a single ParityDb instance (#1278) (#storage)
#tests
📦 Node
Added
▹ Add e2e regression coverage for genesis_extrinsics parsing (#1516) (#audit, #tests, #ci)
▹ Add indexer-side assertions to c2m_bridge e2e tests (opt-in) (#1718) (#tests, #c2m-bridge, #indexer)
▹ Add per-test tracing logger to the e2e suite (#1564) (#tests)
Changed
▹ Restore cNIGHT observation coverage against Cardano Preview (#1578, #1613) (#tests)
▹ Decouple qanet e2e tests from local-env docker artefacts (#1666) (#node, #tests)
▹ Read e2e test contract values from runtime-values instead of hardcoded CBOR (#1348) (#node, #tests)
▹ Implement e2e tests for C-to-M bridge (#1654) (#tests)
▹ Split e2e test suite into per-topic module files (#1565) (#tests)
▹ Run nightly cNIGHT e2e job inside a container (#1658) (#tests, #ci)
▹ Edge-case tests for c2m-bridge subminimal-transfer accumulation (#1677) (#tests)
🧰 Toolkit
Added
▹ Port counter contract E2E test + compact-contract-tests workflow (#1852) (#toolkit, #tests)
#tooling
📦 Node
Changed
▹ Fix reserve-contracts CLI governance-update txs on local-env (Ogmios 3002) (#1934) (#fix, #tooling)
#toolkit
Changed
Enforce derivation path role validation in wallet constructors (#1076, PM-20015) (#toolkit)
Add regression tests verifying that DustWallet::from_path() and
ShieldedWallet::from_path() reject derivation paths with mismatched
roles. Addresses Least Authority audit Issue AN.
Issue: #1327
PR: #1076
JIRA: https://shielded.atlassian.net/browse/PM-20015
Add commands for initiating bridge transfers. (#1340) (#toolkit)
Adds bridge-transfer command that submits transaction to Cardano. Transaction is from user wallet to ICS address and has metadata that encodes either: transfer to specified Midnight UserAddress, to reserve or invalid one (will end up in Treasury).
Fix environments configuration files and genesis state generation process to prevent empty locked pool (#1675) (#toolkit, #runtime)
Makes all /res Reserve and ICS configs valid (non zero values). All genesis files and chain-specs, with known exception for Preview, have non empty locked pool amount.
Removes logic that assigned MAX_SUPPLY - treasury to the reserve_pool leaving locked_pool empty in absence of reserve config.
Now, if reserve config is absent, the reserve pool would be empty. Genesis state will likely fail in such a case, because
funding seeds would fail.
Therefore there will be --allow-empty-pools flag required if any pool or treasury is empty.
Future chain-spec generation should not create specs with empty locked pool if some config was omitted.
All environments are now configured to mimic mainnet amounts configuration in regards to Midnight Genesis reserve, locked and treasury pools.
Durable environments genesis states and chain-specs are not re-created. We keep chain-spec as on environment and genesis-state consistent with chain-specs. This is way CI likes.
Currently there is discrepancy between pool amounts in config for Preview environment only. Preview needs reset and new chain-spec will be correct if generated from current config files.
▹ Ledger 9 support (#1604) (#node, #runtime, #toolkit)
▹ Update Rust toolchain to 1.98.1 (#2166) (#node, #toolkit, #runtime)
▹ Improve wallet seed, key pair, and address code quality (#1217, PM-22038) (#toolkit, #ledger)
📦 Node
Changed
▹ Bump ledger 9 version to 9.1.0.0-rc.5 (#2096) (#node, #runtime, #toolkit)
▹ Stop duplicating binaries and res/ in a second image layer (#2048) (#node, #toolkit, #docker)
▹ Incomplete zeroization after conversion to ordinary buffers (PM-22034, #1379) (#node, #toolkit)
▹ Bump ledger to 9.1.0.0-rc.2 (#1692) (#node, #runtime, #toolkit)
▹ Bump ledger to 9.1.0.0-rc.3 (#1738) (#node, #runtime, #toolkit)
▹ Bump ledger to 9.1.0.0-rc.4 (#2022) (#node, #runtime, #toolkit)
▹ Pin ledger 9.1.0.0-rc.5 per crate instead of by the workspace tag (#2134) (#node, #runtime, #toolkit)
▹ Remove ledger 7 support (#1999) (#node, #toolkit, #runtime)
🧰 Toolkit
Added
▹ Add --output-events to generate-intent circuit (#1910) (#toolkit)
▹ Add --coin-selection flag to coin-selecting commands (#1457) (#toolkit)
▹ Add compact 0.33.0-rc.1 support (Ledger 9 compatible) (#1711) (#toolkit, #compactc, #ledger9)
▹ Port counter contract E2E test + compact-contract-tests workflow (#1852) (#toolkit, #tests)
▹ Add batched dust_balance::execute_many for multi-seed wallet cache warmup (#1603) (#toolkit)
▹ ECDSA contract maintenance & deploy committees (#1861) (#toolkit, #ledger, #ecdsa, #contract-maintenance)
▹ ECDSA toolkit end-to-end coverage (#1861) (#toolkit, #ledger, #ecdsa, #e2e, #contract-maintenance)
▹ Toolkit ECDSA unshielded signature support (#1837) (#toolkit, #ledger, #unshielded, #ecdsa)
▹ Add show-night-pools command (#1726) (#toolkit)
▹ Per-destination amounts and token types in generate-txs single-tx (#1560) (#toolkit, #generate-txs)
▹ Pin specific UTXOs as inputs to generate-txs single-tx (#1404) (#toolkit, #generate-txs)
▹ Add tic-tac-toe contract e2e test (#1940) (#toolkit)
▹ Add per-phase timing logs for transaction generation (#1912) (#toolkit, #perf)
▹ Add --print-system-tx-hex flag to update-ledger-parameters (#1473) (#toolkit)
▹ Add welcome contract e2e test (#1940) (#toolkit)
Changed
▹ Harden arithmetic in coin selection with checked operations (#1293, PM-22018) (#toolkit, #security)
▹ Enforce EOF on untagged CLI parser path; document ADR-0022 untagged contract (#1437, PM-22028) (#toolkit, #audit)
▹ Resolve ledger versions from Cargo.lock at build time (#1793) (#toolkit, #security)
▹ Abstract toolkit transaction builders over a BuilderContext trait (#1605) (#toolkit, #refactor)
▹ Bump AL2023 base image to clear critical unbound CVE (#2207) (#toolkit, #docker, #security)
▹ Cache runtime metadata across blocks when fetching (#2111) (#toolkit, #performance)
▹ generate-txs claim-rewards supports --claim-kind (#1697) (#toolkit)
▹ Build compactc from the compact submodule for local development (#1662) (#toolkit, #build)
▹ Tidy contract-address --untagged flag handling (#1486, PM-19934) (#toolkit)
▹ Fix dust-balance wallet/ledger snapshot saved at block_height = 0 when dust_warp is enabled (#1574) (#toolkit)
▹ Accept ecdsa: seeds on chains forked from ledger 8 (#2181, #2183) (#toolkit, #ecdsa, #hardfork)
▹ toolkit-js deploy authority seed accepts the scheme prefix (ECDSA rejected) (#1861) (#toolkit, #ledger, #ecdsa, #contract-maintenance, #toolkit-js)
▹ Fix toolkit-js compactc-resolver on Node 24+ (#1711) (#toolkit)
▹ Fix v6/v7 verifier-key dispatch in ledger-9 contract maintenance (#1711) (#toolkit, #ledger9)
▹ Don't abort context replay on a well_formed failure the chain itself tolerated (#2098) (#toolkit, #bugfix)
▹ Fix self-funded register-dust-address for wallets with multiple NIGHT UTXOs (#1922) (#toolkit, #bugfix)
▹ Rename StandardTrasactionInfo to StandardTransactionInfo (#2016) (#toolkit, #refactor)
▹ Fix update-ledger-parameters command re-using the same param across multiple limits (#2073) (#toolkit)
▹ Do not create genesis state with Reserve having less than in reserve-config.json (#1791) (#toolkit)
▹ Fork-aware transaction generation across the ledger 8->9 hardfork (#1925) (#toolkit, #ledger9)
▹ Adapt toolkit to ledger 9.1.0.0-rc.2 crypto-stack split (#1692) (#toolkit)
▹ Adapt toolkit to ledger 9.1.0.0-rc.3 (#1738) (#toolkit)
▹ Lock redb fetch cache against concurrent toolkit processes (#1493) (#toolkit)
▹ Override toml to 4.3.0 to clear the npm audit gate (#2139) (#toolkit)
▹ Remove gdb from the toolkit image (#2187) (#toolkit, #docker, #security)
Clear the backlog of pending major dependency updates (#toolkit, #ci, #local-env)
CI base image: actions/cache to v6.1.0 and azure/setup-kubectl to v5.1.0,
both pinned by commit. Docker Compose moves to v5.5.0, which required installing
the buildx plugin alongside it - compose v5 removed its internal buildkit
builder and delegates build: to Docker Bake, so without buildx the
contract-compiler service in local-env's compose file no longer builds.
The paritytech/srtool "v1" offer was a false positive: published tags are
<rust version>-<srtool version>, and splitting that across an ARG and a
hard-coded prefix made Renovate read the rust half as the image version and
offer a tag that does not exist. The whole tag is now one ARG, so deterministic
runtime builds keep resolving.
Local environment: the contract-compiler base moves to node:24-slim (still
Debian bookworm, so the pinned apt package set is unaffected), and eslint moves
to v10. eslint 10 drops @eslint/eslintrc, which removes js-yaml from the tree
entirely - the only way the js-yaml major was ever going to resolve, since
eslintrc caps it at 4.x. Two things fell out: globals was a phantom dependency
that only resolved through eslint 9's transitive tree, and eslint 10's
preserve-caught-error rule caught a config-parse failure being re-thrown with
the original error discarded, which now attaches it as cause.
Toolkit: @types/node moves to 24 in util/toolkit-js, which already targeted
@tsconfig/node24. The redundant nanoid and js-yaml overrides entries are
removed - both were npm-audit remediations whose consumers have since raised
their own ranges, so they pinned exactly what npm would pick unaided, and
removing them leaves the lockfiles byte-identical.
▹ Fix sender reporting FAILED_TO_FINALIZE for txs whose including block finalized (#1943) (#toolkit)
▹ --no-watch-progress sends now fail when the pool rejects the transaction (#2138) (#toolkit)
▹ show-wallet reports claimable block-reward and bridge-transfer amounts (#1766) (#toolkit)
▹ Return errors instead of panicking in single-tx and fetcher (#1822) (#toolkit)
▹ Split midnight-ledger-helpers crate (#2106) (#toolkit)
▹ Give each ledger version its own copy of the builders (#2075) (#toolkit, #refactor)
▹ Store circuit zkir on-chain in test contract deploys (#1692) (#toolkit, #ledger9)
▹ Accept spec version 1.0.300 when replaying chain history (#2161) (#toolkit)
▹ Faster, resilient chain sync and wallet replay with working caching on mainnet (#1938) (#toolkit, #performance)
▹ Toolkit sender handles transaction errors with terminal-status messages. (#1323) (#toolkit)
▹ Dispatch toolkit-js variants by compactc version instead of ledger version (#1555) (#toolkit)
▹ Recognise the 1.0.3 runtime when fetching blocks (#2002) (#toolkit)
▹ Fix stack overflow in trusted_deserialize_tagged on long-running chains (#1576) (#toolkit)
▹ Update default CompactC version to 0.31.0 (#1555) (#toolkit)
▹ version subcommand reports the latest supported ledger version (#1649) (#toolkit)
#toolkit-js
🧰 Toolkit
Changed
▹ toolkit-js deploy authority seed accepts the scheme prefix (ECDSA rejected) (#1861) (#toolkit, #ledger, #ecdsa, #contract-maintenance, #toolkit-js)
#unshielded
🧰 Toolkit
Added
▹ Toolkit ECDSA unshielded signature support (#1837) (#toolkit, #ledger, #unshielded, #ecdsa)