v6.0.0
Overview
Migration difficulty: high, mostly because almost everything you pull from moved.
The v6 rollup is a fresh deployment starting from genesis. Run your v6 node with a new, empty data directory: no v5 chain state carries over.
Two things to settle before you start: every artifact location changed, and the
ACVM_* configuration variables were renamed with no fallback. A node doing real
proving fails to start on the old names; one that is not falls back to WASM
simulation and starts anyway, much slower, so a clean startup is not evidence that
your configuration migrated.
When to switch on Mainnet
The v6 rollup becomes canonical on Mainnet when governance executes the v6 upgrade proposal. The earliest execution time is Monday 26 October 2026, 08:00 UTC. Until then, v5 is the canonical rollup and your v5 node keeps doing the work.
You have two options.
Option 1 (recommended): stand up a v6 node in standby now. 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 still canonical they do not match, so the node enters standby mode: it serves
only a health endpoint (which reports healthy, so liveness probes pass), polls L1 once a
minute, and uses very few resources. Once the v6 rollup becomes canonical, the node
logs Compatible rollup found at <address>. Exiting standby mode. and starts normally,
with no action from you. You see this at startup:
Rollup at 0x... is incompatible: ... Entering standby mode. Will poll every 60s for a compatible rollup...
If the v6 node shares a host with the v5 node, give it its own data directory, 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 the v6 node fail at one of
those two moments.
Standby only works for a node that follows the canonical rollup, which is the default.
Do not pin ROLLUP_VERSION to the v6 rollup's version: the v6 rollup is not in the
registry until the proposal executes, so the node cannot look it up and fails to start.
Keep the v5 node running until the v6 node has left standby and is attesting.
Option 2: upgrade at execution time. Stop your v5 node and start the v6 node on Monday 26 October 2026 at 08:00 UTC, or as soon after as the proposal executes. This works, but your sequencer does nothing until the v6 node has started and synced, and you have to be there at the time.
v5 nodes delete other rollups' signing records from a shared PostgreSQL HA signing database when they start. If a v5 replica restarts after the v6 replica has started signing, the v6 replica loses its double-signing protection. Give the v6 replicas their own database, or do not restart v5 replicas after the switch to v6. See Signing history and rollup upgrades.
New repository, image and package locations
Everything moved. Old locations keep what was already published, so existing v5 setups keep working, but nothing new lands there.
| v5 and earlier | v6 | |
|---|---|---|
| Source repository | AztecProtocol/aztec-packages | aztec-labs-eng/aztec-node |
| Docker images | aztecprotocol/aztec | azteclabs/aztec |
| Prover agent image | aztecprotocol/aztec-prover-agent | azteclabs/aztec-prover-agent |
| npm (client packages) | @aztec/* | @aztec-labs/* |
| npm (foundation packages) | @aztec/bb.js, @aztec/noir-* | @aztec-foundation/* |
| Aztec.nr | in the monorepo | aztec-labs-eng/aztec-nr |
Update your image references first. A compose file or Helm values still pointing at
aztecprotocol/aztec will pull a v5 image and fail against a v6 network.
- image: aztecprotocol/aztec:5.2.0
+ image: azteclabs/aztec:6.0.0
The @aztec npm scope keeps the packages published for earlier versions, so an existing
project pinned to a v5 version continues to resolve. The packages now depend on upstream
viem instead of the @aztec/viem fork.
Behaviour changes
World-state history retention uses one policy
--world-state-history-retention <policy> ($WS_HISTORY_RETENTION)
Replace WS_NUM_HISTORIC_CHECKPOINTS=N or WS_NUM_HISTORIC_BLOCKS=N with WS_HISTORY_RETENTION=rolling:N.
Replace values below 1 with WS_HISTORY_RETENTION=archive. The former --world-state-checkpoint-history flag is removed.
rolling:Nretains the latest N finalized checkpoints and all newer state. The default isrolling:64.pinned:Nretains checkpoint N and every later checkpoint permanently, including every block of the pinned checkpoint.archiveretains all history from genesis and disables history pruning.
Rolling counts and pinned checkpoint numbers must be positive integers. Increasing a rolling window accumulates history
as the chain advances. Pinned and archive modes reject databases missing required history, even with SYNC_MODE=force-snapshot.
Use a fresh world-state database to rebuild missing history. Fresh databases try compatible snapshots before replaying from
genesis; pinned mode only accepts snapshots in the pinned checkpoint or earlier, and archive mode requires full history.
ACVM_* configuration renamed to NOIR_EXECUTE_*
Protocol circuits are now executed with noir's noir-execute rather than the acvm
binary, and the configuration naming the executor follows the tool. What you point it at
is unchanged.
| Old | New |
|---|---|
ACVM_BINARY_PATH | NOIR_EXECUTE_BINARY_PATH |
ACVM_WORKING_DIRECTORY | NOIR_EXECUTE_WORKING_DIRECTORY |
--sequencer.acvmBinaryPath | --sequencer.noirExecuteBinaryPath |
--sequencer.acvmWorkingDirectory | --sequencer.noirExecuteWorkingDirectory |
--proverNode.acvmBinaryPath | --proverNode.noirExecuteBinaryPath |
--proverNode.acvmWorkingDirectory | --proverNode.noirExecuteWorkingDirectory |
- 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
There is no fallback to the old names. A prover agent exits with Requested real proving but no path to bb or noir-execute binaries provided; a prover node or sequencer
configured for real proofs throws from BBNativeRollupProver.new when it tries to stat
an undefined path. Only a node running without real proofs survives, by falling back to
WASM simulation, which is much slower, so a node that appears to start may still be
badly degraded.
If you run the release image it sets the new variables itself, and its default working
directory moves from /usr/src/acvm to /usr/src/noir-execute. Check any values you
override.
A trace-capable L1 endpoint is required by default
ETHEREUM_ALLOW_NO_DEBUG_HOSTS now defaults to false.
| Flag | Environment Variable | Previous | New |
|---|---|---|---|
--archiver.ethereumAllowNoDebugHosts | ETHEREUM_ALLOW_NO_DEBUG_HOSTS | true | false |
At startup the node checks that the endpoint it traces with (ETHEREUM_DEBUG_HOSTS, or
ETHEREUM_HOSTS when that is unset) serves debug_traceTransaction or
trace_transaction. It used to log a warning and start when neither worked. It now
refuses to start, with an error naming ETHEREUM_ALLOW_NO_DEBUG_HOSTS.
A checkpoint published through a non-standard contract, rather than by a direct call to the rollup, cannot be read from the transaction calldata alone: the node needs a trace to recover it. A node without one starts normally and then stops syncing at the first such checkpoint, until it is pointed at a trace-capable endpoint and restarted. Failing at startup surfaces the problem before the node is relied on.
Migration: point ETHEREUM_DEBUG_HOSTS at an endpoint that serves trace methods
(see L1 RPC requirements). If you
accept the risk of stalling, set ETHEREUM_ALLOW_NO_DEBUG_HOSTS=true to keep the old
behaviour.
Attester-initiated sequencer exits
A position can now be exited by its attester, not only by its withdrawer. Exits can also be batched: each attester signs an exit authorization, and one relayer submits them all in a single transaction. This is what makes it practical to exit tens or hundreds of positions, for example as a staking provider.
The stake still goes to the position's withdrawer, never to the attester. An attester-initiated exit starts the exit delay; the withdrawer then names the recipient, and anyone can finalize once the delay has passed. Attester-initiated exits are rate-limited to about 5% of the sequencer set per rolling window, only work on the canonical rollup, and so on Mainnet only after the v6 upgrade executes.
See Exiting a sequencer for the full procedure, the limits, and troubleshooting. In short:
# Each attester signs an authorization, 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
# Simulate, then submit with 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
aztec initiate-withdraw-by-attester exits a single position in a transaction sent from
the attester key itself.
Three functions are live on the rollup:
| Function | What it does |
|---|---|
initiateWithdrawByAttester(address) | Exit one position. Caller must be the attester. |
initiateWithdrawByAttesterBatch(...) | Relay many attester-signed exits. Reverts if the rate limit cannot fit the whole batch. |
initiateWithdrawByAttesterBatchUpToLimit(...) | Relay many attester-signed exits, processing only as many from the start of the list as the rate limit allows and leaving the rest for later. |
Both batch functions still revert the whole transaction if any entry is invalid: an
expired deadline, a bad signature, an attester that is already exiting or has no stake.
Run --dry-run before submitting. Pass --up-to-limit to the batch command to use the
UpToLimit function.
Calling the contract directly
If you cannot use the CLI, call the rollup with cast. Exit a single position, signed
and submitted by the attester:
cast send $ROLLUP "initiateWithdrawByAttester(address)" $ATTESTER \
--private-key $ATTESTER_KEY --rpc-url $L1_RPC
Batching needs an EIP-712 signature per attester. The domain is
{ name: "Aztec Rollup", version: "1", chainId: <L1 chain id>, verifyingContract: <rollup> }
and the type is AttesterExit(address attester,uint256 deadline). Sign one per position:
cast wallet sign --private-key $ATTESTER_KEY --data '{
"domain":{"name":"Aztec Rollup","version":"1","chainId":'$L1_CHAIN_ID',"verifyingContract":"'$ROLLUP'"},
"types":{"AttesterExit":[{"name":"attester","type":"address"},{"name":"deadline","type":"uint256"}]},
"primaryType":"AttesterExit",
"message":{"attester":"'$ATTESTER'","deadline":"'$DEADLINE'"}
}'
Then relay them. Each entry is (attester, deadline, (v, r, s)), and the relayer pays
the gas, so the submitting key need not be an attester:
cast send $ROLLUP \
"initiateWithdrawByAttesterBatchUpToLimit((address,uint256,(uint8,bytes32,bytes32))[])" \
"[($ATTESTER_0,$DEADLINE,($V0,$R0,$S0)),($ATTESTER_1,$DEADLINE,($V1,$R1,$S1))]" \
--private-key $RELAYER_KEY --rpc-url $L1_RPC
deadline is a unix timestamp and must be in the future. Each attester may appear only
once per batch.
Withdrawer-initiated exits are unchanged.
remove-l1-validator and sequencers remove require --recipient
aztec remove-l1-validator and aztec sequencers remove now require --recipient, the address that receives the
withdrawn stake. Previously both always named the attester's own address as the recipient, sending the stake to the hot attester key
(for delegated stake, a key the provider holds), and a recipient cannot be changed once set.
Migration: add --recipient [RECIPIENT_ADDRESS] to any script that calls remove-l1-validator or sequencers remove.
Without it both commands fail before sending anything. The same command, sent from the withdrawer key, names the
recipient after an attester-initiated exit.
Provers can skip full-epoch proving
A new prover node setting stops the node from proving complete epochs on its own:
--proverNode.proverNodeDisableFullEpochProving ($PROVER_NODE_DISABLE_FULL_EPOCH_PROVING)
The default is false, so nothing changes unless you set it. With it set, the prover node
logs Full epoch proving disabled at startup and only proves the partial epochs
requested through its startProof admin method. Use it to run a prover that serves paid
partial-epoch proofs (for example, for early withdrawals) without competing for full
epoch proofs.
Change the log level without a restart
The node admin config has a new logLevel key. Set it with aztecAdmin_setConfig, using
the same format as LOG_LEVEL, and read it back with aztecAdmin_getConfig:
curl -X POST http://localhost:8880 \
-H 'Content-Type: application/json' \
-H 'x-api-key: [ADMIN_API_KEY]' \
-d '{"jsonrpc":"2.0","method":"aztecAdmin_setConfig","params":[{"logLevel":"debug;trace:sequencer,p2p"}],"id":1}'
The change applies to the node process immediately, including loggers created later. It
does not reach processes the node spawns, and a restart reverts to LOG_LEVEL.
Publishers must afford the L1 transaction before work starts
Nodes now check that a publisher holds enough ETH for its L1 transaction before doing the work behind it. The amount checked is a worst case: the transaction's gas limit times the max fee per gas, plus blob fees, at current L1 fees. At a 1 gwei base fee a proposal needs a few thousandths of an ETH.
- Sequencers: if no publisher for the proposer can afford a checkpoint proposal,
the node skips the slot before building or gossiping anything. It logs an error with
each publisher's balance and the required amount, and records the
insufficient_publisher_balancereason onaztec.sequencer.checkpoint.precheck_failed_count. Governance and slashing votes are still attempted. If a publisher can afford the proposal but not the votes bundled with it, the votes are dropped and the proposal is sent alone. - Provers: a prover node still proves an epoch while no publisher can afford the
proof submission, but holds the finished proof back instead of sending it. It
retries every 12 seconds and submits as soon as a publisher is funded, until the
proof submission window closes.
aztec.prover_node.proof_submission_unaffordable_countcounts the held back proofs. Nothing changes when proof publishing is disabled. - Selection: a publisher with a recently mined transaction is no longer ranked below an idle one with less ETH, so a dust-funded idle publisher can no longer win every proposal. A publisher whose transaction was rejected for insufficient funds is skipped until its balance increases, or for at most five minutes.
Publisher balances are checked every minute
Sequencers and prover nodes now read every publisher's balance once a minute, whether
or not the publisher has sent anything, and price a reference transaction at current
L1 fees: the first checkpoint proposal of an epoch for a sequencer, an epoch proof
submission for a prover. At startup the node logs a Publisher balances line with
every publisher's balance, at error level if none can afford the reference
transaction. While that lasts, it logs No publisher can afford a proposal (or
an epoch proof) at most every 10 minutes, naming the publisher to fund and how
much ETH it is missing. The skipped proposal and held back proof errors name them too.
A warning is logged when a publisher's balance falls below a multiple of the cost of the reference transaction:
--sequencer.publisherLowBalanceWarningMultiplier <value> ($PUBLISHER_LOW_BALANCE_WARNING_MULTIPLIER)
--proverNode.publisherLowBalanceWarningMultiplier <value> ($PUBLISHER_LOW_BALANCE_WARNING_MULTIPLIER)
The default is 4. If you use automatic top-ups,
set PUBLISHER_FUNDING_THRESHOLD above the warning level; the node warns if it is not.
Top-ups are now checked every minute instead of every 2 minutes.
Metric changes (Prometheus names):
aztec_l1_publisher_balance_ethis now recorded every minute for every publisher, instead of only after a transaction is sent. Alerts on it now fire for a publisher that has never sent, or stopped sending because it cannot afford to. It gains anaztec_l1_tx_scopelabel (sequencerorprover).- New
aztec_l1_publisher_sends_affordable: how many reference transactions each publisher's balance covers at current fees. Alert when it drops below 1. - New
aztec_l1_publisher_required_balance_eth: the cost of one reference transaction at current fees. - New
aztec_l1_publisher_funder_balance_eth: the balance of the funding account used for automatic top-ups. aztec_l1_balance_ethis deprecated and will be removed in a later release. Useaztec_l1_publisher_balance_ethinstead.aztec_l1_gas_price_weiandaztec_l1_blob_base_fee_weiare now exported. They were defined before but never reached the exporter.
See Metrics reference for example alert rules.
New node RPC methods
Two additions to the JSON-RPC surface. Both are additive; nothing was removed.
| Method | What it is for |
|---|---|
aztec_getTxEffectMembershipWitness | Membership proof for a transaction's effects. |
aztec_getValidatorStatsBatch | Validator statistics for several attesters in one call. |
Both currently render under "Other methods" in the node API reference because the generator has no grouping for them yet.
Upgrade checklist
- Point your image references at
azteclabs/aztecandazteclabs/aztec-prover-agent. - Rename
ACVM_*toNOIR_EXECUTE_*in your environment, compose files or Helm values, before starting a v6 node. - Confirm any overridden working directory matches the new default if you rely on the release image.
- Give the v6 node a new, empty data directory. The v6 rollup starts from genesis.
- Fund your sequencer and prover publishers. A node whose publishers cannot afford the
L1 transaction skips the proposal or holds back the proof submission. Alert on
aztec_l1_publisher_sends_affordable, and move any alert or dashboard onaztec_l1_balance_ethtoaztec_l1_publisher_balance_eth. - Check that
ETHEREUM_DEBUG_HOSTS(orETHEREUM_HOSTS, if you leave it unset) servesdebug_traceTransactionortrace_transaction. A v6 node refuses to start without one unless you setETHEREUM_ALLOW_NO_DEBUG_HOSTS=true. - On Mainnet, start the v6 node before the upgrade executes and let it wait in
standby, leaving
ROLLUP_VERSIONunset. Keep the v5 node running until the v6 node has left standby and is attesting. - If you run HA signing on a shared PostgreSQL database, give the v6 replicas their own database or do not restart v5 replicas after the switch to v6.
Full release notes
For the developer-facing changes in this release (the npm scope moves in detail, the aztec-nr repository move, Aztec.js artifact and return-type changes, and the removed CLI commands), see the migration notes.