Ledger v9.1.0.1 release notes
For the complete documentation index, see llms.txt
- Version: v9.1.0.1 (the builder packages carry 9.1.0.0, released on 4 November 2026)
- Date: November 6, 2026
High-level summary
Ledger 9.1.0.1 is the first ledger 9 release on Mainnet. The node embeds ledger 9.1.0.1, and the packages that DApp and wallet builders use carry ledger 9.1.0.0. Mainnet moved to ledger 9 at the ledger 9 network upgrade on 6 November 2026. On the same day, Preview was reset as a new chain that runs ledger 9.1.0.1. Preprod stays on ledger 8.1.3 until a later upgrade.
Ledger 9 is a new ledger version, not a patch. Its transaction format changes, and a transaction built for ledger 8 doesn't decode on ledger 9. DApps, wallets, indexers, and nodes that use Mainnet must move to the ledger 9 versions. Proof server 9.0.0 is the matching proof server. For what each role must do, and in what order, see the ledger 9 upgrade page.
Audience
This release note is most relevant for:
- Node operators and validators on Mainnet.
- DApp developers who deploy to or call smart contracts on Mainnet.
- Wallet developers and indexer operators who serve Mainnet.
- Developers who run the proof server against Mainnet.
- Developers who use the
ledger-v9oronchain-runtime-v4npm packages directly, or the ledger Rust crates.
Summary of updates
- Network: Mainnet runs ledger 9 after the ledger 9 network upgrade. Preview runs ledger 9 after its reset as a new chain. Preprod runs ledger 8.1.3 until a later upgrade.
- Compatibility: ledger 8 transactions don't decode on ledger 9. After the upgrade, wallets on wallet SDK 1.x can't transact on Mainnet, and Mainnet rejects transactions built with Midnight.js 4.x.
- Contracts: contract-to-contract calls and event emission, both in a first phase that covers unshielded data only.
- Cryptography: ECDSA signature verification, native Keccak hashing, and native secp256k1, all available to Compact smart contracts.
- Proving: version 3 of the zero-knowledge intermediate representation (ZKIR 3.2.0) across the proving stack and the Compact toolchain. Proofs move to
midnight-zk-stdlibv2 andmidnight-circuitsv7, and proofs and verifier keys made with zk-stdlib v1 stay verifiable. - Verifier keys: the verifier keys of some circuits change, so affected smart contracts need their keys regenerated.
- Contract maintenance: maintenance updates can insert and remove the IR of a contract operation.
- Treasury: a new
UnlockToTreasurysystem transaction moves funds from the locked pool to the treasury. - Fees: a fee floor,
min_block_price, applies from the first block after the upgrade, so fees rise slightly. Separate cost factors for validation, guaranteed application, and fallible application replaceparallelism_factor. - Security: ledger 9 carries forward the security fixes released to Mainnet as ledger 8.1.2 and 8.1.3.
- DUST: DUST state resets once at the upgrade. On Mainnet, every DUST registration is replayed automatically to its full cap, so Mainnet users don't need to do anything.
- Proof server: proof server 9.0.0 is the proof server for ledger 9. Its default job capacity is now 10.
- Packages:
@midnightntwrk/ledger-v91.0.0,@midnightntwrk/onchain-runtime-v44.0.0, and@midnightntwrk/zkir-v22.2.0 on npm. This is also the first release of the ledger 9 crates on crates.io, including the newmidnight-ledger-v9crate at 1.0.0.
New features
Contract-to-contract calls and events
A smart contract on ledger 9 can call another smart contract in the same transaction. A smart contract can also emit events, which DApps can observe through the indexer API. Both features are in a first phase and cover unshielded data only. Events need ledger 9, indexer 4.4.101, Compact toolchain 0.36.0, and Midnight.js 5.0.0 together.
To use these features, compile your smart contract with Compact toolchain 0.36.0, which uses language version 0.28.0 and Compact runtime 0.21.0.
New cryptographic primitives
Ledger 9 adds ECDSA signature verification in the Compact runtime, native Keccak hashing, and native secp256k1. Compact smart contracts can use all three as primitives.
ZKIR version 3
Ledger 9 uses version 3 of the zero-knowledge intermediate representation (ZKIR 3.2.0). The proving stack and the Compact toolchain both move to it.
Proving with zk-stdlib v2
Ledger 9 generates proofs against midnight-zk-stdlib v2 and midnight-circuits v7. Proofs and verifier keys made with zk-stdlib v1 stay verifiable, and Zswap verification keeps accepting v1 proofs.
Contract maintenance of circuit IR
A contract maintenance update can insert or remove the IR of a contract operation. In the ledger WASM bindings these updates are IrInsert and IrRemove. Ledger 9 adds the IrAlreadyPresent and IrNotFound errors for these updates.
Treasury unlock
The UnlockToTreasury system transaction moves funds from the locked pool to the treasury.
Protocol token bridge
Ledger 9 carries support for the cNIGHT to mNIGHT protocol token bridge. The upgrade doesn't turn it on for Mainnet. Turning it on is a separate governance action, and its rollout will be announced separately, so don't treat bridging as available. This release note doesn't cover using the bridge.
Proof server 9.0.0
The proof server image for ledger 9 is midnightntwrk/proof-server:9.0.0. Pin it by image digest. The port stays 6300. The default job capacity changes from 0 (no limit) in proof server 8.1.3 to 10, so a busy proof server returns HTTP 429 when its job queue is full. To change the limit, set --job-capacity or the MIDNIGHT_PROOF_SERVER_JOB_CAPACITY environment variable.
On Mainnet and Preview, use proof server 9.0.0. On Preprod, keep using proof server 8.1.3.
New features requiring configuration updates
Ledger parameters gain the price floor and the validation_factor, guaranteed_factor, and fallible_factor fields, and lose parallelism_factor. Tooling that constructs or serializes LedgerParameters must supply the new fields. The initial validation_factor of 1/4 carries over the previous parallelism_factor of 4.
Deprecations
Ledger 8 is no longer accepted on Mainnet after the ledger 9 network upgrade. Preview no longer runs ledger 8 after its reset. Ledger 8 stays in use on Preprod until its upgrade.
Breaking changes or required actions
The ledger 9 network upgrade changes the ledger that Mainnet runs. Each role has its own steps, and the ledger 9 upgrade page lists them in order. In short:
- Node operators and validators: upgrade every Mainnet validator and RPC node from node 1.0.400 or 2.1.100 directly to node 2.1.101 before the governance upgrade. A node on 1.0.400 stops at the upgrade block. For the steps, see the node 2.1.101 release notes.
- DApp developers: move to wallet SDK 2.0.0, Midnight.js 5.0.0, and indexer 4.4.101. Midnight.js 5.0.0 refuses to submit a ledger 8 transaction to a ledger 9 network with
EraMismatchError, and wallet SDK 2.0.0 refuses a mismatched transaction withProtocolVersionMismatchError. A ledger 8 transaction that is still pending at the upgrade ends in theOrphanedstate. - Smart contract developers: compile new smart contracts with Compact toolchain 0.36.0 (language version 0.28.0). The tested upgrade rehearsal checks that a smart contract deployed before the upgrade can still be called and that a smart contract compiled with 0.36.0 deploys. In an earlier devnet test, smart contracts built with Compact toolchain 0.31.1 kept working without a recompile when the ZK config provider uses
verify: 'require-if-present', and Midnight.js 5.0.0 refuses artifacts from other toolchains, such as 0.30.0 or 0.35.0, withEraMismatchError. Recompiling a contract that an earlier toolchain built changes its verifier keys, so moving a deployed contract to 0.36.0 needs a maintenance update. For how recompiling changes verifier keys, see the ledger 9 upgrade page. - Indexer operators: run indexer 4.4.101 and re-index from genesis. This indexer stores contract state in a new layout, and you can't upgrade an existing database in place. The indexer then follows the chain across the upgrade by itself.
- Wallet developers: move to wallet SDK 2.0.0. Wallets detect the upgrade when
protocolVersionreaches 2000000 or higher. Drop any cached DUST tree indices at that point, because the indexer sends no dedicated reset event. - Proof server users: on Mainnet, run proof server 9.0.0, pinned by image digest.
- Package users: the ledger 9 npm packages are
@midnightntwrk/ledger-v9and@midnightntwrk/onchain-runtime-v4. The on-chain runtime moves from the v3 line to the v4 line, and the major version is in the package name, not in a version range, so change the dependency to@midnightntwrk/onchain-runtime-v44.0.0. The npm version ofledger-v9doesn't match the ledger version: ledger 9.1.0.0 isledger-v91.0.0. Pin exact versions. Don't rely on thelatestdist-tags of these packages, which have pointed to release candidates.
Verifier keys
midnight-circuits 7.3.0 and midnight-zk-stdlib 2.4.0 change the verifier keys of ZKIR v2 circuits that use hash_to_curve, and of ZKIR v3 circuits that encode a Jubjub scalar. V0 and V1 keys don't change. Smart contracts with affected circuits need their verifier keys regenerated.
Ledger parameters and Rust APIs
parallelism_factoris removed from the ledger parameters, andvalidation_costreturns a cost with the factor applied.- Signing envelopes now share one construction. Code that builds them by hand must move to it.
- The default
IrMinorVersionis nowV2, andVersionedInnerPKis removed. - In
onchain-vm,Key::ValueandOp::PushholdAlignedValueCheckedin place ofAlignedValue. Rust code that constructs them directly must convert withAlignedValueChecked::try_from. - Decoding and validation are stricter, and reject data and contract calls that earlier ledger 9 release candidates accepted.
apply_guaranteed_onlyandGuaranteedApplyResultallow split-phase transaction execution with deferred event generation.- The ledger WASM bindings expose
lookup_keyon the proving path, so the prover uses the right key version, and thecontractLogvariant ofEventDetails, which matches the new on-chain event format. - The npm packages are published under the
@midnightntwrkscope. The legacy@midnight-ntwrkscope still receives releases for now.
Ledger era in the Midnight.js and Compact.js types
The types in Midnight.js 5.0.0 and Compact.js 3.0.0 are aware of the ledger era. Code that assumed a single ledger era must now select one explicitly. Rebuild against the new API and select the era.
Contract action subscriptions
An indexer subscription to contract actions that you open without an offset now delivers only new actions. It no longer replays the history of the smart contract. To replay history, pass an explicit offset, such as height 0. Midnight.js 5.0.0 does this. Midnight.js 4.x doesn't, and receives no history.
The indexer also serves state from after the upgrade for smart contracts that no transaction has touched since the upgrade.
DUST at the upgrade
DUST state resets once at the ledger 9 network upgrade. NIGHT balances don't change.
- Mainnet: every DUST registration on Mainnet is backed by cNIGHT, and the network replays all of them automatically after the upgrade, straight to their full DUST cap. Mainnet users don't need to do anything.
- Transactions during the replay: the replay takes about 48 blocks, under five minutes on a recent Mainnet snapshot, and ends with a
DustReapplyCompletedevent. Transactions submitted while it runs wait in the transaction pool and are included once it ends. - Wallets and indexers: wallets must run wallet SDK 2.0.0, because wallets on wallet SDK 1.x can't transact after the upgrade. Indexers must run 4.4.101 to report DUST capacity correctly.
- Preview: Preview was reset as a new chain, so nothing is replayed. Request tNIGHT from the Preview faucet and register for DUST generation again.
- Preprod: when Preprod upgrades later, DUST registrations that cNIGHT doesn't back are cleared, and wallets and the faucet register their DUST address again. Expect a gap in faucet service on Preprod during its upgrade window.
Fees
Ledger 9 adds a fee floor, min_block_price, which ledger parameters govern. It applies from the first block after the upgrade, so fees rise slightly. Ledger 9 also uses a new cost model: validation_factor, guaranteed_factor, and fallible_factor replace parallelism_factor and apply to compute cost only, and validation_cost now returns the cost with the factor applied. Update fee estimation in wallets and DApps to respect the floor before the upgrade.
Ledger error changes
If you match on ledger error names, GenerationInfoAlreadyPresent is now InitialNonceAlreadyPresent, and DustLocalStateError no longer has a BackingNightNotFound variant. New errors are ZeroValueUtxo, ContractMetadataTooLarge, ContractAuthorityMetadataTooLarge, IrAlreadyPresent, IrNotFound, MetadataTooLarge, AuthorityMetadataTooLarge, and UnknownVerifierKeyVersion. For the details, see the ledger error reference.
Bug fixes and quality improvements
| Component | Description |
|---|---|
| ledger | DUST registration accounting uses the block time rather than the time the transaction declares. |
| ledger | The cost heuristic is tighter, so fewer transactions move to the fallible section. |
| ledger | Refines gas accounting for transcripts that both write and delete state. |
| ledger, zswap, storage | Several edge cases in DUST, cost, and delta accounting saturate instead of overflowing, and paths that could panic now return an error. |
| ledger | ContractOperationVersionedVerifierKey::V3 and V4 serialize independently. |
| transient-crypto | Coin ciphertext decryption correctly excludes the identity point. |
| zkir-wasm | In-process DUST spend proofs are no longer rejected with InvalidDustSpendProof (midnight-ledger#832). |
| base-crypto | Moves to k256 0.14 and signature 3. transient-crypto no longer depends on either. |
Known issues
- Wallets and DApps that haven't moved to wallet SDK 2.0.0 can't transact on Mainnet after the upgrade. Check with your wallet provider for a ledger 9 release.
- Bridging NIGHT between Cardano and Midnight isn't available at the upgrade. The protocol token bridge stays off until governance enables it, and its rollout will be announced separately.
- Block production rewards aren't part of ledger 9.
- A contract call that spends a shielded coin the contract already holds and writes the change back with
writeCoincan be rejected withCustom error: 104(ran out of gas budget) on a chain whose commitment tree isn't empty. There's no workaround in this release, and a fix is planned in a follow-up release. Track it in the ledger issue for thewriteCoingas error. - A contract call paid with exactly one DUST spend can fail with
OutsideTimeToDismiss, while the same call with zero, two, or more DUST spends is accepted. To avoid it, pay with two or more DUST spends. A fix is planned in a follow-up release. Track it in the ledger issue for single DUST spend rejections.