Skip to content

v6.0.0

Latest

Choose a tag to compare

@aminsammara aminsammara released this 22 Oct 11:28
· 34 commits to main since this release
d2e67c1
   v5   L1 ▕░░░░░░░░░░░░░░░░░░░░░░░░░░░░░▏ L2    24–108s
   v6   L1 ▕████████▏ L2                          12–30s

                   A Z T E C  ·  6 · 0 · 0

Date: 2026-10-22 · Tag: v6.0.0 · Baseline: v5.2.0 · Major release

Install: aztec-up install 6.0.0 · Docker: azteclabs/aztec:6.0.0 (note the new Docker Hub organization)

Summary

v6 is the new Aztec rollup deployment proposed in AZUP-3. It is a major protocol upgrade, and upgrading to v6.0.0 is required for everyone. The new rollup becomes canonical on Mainnet no earlier than Monday 26 October 2026, 08:00 UTC, and Testnet upgrades at the same time.

Node operators: two breaking changes. A trace-capable L1 endpoint is now required by default, and the Docker image moved to the azteclabs Docker Hub organization. See Breaking changes for node operators.

Almost everything you pull from has moved: the Docker image is now published under azteclabs (azteclabs/aztec), the npm packages are now under @aztec-labs and @aztec-foundation, and Aztec.nr is now published from aztec-labs-eng/aztec-nr.

Breaking changes for node operators

  • A trace-capable L1 endpoint is required by default (#511). ETHEREUM_ALLOW_NO_DEBUG_HOSTS now defaults to false: the node refuses to start unless ETHEREUM_DEBUG_HOSTS (or ETHEREUM_HOSTS) serves debug_traceTransaction or trace_transaction. Without traces, a node silently stops syncing at the first checkpoint published through a non-standard contract. Set the flag to true to accept that risk.

  • The Docker image moved to the azteclabs Docker Hub organization: azteclabs/aztec (and azteclabs/aztec-prover-agent). The image name is unchanged, but aztecprotocol/aztec has no v6 releases; a compose file still pointing at it pulls v5.

    - image: aztecprotocol/aztec:5.2.0
    + image: azteclabs/aztec:6.0.0

When to switch on Mainnet

Option 1 (recommended): standby. Start a v6 node next to your v5 node any time before the execution date. At startup it compares the canonical rollup's genesis archive root, VK tree root and protocol contracts hash with its own. While v5 is canonical they differ, so the node enters standby: it serves only a health endpoint (which reports healthy), checks L1 once a minute, and uses very few resources. When the v6 rollup becomes canonical it logs Compatible rollup found and starts normally, with nothing for you to do.

  • Run it on a separate host, or give it its own container name, AZTEC_PORT and P2P_PORT. Standby binds the HTTP port as soon as it starts, and the node binds the P2P port when it leaves standby, so reusing the v5 values makes it fail.
  • Use a new, empty data directory.
  • Leave ROLLUP_VERSION unset so the node follows the canonical rollup. Pinning it to the v6 rollup's version makes the node fail at startup, because that version is not in the registry until the proposal executes.
  • Keep your v5 node running until the v6 node has left standby and is attesting.

Option 2: upgrade at execution time. Stop the v5 node and start v6 on Monday 26 October 2026 at 08:00 UTC, or as soon after as the proposal executes. Your sequencer is idle until the v6 node has started and synced. Slashing is disabled for the first 8,400 slots (about 7 days) after the v6 rollup becomes canonical, so the slots you miss while starting up cost you rewards but do not get you slashed.

High-availability signing on a shared PostgreSQL database: v5 nodes delete other rollups' signing records when they start (#352 fixes this in v6 only). Give your v6 replicas their own database, or do not restart v5 replicas after the switch, so the v6 replicas keep their double-signing protection.

Full operator migration guide: v6.0.0 operator changelog.

Breaking changes

Everything below applies to every project moving from v5.2.0.

Where things live

  • [Docker] The image moved to the azteclabs Docker Hub organization: azteclabs/aztec (and azteclabs/aztec-prover-agent). aztecprotocol/aztec has no v6 releases; a compose file still pointing at it pulls v5.

    - image: aztecprotocol/aztec:5.2.0
    + image: azteclabs/aztec:6.0.0
  • [npm] Packages moved to @aztec-labs (#93), and the foundation packages (bb.js, the noir-* packages, l1-artifacts, and others) to @aztec-foundation (#113). Subpaths are unchanged beyond the scope. The @aztec scope keeps everything already published, so v5 projects keep installing.

    -import { Contract } from '@aztec/aztec.js';
    +import { Contract } from '@aztec-labs/aztec.js';
  • [npm] The packages depend on upstream viem, not the @aztec/viem fork (#304). If you aliased viem to the fork, depend on upstream viem at the version @aztec-labs/aztec.js uses.

  • [Aztec.nr] Aztec.nr is published from aztec-labs-eng/aztec-nr. AztecProtocol/aztec-nr has no v6 tags, so bumping only tag fails with Remote branch v6.x.x not found. Update git as well (#135):

    -aztec = { git = "https://github.com/AztecProtocol/aztec-nr", tag = "v5.2.0", directory = "aztec" }
    +aztec = { git = "https://github.com/aztec-labs-eng/aztec-nr", tag = "v6.0.0", directory = "aztec" }
  • [Aztec.nr] The ECDSA note and the protocol contract interfaces ship with aztec-nr (#404). Depend on them from aztec-labs-eng/aztec-nr at the same tag as aztec. Pulling them from the old repositories brings in a second copy of aztec and fails with No matching impl found.

Protocol: every address changes, every contract recompiles

  • The contract address domain separator is bumped to V3, so every contract address, account addresses included, differs from v5 for the same class, salt, initialization and keys. This is deliberate: an address can never be live on two rollups at once. Anything that hard-codes an address must be updated. Protocol contracts keep their magic addresses (1, 2, ...).
  • Block headers commit to a per-block tx effects tree (#123). A block header alone now proves a transaction's inclusion and exact effects with a short membership proof. Every transaction hash, verification key, contract artifact and canonical address changes with it.
  • The protocol nullifier is derived from the tx request's salt alone (#310). Two transactions with the same origin and salt (a fee bump or a cancellation) are mutually exclusive: at most one is mined. tx_request_salt in the private context becomes protocol_nullifier. Wallets must draw a fresh salt for every transaction. Contracts need only a recompile.
  • The standard contracts are at new addresses. MultiCallEntrypoint, HandshakeRegistry, AuthRegistry and PublicChecks are all re-pinned. Handshakes made with the v5 registry must be re-established.
  • The PXE oracle interface is now version 33. Contracts must be recompiled against Aztec.nr v6.0.0 to run against a v6 PXE.

Aztec.nr

  • Fact collections are scoped by FactScope instead of an AztecAddress (#426). FactScope::account(address) is the old behaviour; the new FactScope::public() is shared by all accounts.

    - record_retractable_fact(contract_address, recipient, type_id, collection_id, fact_type_id, payload, origin_block);
    + record_retractable_fact(contract_address, FactScope::account(recipient), type_id, collection_id, fact_type_id, payload, origin_block);
  • OriginBlock is replaced by aztec::oracle::block_reference::BlockReference, with the same fields (#157).

  • Nullifier existence checks are batched: get_nullifier_statuses checks any number of nullifiers in one oracle call and reports each one's inclusion block. check_nullifier_exists still works (#157).

  • Writer::advance_offset is removed. Serialize the skipped fields instead (#387).

  • DelayedPublicMutable rejects delays below one hour, at compile time for the initial delay and at runtime in schedule_delay_change (#99).

  • Nine DOM_SEP__* constants left the protocol constants module. DOM_SEP__PARTIAL_NOTE_COMMITMENT and DOM_SEP__NOTE_COMPLETION_LOG_TAG move to aztec::note::partial_note; the other seven are now internal. Custom account entrypoints should call compute_tx_nullifier instead of hashing DOM_SEP__TX_NULLIFIER themselves (AztecProtocol/aztec-packages#25014).

Aztec.js

  • Protocol contract wrappers moved to @aztec-labs/aztec.js/protocol and out of @aztec-labs/noir-contracts.js. They are bound to their canonical address, so they attach with withWallet(wallet). at(wallet) still works but is deprecated (AztecProtocol/aztec-packages#24998).

    - import { FeeJuiceContract } from '@aztec/noir-contracts.js/FeeJuice';
    + import { FeeJuiceContract } from '@aztec-labs/aztec.js/protocol';
    - const feeJuice = FeeJuiceContract.at(ProtocolContractAddress.FeeJuice, wallet);
    + const feeJuice = FeeJuiceContract.withWallet(wallet);
  • A function's return type is a single returnType, not a returnTypes list. decodeFromAbi takes one type; use decodeEachFromAbi for lists (AztecProtocol/aztec-packages#25066).

  • Artifacts keep the names of #[abi(tag)] globals, readable with getGlobalsByTag. Artifacts compiled before this are rejected and must be recompiled (AztecProtocol/aztec-packages#25184).

  • GasPrice is renamed FeesPerGas in @aztec-labs/ethereum/l1-tx-utils, with matching method and field renames (getGasPrice() → getFeesPerGas()) (AztecProtocol/aztec-packages#25152).

Node API

  • getBlockHashMembershipWitness requires a reference block the node has. v5 accepted a block number one past the tip; v6 does not. To prove against a specific archive root, including a block's own post-block archive, use the new getBlockHashMembershipWitnessAtArchive({ archive }, blockHash) (#334).

CLI

  • Removed aztec bridge-erc20. Use L1ToL2TokenPortalManager from @aztec-labs/aztec.js/ethereum. Fee juice bridging with aztec-wallet bridge-fee-juice is unchanged (#52).
  • Removed get-canonical-sponsored-fpc-address. aztec-wallet now aliases it as contracts:SponsoredFPC (#49).
  • Removed inspect-contract, compute-selector, generate-secret-and-hash, parse-parameter-struct and example-contracts. Their aztec.js equivalents are listed in the migration notes (#36).

Node operators

  • ACVM_* is renamed NOIR_EXECUTE_*, with no fallback (#116). A prover agent exits with Requested real proving but no path to bb or noir-execute binaries provided; a node not doing real proofs starts anyway but falls back to much slower WASM simulation.

    - ACVM_BINARY_PATH=/usr/src/labs-aztec-toolchain/bin/noir-execute
    - ACVM_WORKING_DIRECTORY=/usr/src/acvm
    + NOIR_EXECUTE_BINARY_PATH=/usr/src/labs-aztec-toolchain/bin/noir-execute
    + NOIR_EXECUTE_WORKING_DIRECTORY=/usr/src/noir-execute

    The same rename applies to the --sequencer.* and --proverNode.* flags. The release image sets the new variables itself.

For node operators

Attester-initiated sequencer exits (#215)

A position can now be exited by its attester, not only its withdrawer, and exits can be batched: each attester signs an authorization offline, and one relayer submits them all in one transaction. This is built for staking providers, who hold the attester keys for many delegations but not the withdrawer keys.

# 1. Each attester signs an exit authorization (offline), appended to one file
aztec sign-attester-exit --private-key $ATTESTER_KEY --attester $ATTESTER \
    --rollup $ROLLUP --l1-chain-id $L1_CHAIN_ID --deadline $DEADLINE \
    --output exits.json --append

# 2. Simulate, then submit from any funded key
aztec initiate-withdraw-by-attester-batch --dry-run --authorizations exits.json \
    --rollup $ROLLUP --l1-chain-id $L1_CHAIN_ID --l1-rpc-urls $L1_RPC
aztec initiate-withdraw-by-attester-batch --authorizations exits.json \
    --rollup $ROLLUP --l1-chain-id $L1_CHAIN_ID --l1-rpc-urls $L1_RPC \
    --private-key $RELAYER_KEY

# 3. The withdrawer names the recipient (does not restart the delay)
aztec remove-l1-validator --validator $ATTESTER --recipient $RECIPIENT \
    --rollup $ROLLUP --l1-rpc-urls $L1_RPC --l1-chain-id $L1_CHAIN_ID \
    --private-key $WITHDRAWER_KEY

# 4. After the delay, anyone finalizes
cast send $ROLLUP "finalizeWithdraw(address)" $ATTESTER --private-key $ANY_KEY --rpc-url $L1_RPC

What to know:

  • The stake always goes to the withdrawer's chosen recipient, never to the attester. If you are a provider exiting delegated positions, your delegators must do step 3.
  • Timing. On Mainnet the stake is claimable about 9.6 days after the exit starts: the rollup's 4-day exit delay and the 9.6-day governance withdrawal delay both have to pass.
  • Rate limit. At most floor((N - 1) / 20) attester-initiated exits (about 5% of the set) per rolling 9.6-day window, never taking the set below the 48-seat committee. Withdrawer exits are not limited. Check the current state with getAttesterExitLimitState().
  • Batches. By default a batch is all or nothing against the rate limit; --up-to-limit processes as many as fit and leaves the rest for later. Either way, one invalid entry (expired deadline, bad signature, already exiting) reverts the whole transaction, so always --dry-run first.
  • Only on the canonical rollup. On Mainnet, attester exits work on v6 once the upgrade executes, not on v5. Until then, pass the v6 rollup to sign-attester-exit with --rollup explicitly.
  • aztec initiate-withdraw-by-attester exits one position in a transaction sent from the attester key.
  • aztec remove-l1-validator and aztec sequencers remove now require --recipient (#520). Both used to make the attester's own address the recipient, which sent the stake to the hot attester key (or, for delegated stake, to the provider) and could not be changed afterwards. remove-l1-validator --recipient, run by the withdrawer, is also how you name the recipient after an attester-initiated exit.

Full guide: Exiting a sequencer.

Publishers and L1

  • Nodes check that a publisher can afford its L1 transaction before doing the work (#443). A sequencer with no funded publisher skips the slot before building anything; a prover finishes the proof but holds it back, retrying every 12 seconds until a publisher is funded or the submission window closes. A dust-funded idle publisher can no longer win every proposal.
  • Publisher balances are checked every minute, for every publisher (#465, #466). The node logs which publisher to fund and how much ETH it is missing. New metrics aztec_l1_publisher_sends_affordable, aztec_l1_publisher_required_balance_eth and aztec_l1_publisher_funder_balance_eth; aztec_l1_publisher_balance_eth is now always recorded, and aztec_l1_balance_eth is deprecated. Alert on aztec_l1_publisher_sends_affordable < 1.
  • A clear error and metric when the L1 RPC cannot trace a propose transaction (#509).
  • Proof submissions that run out of gas are resent (#491), and very early epoch proofs are resubmitted correctly (#397).

BLS keys and staking

  • The upgrade raises the GSE's proof-of-possession gas cap from 250k to 300k. Since Osaka's modexp repricing, about 1 in 28,600 honestly generated BLS keys needed more than 250k gas to verify, and their deposits were refunded and dropped from the entry queue. At 300k that is about 1 in 2.5 million. The GSE is shared, so this also applies to v5 from the moment the upgrade executes.
  • aztec validator-keys and the staker output now check BLS keys against the live cap, so you find an expensive key before depositing it (#396, #507).

Provers

  • New: PROVER_NODE_DISABLE_FULL_EPOCH_PROVING (#436). When true, the prover node stops proving complete epochs on its own and proves only the partial epochs requested through its startProof admin method. Use it to serve paid partial-epoch proofs (for example, for early withdrawals) without competing for full epoch proofs. Default false.
  • Fault recovery. A dead batch verifier is rebuilt (#359, #354), prover agents report preemption (#475) and finish their proof on shutdown (#300), and per-block L1-to-L2 messages are capped when slicing checkpoints (#390).

Operations

  • Change the log level without a restart (#497). aztecAdmin_setConfig accepts a logLevel in the LOG_LEVEL format (e.g. "debug;trace:sequencer,p2p"), and aztecAdmin_getConfig reports it. A restart reverts to LOG_LEVEL.
  • The node exits when its world state database process dies, instead of running on without it, including on an idle node at genesis (#449, #460).
  • HA signing keeps each rollup's signing history across restarts of replicas serving other rollups, with a 24-hour default retention set by VALIDATOR_HA_OLD_DUTIES_MAX_AGE_H (#352). See the warning under When to switch on Mainnet.
  • New node RPC methods: aztec_getTxEffectMembershipWitness and aztec_getValidatorStatsBatch.

For wallet / PXE developers

  • Draw a fresh salt for every transaction. Transactions with the same origin and salt now share a protocol nullifier, so at most one is mined. This is what makes fee bumps and cancellations possible, and it means a reused salt silently drops a transaction (#310).
  • PXE databases re-initialize on first open (data schema bump), and the PXE requires contracts built against oracle interface version 33.
  • Tx inclusion proofs from a block header. TxEffect.computeTxEffectLeaf(), Body.computeTxEffectsTreeRoot() and the node's aztec_getTxEffectMembershipWitness prove that a transaction was included in a block with exactly a given set of effects (#123).
  • Browser-facing packages no longer import Node.js-specific modules (#444).

Security & correctness

Most of this is in how the node treats input from peers and from L1.

  • p2p: gossip messages with trailing bytes are rejected (#236); tx req/resp requests are de-duplicated, capped and bounded (#201, #202, #379); public calldata and contract class log validation are tighter (#510); a tx whose proof was evicted is dropped rather than served without it (#375); and peers are no longer penalized for conditions that are local to the receiver (#143, #235, #316, #477).
  • Archiver: checkpoints that repeat a tx hash are rejected (#338); a rolled-back checkpoint range re-syncs at the same L1 head (#381); a failed batch restores the L1 sync point (#336); and a checkpoint accepted earlier in the same batch is a valid parent (#503).
  • Slashing accuracy: checkpoint proposals with a forged lastArchiveRoot are slashable (#339); proposals rejected only because of a reorg during validation are not (#315); equivocation is slashed only when one key signed both checkpoints (#493); and a committee is served only once its seed is fixed on L1 (#500).

New in this release

  • Attester-initiated, batched sequencer exits. See For node operators.
  • Public fact collections. FactScope::public() lets any execution of a contract read and write a collection, whichever accounts are in scope (#426).
  • Deployment framework: universal deploys (#16) and deployment transactions paid through a payment method you supply (#455).
  • getBlockHashMembershipWitnessAtArchive proves block membership against any archive root the node knows (#334).

Protocol constants

New in v6. The Mainnet v6 rollup (0xE37A2663Cc9c119BA41572C40fAb0bbb23a5402f, rollup version 2070860440) was deployed with:

vk root               0x22fff5de6ce590153df4468f7f0b152188a803d91b3c9c648b91d93d5913f219
protocol contracts    0x0f54271c52865841a77aaa66036eed901aff22fdce9f08e123ec8b205c9854d7
genesis archive root  0x29eb2c527f8d45276430363214e6c8d709ef3f657a3670ebac3179373d41e5c4

A v6.0.0 node starts only when the canonical rollup carries exactly these values, which is what makes standby mode safe: it cannot attach to the wrong rollup. The new Testnet rollup uses the same circuits.

Reference