> For the complete documentation index, see [llms.txt](/llms.txt)

# 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:

```text
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.

High-availability setups sharing a signing database

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](/operate/operators/setup/high_availability_sequencers.md#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.

```diff
- 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

```bash
--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:N` retains the latest N finalized checkpoints and all newer state. The default is `rolling:64`.
* `pinned:N` retains checkpoint N and every later checkpoint permanently, including every block of the pinned checkpoint.
* `archive` retains 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` |

```diff
- 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](/operate/operators/concepts/l1-rpc.md#debug-traces)). 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](/operate/operators/sequencer-management/exiting-a-sequencer.md) for the full procedure, the limits, and troubleshooting. In short:

```bash
# 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 revert the whole transaction if any entry they process is invalid: an expired deadline, a bad signature, an attester that is already exiting or has no stake. `UpToLimit` does not check the entries it leaves for later. 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:

```bash
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:

```bash
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:

```bash
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:

```bash
--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`:

```bash
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_balance` reason on `aztec.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_count` counts 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:

```bash
--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](/operate/operators/solo-sequencer/fund-accounts.md#optional-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_eth` is 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 an `aztec_l1_tx_scope` label (`sequencer` or `prover`).
* 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_eth` is deprecated and will be removed in a later release. Use `aztec_l1_publisher_balance_eth` instead.
* `aztec_l1_gas_price_wei` and `aztec_l1_blob_base_fee_wei` are now exported. They were defined before but never reached the exporter.

See [Metrics reference](/operate/operators/monitoring/metrics-reference.md#l1-publisher-eth-balance) 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](/operate/operators/reference/node_api_reference.md) because the generator has no grouping for them yet.

## Upgrade checklist

1. Point your image references at `azteclabs/aztec` and `azteclabs/aztec-prover-agent`.
2. Rename `ACVM_*` to `NOIR_EXECUTE_*` in your environment, compose files or Helm values, **before** starting a v6 node.
3. Confirm any overridden working directory matches the new default if you rely on the release image.
4. Give the v6 node a new, empty data directory. The v6 rollup starts from genesis.
5. 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 on `aztec_l1_balance_eth` to `aztec_l1_publisher_balance_eth`.
6. Check that `ETHEREUM_DEBUG_HOSTS` (or `ETHEREUM_HOSTS`, if you leave it unset) serves `debug_traceTransaction` or `trace_transaction`. A v6 node refuses to start without one unless you set `ETHEREUM_ALLOW_NO_DEBUG_HOSTS=true`.
7. On Mainnet, start the v6 node before the upgrade executes and let it wait in [standby](#when-to-switch-on-mainnet), leaving `ROLLUP_VERSION` unset. Keep the v5 node running until the v6 node has left standby and is attesting.
8. 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](/developers/docs/resources/migration_notes.md).
