Skip to content

node-1.0.0

Choose a tag to compare

@github-actions github-actions released this 20 May 09:42
f4a4cd5

Midnight Node 1.0.0

Release date: 2026-05-20
Git tag: node-1.0.0
Tree hash: a748db6ce78ccbd9b6bb3571686b83f849c7dc59
Environment: All public networks at time of release. For the full compatibility matrix, see the release notes overview.

Docker Images

docker pull midnightntwrk/midnight-node:1.0.0
docker pull midnightntwrk/midnight-node-toolkit:1.0.0

High-level summary

Midnight Node 1.0.0 is the mainnet GA release. It bumps spec_version to 1_000_000 and bumps transaction_version to 3. The runtime adopts TransactionExtension (replacing the deprecated SignedExtension), tightens the throttle pallet, lands the Midnight-side handler hooks for the Cardano-to-Midnight bridge (the bridge itself is not enabled at this release — preparatory plumbing only), and migrates to measured benchmark weights. The node aligns with the polkadot-stable2603 Substrate SDK, gains a self-describing rpc.discover OpenRPC v1.4 endpoint, and picks up midnight-ledger 8.1.0 along with a number of audit-driven hardenings. The toolkit ships as an independently versioned image with substantial new transaction-generation, caching and observability features. Runtime upgrade required. SDK consumers using polkadot.js or subxt see no breakage — the new AuthorizeCall and WeightReclaim extensions are zero-sized, so the encoded transaction bytes are unchanged; only the implicit transaction_version mixed into the signature hash differs, which live signers fetch from chain state on every sign. The only genuine breakage is pre-signed extrinsics held across the upgrade boundary, and that is true for any spec_version bump.

Audience

These release notes are intended for:

  • Node operators (all networks): Required upgrade. Roll the binary, then submit the runtime upgrade. Re-check networkId against your chainspec (now validated on boot).
  • DApp developers / SDK consumers: No action required for live signing. polkadot.js / subxt fetch transaction_version and spec_version from chain state on every sign, and the two new TransactionExtension entries are zero-sized — encoded tx bytes are unchanged. Pre-signed extrinsics held across the upgrade need re-signing (same as any spec_version bump). Use rpc.discover if you generate clients from spec.
  • Toolkit users / load-test operators: Required upgrade. Toolkit is now independently versioned and ships a new structured-logging stack, new show-block, batch-single-tx, and per-seed caching subcommands.
  • Governance signers: New proposal_weight_bound parameter required on motion_close. Toolkit runtime-upgrade / update-ledger-parameters now accept long-form --council-members / --technical-committee-members.
  • Cardano bridge consumers: Heads up — the Cardano-to-Midnight bridge is not enabled at 1.0.0. The handler hooks ship in the runtime so you can develop against the on-chain shape (handlers return a value attached to bridge events, each transfer carries McTxHash), but no transfers flow until the bridge is turned on in a later release.

What Changed

Change Upgrade Type PR
Cardano-to-Midnight bridge handler implementation (events, McTxHash, handler return value) — preparatory only, bridge not enabled Runtime upgrade #1188
Migrate runtime from SignedExtension to TransactionExtension (adds AuthorizeCall, WeightReclaim); transaction_version 2→3 Runtime upgrade (wire-format change, SDK-transparent via metadata) #597
Align node, runtime, relay and partner-chains with polkadot-stable2603 SDK Runtime upgrade #1299
Align node and runtime with polkadot-stable2512-3 SDK Runtime upgrade #1262
Throttle pallet: per-account transaction-count limit (MaxTxs); AccountUsage migration Runtime upgrade (storage migration) #1060
motion_close gains proposal_weight_bound; promoted to DispatchClass::Operational Runtime upgrade (extrinsic signature change) #1032
Use measured benchmark weights across FRAME and local pallets Runtime upgrade #1495
Early block-weight check in midnight pallet pre_dispatch Runtime upgrade #1305
Remove stale cost model stubs; re-enable test_get_mn_transaction_fee Runtime upgrade (audit) #839
Bump midnight-ledger to 8.1.0 (storage-core 1.2.0 incremental GC; race-condition, panic, leak, lock-ordering fixes) Node upgrade #1301, #1510
Bump midnight-storage-core to 1.2.0-rc.2 Node upgrade #1388
rpc.discover endpoint serving OpenRPC v1.4 spec (16 custom + 52 Substrate methods, JSON Schema types) Node upgrade (new API) #869
Validate networkId on node boot against genesis state Node upgrade #1265
Reject unsupported system transaction types (no more wildcard "unknown" accept) Node upgrade (audit) #840
Validate genesis file type / size (>10 MB, symlinks, non-regular files rejected) Node upgrade (audit) #832
unsafe_allow_symlinks config option (default off) Node upgrade #1372
Redact DB host/port/dbname from error logs (full details at debug level) Node upgrade #1067
ssl_root_cert configuration option for Postgres Node upgrade #1029
Per-SQL-query Prometheus timing for midnight data-source queries Node upgrade #904
In-memory cache for multi_asset.id lookups (removes repeated JOIN multi_asset from cNight queries) Node upgrade (perf) #934
Coarse tx / tx_out / ma_tx_out id-range bounds for cNight observation queries (prune before joins) Node upgrade (perf) #1365
Improve logging for malformed ledger transactions Node upgrade #961
Reduce cNIGHT observation address logs from error to debug Node upgrade #905
Fix chain-state truncation after unclean shutdown (explicit DB drop) Node upgrade (correctness) #1140
Drop ledger default storage on graceful shutdown Node upgrade #886
Remove hard-fork test ledger version dependencies / cfg(hardfork_test) Node upgrade #1024
Point to midnightntwrk partner-chains fork Node upgrade #948
Bump vulnerable deps (rustls-webpki, astral-tokio-tar) — RUSTSEC-2026-0049 / 0066 Node upgrade (security) #1079
Bump node version to 1.0.0 Node upgrade #919
Toolkit images versioned independently (toolkit-X.Y.Z tags) Toolkit #1261
Toolkit JSON log format change (drops structured_logger for tracing_subscriber) Toolkit (BREAKING — log format) #899
Toolkit --log-json, --verbose, --quiet, --verbose-fetch, --verbose-ledger; pretty default Toolkit #859, #899
Toolkit show-block diagnostic command Toolkit #1068
Toolkit batch-single-tx bulk transaction generation; file-based caches; --seeds on fetch Toolkit (perf) #820, #939
Toolkit support for multiple shielded coin inputs in single-tx / batch-single-tx / batches Toolkit #1216
Toolkit support for fallible contract calls and fallible inputs Toolkit #888, #966
Toolkit zswap state chaining in batched intents Toolkit #879
Toolkit LEDGER_VERSION override for multiple ledger stacks Toolkit #946
Toolkit contract_custom builder enabled for ledger 7 Toolkit #864
Toolkit batched block-number-to-hash RPC during sync Toolkit (perf) #1263
Toolkit upgrade subxt v0.44 → v0.50 Toolkit #1229
Toolkit restore --council-members / --technical-committee-members long-form flags Toolkit #875
Toolkit cap intent file reads at 64 MB Toolkit (security) #874
Toolkit checked arithmetic in offer creation and wallet seed increment (audit Issue AL) Toolkit (audit) #942, #1081
Toolkit cleanup nullifier/nonce on fork export path; redact new_authority in CLI logs Toolkit #1074
Toolkit cryptographically secure RNG for parent block hash fallback Toolkit (audit) #878
Toolkit error propagation in ledger state updates and save_intents_to_file Toolkit (audit) #927, #873
Toolkit remove verbose println! from ledger helpers Toolkit (audit) #936
Toolkit fix DustWallet spend state propagation (audit Issue AO) Toolkit (audit) #877
Toolkit fix using nullifier as nonce when encoding zswap state Toolkit (correctness) #895
Toolkit regression tests for nonce/nullifier distinction (audit Issue E) Toolkit (audit) #1128
Toolkit fix Dust address format to match specification Toolkit (correctness) #1059, midnight-architecture#190
Toolkit fix missing persist() and recursion depth on context fork Toolkit #881
Toolkit fix panic when first block has no midnight transactions Toolkit #1045
Toolkit add support for node 0.20.1 runtime version Toolkit #827
Toolkit tracing for structured log fields; new diagnostic logs Toolkit #1230, #1058, #1030
Slim node Docker image ~200 MB via multi-stage build; pin libfaketime 0.9.10 Infrastructure #897
Content-hash Docker tags (skip rebuild when tree unchanged) Infrastructure #783
Cardano hard-fork script for local-env Infrastructure #1326
CI permissions/workflow hardening; bot TOCTOU + expression-injection fixes; actionlint Infrastructure (security) #855, #848, #861
Bump srtool image to Rust 1.93.0 Infrastructure #1497
Migrate Renovate to org-wide hardened preset Infrastructure #1118
Devnet chainspec rebuilt against runtime 0.22.0 to match mainnet baseline (devnet only) Infrastructure (chainspec) #1341

New Features

Cardano-to-Midnight bridge handler

⚠️ The C-to-M bridge is not yet ready for use and is not enabled at this release. The runtime ships the handler hooks so that the bridge plumbing is in place when it is turned on in a later release; nothing flows across the bridge today. Integrators should treat this as preparatory work, not a live feature.

Description: Implements the Midnight-side handler for the Cardano-to-Midnight (C-to-M) bridge. The bridge plumbing now emits events for each transfer, each call carries an McTxHash (Cardano transaction hash) so an inbound transfer would be traceable end-to-end, and the handler returns a value that is attached to the resulting bridge event. The runtime ships an implementation of this handler so that downstream products can develop against the on-chain shape ahead of the bridge being enabled. Tracking issue: #1083.

Runtime upgrade (preparatory — not enabled).#1188

Self-describing JSON-RPC API (rpc.discover / OpenRPC v1.4)

Description: Registers a standards-compliant rpc.discover JSON-RPC method that returns a complete OpenRPC v1.4 document describing the node's API. 16 custom Midnight methods are fully documented with parameter types, return types, errors and descriptions; 52 standard Substrate methods are listed as reference entries; JSON Schema type definitions for every response type are generated via schemars; a static docs/openrpc.json is committed for offline access; CI drift-detection tests keep the schema in sync with registered methods. DApp developers, SDK authors and API tooling can now generate clients, validate requests and discover capabilities without reading the node source.

Node upgrade.#869

Throttle pallet: per-account transaction-count limit

Description: The existing per-account throttle (byte limit, rolling window) is extended with a per-account transaction-count limit (MaxTxs) over the same rolling block window. AccountUsage storage migrates from a 2-field tuple to a UsageStats struct that adds txs_used; the old map is cleared on upgrade. Operators get a second axis to throttle pathologically-busy accounts; users see clearer error semantics when they trip the limit.

Runtime upgrade with storage migration.#1060

Diagnostic show-block toolkit command

Description: New diagnostic subcommand to inspect individual blocks — metadata, deserialized transactions — with human-readable and JSON output. Reads from the fetch cache first and falls back to live node RPC on cache miss. Intended for support / triage workflows where you want to look at exactly one block without spinning up a fetcher.

Toolkit.#1068

Bulk transaction generation: batch-single-tx, file-based caches

Description: New batch-single-tx subcommand for bulk transaction generation, plus file-based wallet and ledger-state caches (default cache directory moved to ./toolkit_cache). The fetch subcommand gains --seeds to allow caching wallet states alongside the fetch cache. Together these materially improve block-replay and transaction-generation throughput in load tests.

Toolkit.#820, #939

Per-SQL-query Prometheus timing for cNight data source

Description: Midnight-specific data sources (cNight observation, federated authority, candidates) record individual Prometheus timing histograms per SQL query against db-sync. 13 sub-query timers are exposed at :9615/metrics under midnight_data_source_query_time_elapsed{query_name=...}. Operators can finally pinpoint which query is the long pole in a given observation cycle without reaching for pg_stat_statements.

Node upgrade.#904

motion_close weight bound

Description: The motion_close governance extrinsic now takes a proposal_weight_bound parameter following the pallet_collective::close pattern. The previous version declared a constant weight that did not account for the inner Root-dispatched call (Substrate can refund weight post-dispatch but never increase it). The extrinsic is also promoted to DispatchClass::Operational to match the rest of the governance extrinsics. Toolkit and upgrader are updated to pass the new parameter.

Runtime upgrade (extrinsic signature change).#1032

New Features Requiring Configuration Updates

--max-tx-gas-cost transaction-pool filter (carried forward from 0.22.5)

Required updates:

  • If you want to cap accepted transactions by estimated gas cost, set --max-tx-gas-cost <limit> on the CLI or MAX_TX_GAS_COST=<limit> in the environment. CLI takes precedence when both are set.
  • Leaving both unset preserves unbounded behaviour.

Impact: Non-breaking when unset. When set, transactions exceeding the limit are rejected at the pool gateway before validation.

ssl_root_cert Postgres TLS option

Required updates:

  • Operators using PostgreSQL over TLS may now configure ssl_root_cert in the cNight observation config to pin the root CA bundle.

Impact: Optional; existing configs continue to work.

unsafe_allow_symlinks file-loading option

Required updates:

  • If you intentionally load chainspec / config files via symlinks, set unsafe_allow_symlinks = true. The default is false (symlinks rejected) following the genesis-file audit fix in #832.

Impact: Default behaviour change for operators with symlinked config paths — they must either resolve the symlink or opt in explicitly.

networkId validation on boot

Required updates:

  • The node now refuses to start if the chainspec's networkId disagrees with the networkId baked into the genesis state. Confirm both sides match before rolling the binary.

Impact: Misconfigured environments will now fail loud at boot instead of producing a chain that cannot be re-synced.

Improvements

  • polkadot-stable2603 Substrate SDK alignment across node, runtime, relay and partner-chains. Pulls in SessionKeys::generate_session_keys taking an owner, sc_service::build_network taking a spawn_essential_handle, and a swathe of upstream type renames (RuntimeDebugNoBoundDebugNoBound, BeefySignatureHasher removal, etc). (#1299)
  • polkadot-stable2512-3 SDK alignment as an intermediate step: Core::execute_block and BlockBuilder::check_inherents now use LazyBlock; SpawnTasksParams requires tracing_execute_block; MmrApi v3 gains generate_ancestry_proof. (#1262)
  • Runtime now uses measured benchmark weights for GRANDPA, BEEFY MMR, timestamp, migrations, scheduler, preimage, tx-pause, council and technical committee collectives/memberships, session validator management, federated authority + observation, system parameters, and cNIGHT observation. (#1495)
  • Early block-weight check in pallet-midnight's pre_dispatch short-circuits over-budget transactions before expensive ledger validation. (#1305)
  • Bumps midnight-ledger to 8.1.0 (storage-core 1.2.0 incremental GC, shared-ParityDB-backend access; fixes for force_as_arc race, Sp serialization panic, pending-Updates memory leak, lock-ordering violation; finer-grained WASM wallet bindings). All midnight-ledger workspace crates resolved from crates.io at 8.1.0; the previous [patch.crates-io] block has been removed. (#1301, #1510)
  • Explicit DB-backend drop after tokio shutdown drains parity-db's WAL pipeline, preventing silent chain-state truncation after SIGTERM. (#1140, #886)
  • DB connection strings, governance keys, and address-decoder noise no longer leak through error logs. (#1067, #1074, #905)
  • Genesis-file loader rejects symlinks, non-regular files, and files larger than 10 MB by default (audit Issue AI). (#832)
  • System-transaction handler now rejects unrecognized variants with an explicit error rather than silently labelling them "unknown" in metrics (audit). (#840)
  • Toolkit hardening: checked arithmetic for offer / seed math, error propagation in ledger state updates and intent persistence, CSPRNG for parent-block-hash fallback, intent reads bounded at 64 MB (audit). (#942, #1081, #927, #873, #878, #874)
  • DustWallet spend-state propagation fix prevents utxos() returning already-spent outputs in consecutive spends (audit Issue AO). (#877)
  • Zswap state-chaining support in batched intents; multiple shielded coin inputs combine across single-tx / batch-single-tx / batches. (#879, #1216)
  • Toolkit fetch sync batches block-number-to-hash RPC calls into single requests, materially reducing round trips. (#1263)
  • cNight db-sync observation queries cache multi_asset.id lookups, removing repeated JOIN multi_asset from the registration, deregistration, asset-create, asset-spend and candidate-token paths. (#934)
  • cNight observation queries now pre-bound tx / tx_out / ma_tx_out ids for the requested block-range window, so Postgres can prune rows by primary key before doing the expensive joins. Same bounding extended to the tx_in-keyed spend / deregistration queries. (#1365)
  • Node Docker image trimmed ~200 MB by moving the build toolchain into a builder stage and pinning libfaketime to 0.9.10. Image tags now derive from a 12-char tree content hash so identical trees skip redundant rebuilds. (#897, #783)
  • Security advisories fixed via dep bumps (rustls-webpki 0.103.4→0.103.10 for RUSTSEC-2026-0049; astral-tokio-tar 0.5.6→0.6.0 for RUSTSEC-2026-0066). (#1079)
  • Removed all cfg(hardfork_test) infrastructure and *-hf ledger deps; hard-fork e2e tests no longer require a separate node binary. (#1024)
  • Toolkit images are now released independently of the node (toolkit-X.Y.Z tag format). (#1261)

Deprecations

SignedExtension / SignedExtra (runtime extension type)

Deprecated item: pallet-style SignedExtension / SignedExtra type alias
Starts: 1.0.0 (replacement landed)
Full removal: not scheduled — the upstream Substrate API has been replaced; downstream code that referenced the old type alias must move to TxExtension.
Replacement: TransactionExtension / TxExtension, with AuthorizeCall and WeightReclaim extensions; runtime now implements CreateTransaction, CreateBare, CreateSignedTransaction, and CreateAuthorizedTransaction.
Migration steps: Live signing through polkadot.js / subxt continues to work unchanged — the new extensions are zero-sized, so the encoded transaction byte format is identical; only the implicit transaction_version (2 → 3) and spec_version mixed into the payload hash change, and live signers fetch those from chain state. Custom Rust signers that built SignedPayload against the removed runtime::SignedExtra alias need to rename it to runtime::TxExtension and adopt the new positional tuple shown in PR #597.

Toolkit structured_logger (JSON log format)

Deprecated item: legacy structured_logger JSON output format
Starts: 1.0.0
Full removal: 1.0.0 (removed in this release)
Replacement: tracing-subscriber JSON output. Use --log-json to opt in.
Migration steps: Update any log-shipping pipelines that parsed the old structured_logger shape. The new shape (tracing-subscriber JSON layout — timestamp / level / fields.message / target) is illustrated in the "Toolkit JSON structured-log format changed" entry below.

Toolkit positional new_authority argument on maintain-contract

Deprecated item: positional new_authority arg on the maintain-contract subcommand
Starts: 1.0.0
Full removal: 1.0.0 (removed in this release)
Replacement: --new-authority named flag
Migration steps: Update scripts that invoke maintain-contract to pass --new-authority <key>.

*-hf ledger feature flags / cfg(hardfork_test) / cfg(hardfork_test_rollback)

Deprecated item: hard-fork-test conditional compilation infrastructure
Starts: 1.0.0
Full removal: 1.0.0
Replacement: hard-fork e2e tests no longer require a separately-built binary.
Migration steps: CI configs that special-cased a hard-fork build can drop that machinery.

Breaking Changes or Required Actions

⚠️ This release bumps spec_version from 22_000 to 1_000_000 and transaction_version from 2 to 3. The encoded transaction byte format is unchanged — both new TransactionExtension entries (AuthorizeCall, WeightReclaim) are zero-sized. The only signing-affecting change is the implicit transaction_version value mixed into the payload hash; live signers fetch this from chain state and so handle it transparently. The path that breaks is pre-signed extrinsics held across the upgrade, which is true of any spec_version bump.

transaction_version bumped to 3 (SignedExtensionTransactionExtension)

What changed: The runtime migrated from the deprecated SignedExtra / SignedExtension pattern to TransactionExtension. AuthorizeCall<Runtime> is prepended and WeightReclaim<Runtime> is appended to the extension tuple. Both are PhantomData newtypes with type Implicit = () — they SCALE-encode to zero bytes in the extrinsic and contribute zero bytes to additional_signed. The runtime additionally implements CreateTransaction, CreateBare, CreateSignedTransaction, and CreateAuthorizedTransaction for offchain transaction creation. transaction_version was bumped from 2 to 3 to signal the metadata change to clients that gate on the version field.

What breaks (and what doesn't):

  • Transparent for live signing. polkadot.js / @polkadot/api and subxt read transaction_version from chain state on every sign and embed it in the signing payload — the same way they handle spec_version rotations. The encoded tx bytes are unchanged; only the implicit values mixed into the payload hash differ, and the SDK fetches the current values automatically. App code calling tx.signAndSend(account) keeps working without modification.
  • Needs re-signing. Extrinsics signed before the upgrade and held for later submission will fail signature verification (BadProof) at the new runtime — same as any release that bumps spec_version.
  • Needs a metadata refresh. Long-lived clients and offline signers should invalidate cached metadata and reconnect once the upgrade is observed. Hardware wallets that gate signing on metadata hash will reprompt the user — by design.
  • Needs a code change. Custom Rust code that constructs SignedPayload directly (bypassing subxt and the runtime's CreateSignedTransaction impl) must use runtime::TxExtension instead of the removed runtime::SignedExtra and add () slots at front and back of the additional_signed tuple — they encode to nothing but their positions must match the type.

Required actions:

  • Most SDK consumers: nothing — verify your client reconnects after the upgrade and confirm transactions still go through.
  • Pre-signed transaction holders: re-sign against the 1.0.0 runtime.
  • Long-lived daemons that cache metadata: refresh on reconnect.
  • Custom encoders / out-of-tree forks of the runtime crate: rename SignedExtraTxExtension and add the two new positional slots.

Reference: PR #597 contains the full runtime/src/lib.rs diff, the benchmarking-harness diff, and the custom-signer tuple shape; the upstream polkadot-stable2603 sources for AuthorizeCall and WeightReclaim confirm type Implicit = () (i.e. zero-sized contribution to both the extrinsic and additional_signed).

Cardano-to-Midnight bridge handler API changed

What changed: Bridge calls now carry McTxHash per transfer; the handler is now expected to return a value attached to the resulting bridge event. The Midnight runtime implements this handler in 1.0.0.

What breaks: Out-of-tree handler implementations that match the old call shape will fail to compile / run. Downstream consumers relying on the old event shape must update.

Required actions:

  • Update any custom handler implementation to return an event-payload value.
  • Update event consumers to read the new McTxHash and handler-return fields.

Code example: see PR #1188 for the bridge call and handler-return-value shape.

motion_close gains required proposal_weight_bound parameter

What changed: motion_close now takes a proposal_weight_bound: Weight parameter and is dispatched as DispatchClass::Operational. Callers must pre-charge the inner Root call's weight.

What breaks: Any tooling that builds the old 2-argument motion_close call will fail to encode against the new metadata.

Required actions:

  • Update toolkit / upgrader / governance scripts to pass proposal_weight_bound. Toolkit and upgrader are updated in this release.
  • For external governance UIs, regenerate metadata bindings.

Code example: see PR #1032 (toolkit/upgrader call sites updated alongside the pallet change).

Throttle pallet AccountUsage storage migration

What changed: AccountUsage storage moves from a 2-field tuple to UsageStats (which adds txs_used). A migration clears the old map on upgrade.

What breaks: External indexers / consumers reading the raw AccountUsage storage layout will need to update.

Required actions:

  • If you query throttle pallet storage directly, regenerate types from the 1.0.0 metadata after the runtime upgrade.
  • No action required for normal users — accounts simply start with a fresh window post-migration.

Code example: see PR #1060 — the AccountUsage struct definition and the ClearAccountUsageV1 migration are in pallets/throttle/.

Toolkit JSON structured-log format changed

What changed: Toolkit drops structured_logger in favour of tracing_subscriber. JSON output now looks like:

{"timestamp":"2026-03-10T17:26:45.103688Z","level":"INFO","fields":{"message":"spawning 20 fetch workers","log.target":"midnight_node_toolkit::fetcher","log.module_path":"midnight_node_toolkit::fetcher","log.file":"util/toolkit/src/fetcher.rs","log.line":171},"target":"midnight_node_toolkit::fetcher"}

Default log output is now human-readable; pass --log-json to opt back in to JSON.

What breaks: Any log-shipping or alerting pipeline that parsed the previous flat key/value structure must be updated for the new nested fields / target / timestamp / level shape.

Required actions:

  • Update log parsers / dashboards.
  • If your environment defaults to JSON, add --log-json to the command line.

Code example: the new JSON shape is shown in the fenced block above; full context in PR #899.

Toolkit image tag scheme

What changed: The toolkit Docker image is now versioned from util/toolkit/Cargo.toml, independent of the node version. Toolkit-only releases use the toolkit-X.Y.Z tag format.

What breaks: CI that resolves the toolkit image by the node version will pull the wrong tag for toolkit-only releases.

Required actions:

  • Pin the toolkit image by its own version (midnightntwrk/midnight-node-toolkit:1.0.0 for this release; toolkit-X.Y.Z for later toolkit-only releases).

Known Issues

Error: config error: missing field unsafe_allow_symlinks

unsafe_allow_symlinks is a new config value that tells the node to follow symbolic links. This new field is required in this release, and will receive a default in a future release. Provide the argument to avoid the error, e.g. UNSAFE_ALLOW_SYMLINKS=true.

Initial sync performance

Description: Initial sync from genesis is still slow on some operator hardware (~0.2 BPS observed). Sync-perf optimisation work is in progress.
Issue: #1298
Workaround: None at present. Use a curated paritydb snapshot if one is published for your network; otherwise allow extra time on first bootstrap. Track the issue for progress.

Links and References

Fixed Defects

Defect Summary
#895, PM-21923 Toolkit: encoding zswap state used the nullifier as the nonce. Fixed; regression tests added (audit Issue E, #1128).
#1140 Node: chain-state truncation after unclean shutdown. Explicit DB-backend drop drains parity-db's WAL.
#877, PM-20016 Toolkit DustWallet: utxos() could return already-spent outputs across consecutive spends (audit Issue AO).
#881, PM-22124, PM-22253 Toolkit: missing persist() and recursion-depth blow-up on context fork.
#1045, PM-22361 Toolkit: panic when the first block contained no midnight transactions.
#1059 Toolkit: Dust address format was off-spec; aligned with midnight-architecture#190.
#942, PM-20206 Toolkit: silent overflow in offer-creation arithmetic now returns OfferBuildError (audit Issue AL).
#1081, PM-20017 Toolkit: wallet seed increment could panic / collide; returns explicit error on overflow.
#874 Toolkit: unbounded intent-file reads — capped at 64 MB.
#878, PM-20205 Toolkit: parent-block-hash fallback used a non-CSPRNG.
#840, PM-19971 Node: get_system_tx_type silently accepted unknown variants; rejects with explicit error.
#832, PM-19964 Node: genesis loader accepted symlinks / >10 MB files (audit Issue AI).
#1067, PM-19904 Node: DB connection details leaked through error logs.
#839, PM-19968 Ledger: stale cost-model stubs removed; test_get_mn_transaction_fee integration test re-enabled.
#1079, PM-22035 Security: rustls-webpki CRL-matching (RUSTSEC-2026-0049) and astral-tokio-tar PAX-extension (RUSTSEC-2026-0066) advisories addressed.
#1305 Runtime: expensive ledger validation no longer runs for transactions that won't fit in the block; rejected early with ExhaustsResources.
#1032, PM-22326 Governance: motion_close weight no longer underestimates the inner Root call (now passed proposal_weight_bound).
#1140, #886 Shutdown: ledger default storages explicitly released on graceful shutdown.
#905 cNIGHT: non-bech32 and no-delegation-part Cardano address logs demoted from error to debug.

Full Change Details

Changed

Upgrade ledger from 8.0.2 to 8.1.0-rc.1 (#1301) (#node)

Bumps the midnight-ledger dependency from 8.0.2 to 8.1.0-rc.1, picking up
new ledger types and conversion support.

PR: #1301
Issue: #1296

Add regression tests for nonce/nullifier distinction in zswap serialization (#1128, PM-22025) (#toolkit)

Add unit tests verifying that serialized zswap local state uses the coin
nonce (randomness), not the nullifier (spend identifier), for the nonce
field. Addresses Least Authority Q1 2026 Node DIFF audit Issue E.

PR: #1128
JIRA: https://shielded.atlassian.net/browse/PM-22025

Redact database connection details from error logs (#1067, PM-19904) (#node)

Database connection error messages no longer include the host, port, or database name at error level. Full connection details are available at debug log level for authorized troubleshooting.

PR: #1067
JIRA: https://shielded.atlassian.net/browse/PM-19904

Implements handler for C-to-M bridge (#1188) (#node, #runtime)

Updates bridge to emit events.
Updates call by adding McTxHash to each transfer.
Updates handler API: handler is expected to return a value that is attached to events.

Implements the handler in Midnight runtime.

PR: #1188
Required for #1083

Add validation for networkId on node boot to avoid mismatch with genesis state (#1265, PM-22422) (#node, #binary)

Adds validation to ensure the networkId set in the chainspec matches the
networkId used to generate the genesis state.

PR: #1265
Fix for: https://shielded.atlassian.net/browse/PM-22422

Fix DustWallet spend state propagation (#877, PM-20016) (#toolkit)

Fix DustWallet::speculative_spend to return the updated DustLocalState
alongside spends, and extend mark_spent to commit the state atomically
with nullifier recording. This ensures DustLocalState::spend's
pending_until flags are propagated, preventing utxos() from returning
already-spent outputs in consecutive spend operations.

Addresses Least Authority audit finding Issue AO.

PR: #877
JIRA: https://shielded.atlassian.net/browse/PM-20016

Align node and runtime with polkadot-stable2512-3 SDK (#1262) (#node, #runtime)

Bumps Substrate dependencies to the polkadot-stable2512-3 tag and updates call sites for breaking API changes: Core::execute_block and BlockBuilder::check_inherents now use LazyBlock; SpawnTasksParams requires tracing_execute_block (set to None unless trace RPC is wired); MmrApi v3 gains generate_ancestry_proof while BeefyApi no longer exposes it; pallet-version test mock implements Core with LazyBlock. Partner-chains and lockfiles are updated in line with the same SDK line.

PR: #1262
Required for #1244

Align node, runtime, relay, and partner-chains with polkadot-stable2603 SDK (#1299) (#node, #runtime, #partner-chains)

Bumps Substrate dependencies to the polkadot-stable2603 tag and updates call sites for breaking API changes.

PR: #1299
Required for #1245

Early weight check in midnight pallet pre_dispatch (#1305) (#node)

Add an early block weight check in ValidateUnsigned::pre_dispatch before
expensive ledger validation.

PR: #1305

Speed up toolkit syncing (#1263) (#toolkit)

Batch block-number-to-hash RPC calls into a single request.

PR: #1263

Speed up cNight db-sync observation queries (#1365) (#node)

Pre-query coarse tx / tx_out / ma_tx_out id bounds for the requested block-range window, then constrain the four cNight observation queries (registration, deregistration, asset create, asset spend) by primary-key range so postgres can prune rows before doing expensive joins. Extends the same tx.id bounding to the tx_in-keyed spend/deregistration queries.

PR: #1365

Cache multi_asset.id to avoid excessive joins (#934, PM-21995) (#node)

In-memory cache for multi_asset.id lookups, replacing repeated JOIN multi_asset with a single cached lookup per (policy, name) pair. Eliminates the multi_asset join from registration, deregistration, asset create/spend, and candidate token queries.

PR: #934

Reset devnet to runtime version 0.22.0 to match mainnet (#1341) (#chainspec)

Rebuilds the devnet chainspec against runtime version 0.22.0 so devnet matches the mainnet baseline ahead of the 1.0.0 runtime upgrade. Devnet only — no impact on mainnet / testnet operators.

PR: #1341

Point to midnightntwrk partner chains fork (#948, PM-22099) (#node)

PR: #948

Add unsafe_allow_symlinks config option when loading files (#1372) (#node)

Off by default.

PR: #1372

Bump vulnerable dependencies (#1079, PM-22035) (#node, #toolkit)

RUSTSEC-2026-0049 (rustls-webpki) and RUSTSEC-2026-0066 (astral-tokio-tar).

PR: #1079

Reject unsupported system transaction types (#840, PM-19971) (#audit, #client)

Replaces wildcard "unknown" labeling with explicit error (code 204).

PR: #840

Remove stale cost model stubs and re-enable integration test (#839, PM-19968) (#audit, #ledger)

PR: #839

Clean up Postgresql connection (#1029, PM-19924) (#node)

Add ssl_root_cert configuration option.

PR: #1029

Improve logging for ledger transaction errors (#961, PM-22311) (#node)

Warning log for malformed transactions.

PR: #961

Harden bot workflows against TOCTOU and expression injection (#848, PM-22117) (#ci, #security)

PR: #848

Bump srtool image to Rust 1.93.0 for konst 0.4.3 MSRV compatibility (#1497) (#ci)

PR: #1497

Remaining CI/CD security hardening (permissions, data flow, actionlint) (#861, PM-22116) (#ci)

PR: #861

Use content hashes for Docker image tags (#783) (#node, #ci)

Replace 8-char commit hashes with 12-char tree content hashes; identical trees skip rebuilds; force_rebuild escape hatch.

PR: #783

Fix chain-state truncation after unclean shutdown (#1140) (#node)

Explicit DB-backend drop after tokio shutdown drains parity-db's WAL.

PR: #1140

Drop ledger default storage on node shutdown (#886, PM-22219) (#ledger, #node)

Call midnight_node_ledger::drop_all_default_storage() after run_node_until_exit returns.

PR: #886

Bump version to 1.0.0 (#919) (#node)

PR: #919

Permissions hardening across all workflow files (#855, PM-22119) (#ci)

PR: #855

Reduce cNIGHT observation address logging level (#905) (#node)

Non-bech32 and no-delegation-part address logs demoted error→debug.

PR: #905

Remove hard-fork test ledger version dependencies (#1024, PM-22109) (#node)

Drops *-hf ledger deps and all cfg(hardfork_test*) machinery.

PR: #1024

Migrate Renovate to org-wide hardened preset (#1118, SRE-2078) (#sre)

PR: #1118

Slim down node Docker image by ~200 MB using multi-stage build (#897) (#node, #docker, #ci)

Confines build toolchain to a builder stage; pins libfaketime to v0.9.10.

PR: #897

Bump midnight-storage-core to 1.2.0-rc.2 (#1388)

PR: #1388
Issue: #1358

Validate genesis file type and size before reading (#832, PM-19964) (#audit)

Reject symlinks, non-regular files, and oversized files (>10 MB) before reading genesis/config files. Audit Issue AI.

PR: #832

Add proposal_weight_bound parameter to motion_close (#1032, PM-22326) (#runtime)

Follows pallet_collective::close. Made DispatchClass::Operational. Toolkit/upgrader updated.

PR: #1032

Bump midnight-ledger from 8.1.0-rc.1 to 8.1.0 (#1510) (#node)

Promotes the Ledger 8 pin from rc.1 to 8.1.0. storage-core 1.2.0 — incremental GC, shared ParityDB access; force_as_arc race, Sp serialization panic, pending-Updates leak, lock-ordering fixes. All midnight-ledger crates from crates.io; [patch.crates-io] removed.

PR: #1510

Use generated benchmark weights in runtime (#1495) (#runtime)

Connects generated weights for GRANDPA, BEEFY MMR, timestamp, migrations, scheduler, preimage, tx-pause, council/technical-committee, session validator management, federated authority + observation, system parameters, and cNIGHT observation.

PR: #1495

Add per-account transaction count limit to throttle pallet (#1060, PM-22377) (#runtime)

Extends throttle with MaxTxs rolling-window cap. AccountUsage migrates 2-tuple → UsageStats struct (txs_used). Storage migration clears old map.

PR: #1060

Migrate from SignedExtension to TransactionExtension (#597) (#runtime)

Adds AuthorizeCall, WeightReclaim; implements CreateTransaction, CreateBare, CreateSignedTransaction, CreateAuthorizedTransaction.

PR: #597

Toolkit: --log-json, --verbose, --quiet, --verbose-fetch, --verbose-ledger (#859, #899) (#toolkit)

Pretty default; structured JSON via --log-json; new fine-grained verbosity flags; RUST_LOG override.

PR: #859
PR: #899

Add Cardano hard fork script for local-env (#1326) (#local-env, #cardano)

PR: #1326

Enable contract_custom builder for ledger 7 (#864, PM-22229) (#toolkit)

Removes "not supported for ledger 7" error.

PR: #864

Add support for node 0.20.1 runtime version (#827, PM-22050) (#toolkit)

PR: #827

Add batch-single-tx command for bulk transaction generation (#820, #939, PM-22103) (#toolkit)

PR: #820
PR: #939

Add show-block command to toolkit (#1068, PM-22388) (#toolkit)

Diagnostic block inspector. Reads from cache, falls back to live RPC.

PR: #1068

Add option when generating intents to write out the contract on-chain state (#946, PM-22230) (#toolkit)

Adds multiple-Ledger-stack support to toolkit-js; LEDGER_VERSION env var override.

PR: #946

Add support for zswap state chaining (#879, PM-20404) (#toolkit)

PR: #879

Add file-based wallet and ledger state caching to toolkit (#820, #939, PM-22103) (#toolkit)

PR: #820
PR: #939

Bound intent file reads to 64 MB maximum size (#874) (#toolkit)

PR: #874

Replace unchecked arithmetic in offer creation with checked operations (#942, PM-20206) (#toolkit)

Audit Issue AL — as i128 casts and unchecked add/sub replaced with TryFrom/checked_add/checked_sub.

PR: #942

Replace unchecked addition in wallet seed increment with checked_add (#1081, PM-20017) (#toolkit)

Returns explicit error on overflow.

PR: #1081

Cleanup nullifier/nonce use in fork export path; redact new_authority in CLI logging (#1074) (#toolkit)

Mirrors fix from #895. maintain-contract new_authority becomes --new-authority named flag.

PR: #1074

Clean up toolkit logging (#1030) (#toolkit)

PR: #1030

Remove verbose println! logging from ledger helpers (#936, PM-22084) (#audit, #toolkit)

PR: #936

Propagate errors from save_intents_to_file (#873, PM-20209) (#audit, #toolkit)

PR: #873

Use cryptographically secure RNG for parent block hash fallback (#878, PM-20205) (#toolkit)

PR: #878

Replace expect calls with Result error propagation in ledger state updates (#927, PM-19977) (#toolkit, #security)

PR: #927

Upgrade subxt from v0.44 to v0.50 (#1229) (#toolkit, #relay)

PR: #1229

Restore long-form CLI flags for governance key arguments (#875, PM-22246)

--council-members / --technical-committee-members on runtime-upgrade and update-ledger-parameters.

PR: #875

Fix missing persist() on context fork causing "not in arena" errors (#881, PM-22124, PM-22253) (#toolkit)

Also fixes recursion-depth blow-up via get_lazy.

PR: #881

Fix panic if the first block doesn't have any midnight transactions (#1045, PM-22361) (#toolkit)

Scans all blocks; for RPC source queries get_network_id API.

PR: #1045

Add logs to help inspect on-chain contract state (#1058) (#toolkit)

PR: #1058

Change default cache location to ./toolkit_cache; add --seeds option to fetch (#939, PM-22103) (#toolkit)

Two separate caches (fetch + wallet-state).

PR: #939

Fix Dust address format to match the specification (#1059, midnight-architecture#190, PM-22375) (#toolkit)

PR: #1059

Fix using the nullifier as the nonce when encoding zswap state (#895, PM-21923) (#toolkit)

PR: #895

Toolkit images are now versioned independently (#1261) (#toolkit)

Versioned from util/toolkit/Cargo.toml; tags use toolkit-X.Y.Z.

PR: #1261

Drop structured_logger in favour of tracing_subscriber; Breaking JSON structured log format change (#899) (#toolkit)

New JSON shape — see migration guide.

PR: #899

Support multiple shielded coin input in single-tx, batch-single-tx and batches (#1216, PM-22405) (#toolkit)

PR: #1216

Improve toolkit block replay and transaction generation performance (#820, #939, PM-22103) (#toolkit)

PR: #820
PR: #939

Use tracing for structured log fields (#1230) (#toolkit)

PR: #1230

Added

Add rpc.discover endpoint with OpenRPC v1.4 API specification (#869) (#client, #node, #rpc, #api)

16 custom + 52 standard Substrate methods; static docs/openrpc.json; CI drift detection.

PR: #869

Add per-SQL-query Prometheus timing for midnight data source queries (#904, PM-22100) (#node)

13 sub-query timers at midnight_data_source_query_time_elapsed{query_name=...}.

PR: #904
JIRA: https://shielded.atlassian.net/browse/PM-22100

Add support for fallible contract calls (#888, PM-19839) (#toolkit)

PR: #888

Add support for fallible inputs (#966, PM-22302) (#toolkit)

PR: #966