Skip to main content

DApp updatability

This guide explains updatability in the Midnight Network and shows how to update a deployed contract's maintenance authority.

Overview

Updating code in a decentralized environment is challenging because producing an update typically requires a centralized process, which attackers can exploit maliciously. However, DApp developers often need ways to change deployed contracts, and Midnight provides this through Contract Maintenance Authorities (CMAs).

By default, an empty maintenance authority prevents any user from updating the contract. At deploy time, the deployer can nominate public keys and set a signature threshold that determines how many keys must sign an update to enable contract updatability.

note

Currently, only single-key authorities with a threshold of 1 are supported. Multi-key threshold authorities are a planned feature.

This mechanism lets you decentralize update authority to a group requiring joint approval, or grant control to a single owner.

warning

While Midnight does not require you to nominate a CMA for your deployed contract, we strongly advise DApp authors to understand the trade-offs before making this decision.

Why should you care?

Even if you are familiar with updatability in other blockchain ecosystems, Midnight has an important difference that might affect what you choose for your DApp. Most blockchains guarantee that deployed contracts run indefinitely as deployed, reducing the need for updatability.

Midnight differs because contracts are in part zero-knowledge proofs. Breaking updates to the proof system – including security updates – may require contracts to update to the new proof system. This means the system might disable old contracts after upgrades.

This is especially true before mainnet launch. During this period, there is no support for older proof system versions. There will be a support policy at or before mainnet launch.

With appropriate notice, support will be removed for old contract deployments. Updatable contracts can migrate to new versions, but non-upgradable contracts cannot. For the complete version overview, refer to the release compatibility matrix.

danger

Non-upgradable contracts should provide a way for users to withdraw their funds before support for old proof system versions is removed. Check the compatibility matrix for current version support. Upgradable contracts should commit to upgrade timelines or provide a path to withdraw funds if the contract is not upgraded.

note

Currently, Midnight's APIs support only single-key authorities with a threshold of 1. Multi-key and arbitrary party configurations are planned for a future release.

Capabilities of a maintenance authority

A Contract Maintenance Authority (CMA) performs various privileged actions to change a contract after deployment. These actions use a 'verifier key version', which combines the proving system version and the onchain runtime version. Contracts support multiple active verifier key versions simultaneously, with keys registered for each version. This enables transitions between versions and may provide long-term support for some verifier key versions in the future.

A CMA can perform the following privileged actions:

  • Change the CMA associated with this contract. The new CMA succeeds the current one, letting you relinquish control.
  • Remove a verifier key (of a specific version) from the contract. The contract rejects future transactions that attempt to use this operation with the removed verifier key version. The key with that version must exist before removal.
  • Add a new verifier key of a specific version. This adds new functionality to a contract or re-exports existing functionality with a new verifier key version. A key with that version must not already exist; if it does, remove it first.

The current verifier key version is v3. When the proof system or on-chain runtime upgrades to a new major version, a new verifier key version will be required — which is the primary reason CMA updatability exists.

info

Removing and re-adding a verifier key lets you change the implementation of a circuit, modifying its behavior. Be aware that this is a very powerful capability!

Maintenance authorities make changes by signing a sequence of these single updates into a combined maintenance update.

note

Currently, maintenance updates take effect immediately. Update delays (such as a minimum waiting period before changes take effect) are a planned feature for a future release.

Operate a maintenance authority

Operating a maintenance authority requires a DApp developer to:

  • Generate and store key pairs for the authority.
  • Modify deployment to add the authority.
  • Provide an interface for the authority to produce and sign updates.

You can specify the initial contract authority by providing a value for signingKey in the DeployContractOptions. Generate the initial signing key using sampleSigningKey. You can reuse the same CMA across multiple contracts by specifying the same signing key for different deployments.

warning

Store the signing key securely after deployment. If you lose the signing key, you permanently lose the ability to update the contract — there is no recovery mechanism. Do not hardcode signing keys in source code or commit them to version control.

You can update a deployed contract's circuits using the DeployedContract object's circuitMaintenanceTx property, which contains one CircuitMaintenanceTxInterface for each circuit defined on the contract. Use insertVerifierKey to add new verifier keys and removeVerifierKey to remove existing ones.

Similarly, you can update a deployed contract's maintenance authority using the DeployedContract's contractMaintenanceTx property.

Example

The following example demonstrates how to perform maintenance operations on a deployed contract. See the deploy guide for how to set up providers and compiledContract.

import { findDeployedContract } from '@midnight-ntwrk/midnight-js-contracts';

// providers = { publicDataProvider, proofProvider, zkConfigProvider,
// privateStateProvider, walletProvider, midnightProvider }

const foundContract = await findDeployedContract(providers, {
contractAddress,
compiledContract,
});

// Insert a new verifier key for the 'foo' circuit
await foundContract.circuitMaintenanceTx.foo.insertVerifierKey(newVerifierKey);

// Remove a verifier key for the 'foo' circuit
await foundContract.circuitMaintenanceTx.foo.removeVerifierKey();

// Replace the contract maintenance authority
await foundContract.contractMaintenanceTx.replaceAuthority(newSigningKey);
tip

You can also perform maintenance operations from the CLI using the maintainContract and maintainCircuit commands in @midnight-ntwrk/compact-js-command. These accept a --signing flag for the signing key, making them a simpler alternative to programmatic access.

Next steps

Now you understand how to update a deployed contract's maintenance authority. Check out the following resources to learn more about building DApps on the Midnight network: