|
1 | 1 | --- |
2 | | -title: v4.0.0 (from v3.0.0) |
3 | | -description: TODO |
| 2 | +title: v4.x (Upgrade from Ignition) |
| 3 | +description: Breaking changes and migration guide for upgrading from Ignition (v2.x) to Alpha (v4.x). |
4 | 4 | --- |
5 | 5 |
|
6 | 6 | ## Overview |
7 | 7 |
|
8 | | -**Migration difficulty**: TODO |
| 8 | +**Migration difficulty**: High |
9 | 9 |
|
10 | 10 | ## Breaking changes |
11 | 11 |
|
12 | | -### StakingAssetHandler refactored to simple token faucet |
| 12 | +### Node.js upgraded to v24 |
13 | 13 |
|
14 | | -The `StakingAssetHandler` L1 contract has been significantly simplified. It no longer handles validator registration directly - instead it functions as a simple STK token faucet with ZKPassport sybil resistance. |
| 14 | +Node.js minimum version changed from v22 to v24.12.0. |
15 | 15 |
|
16 | | -**v3.0.0:** |
17 | | -```solidity |
18 | | -// Single call registered validator |
19 | | -stakingAssetHandler.addValidator(attester, merkleProof, zkPassportParams, publicKeyG1, publicKeyG2, signature); |
| 16 | +### Bot fee padding configuration renamed |
| 17 | + |
| 18 | +The bot configuration for fee padding has been renamed from "base fee" to "min fee". |
| 19 | + |
| 20 | +**v3.x:** |
| 21 | + |
| 22 | +```bash |
| 23 | +--bot.baseFeePadding <value> ($BOT_BASE_FEE_PADDING) |
| 24 | +``` |
| 25 | + |
| 26 | +**v4.0.0:** |
| 27 | + |
| 28 | +```bash |
| 29 | +--bot.minFeePadding <value> ($BOT_MIN_FEE_PADDING) |
| 30 | +``` |
| 31 | + |
| 32 | +**Migration**: Update your configuration to use the new flag name and environment variable. |
| 33 | + |
| 34 | +### L2Tips API restructured with checkpoint information |
| 35 | + |
| 36 | +The `getL2Tips()` RPC endpoint now returns a restructured response with additional checkpoint tracking. |
| 37 | + |
| 38 | +**v3.x response:** |
| 39 | + |
| 40 | +```json |
| 41 | +{ |
| 42 | + "latest": { "number": 100, "hash": "0x..." }, |
| 43 | + "proven": { "number": 98, "hash": "0x..." }, |
| 44 | + "finalized": { "number": 95, "hash": "0x..." } |
| 45 | +} |
| 46 | +``` |
| 47 | + |
| 48 | +**v4.0.0 response:** |
| 49 | + |
| 50 | +```json |
| 51 | +{ |
| 52 | + "proposed": { "number": 100, "hash": "0x..." }, |
| 53 | + "checkpointed": { |
| 54 | + "block": { "number": 99, "hash": "0x..." }, |
| 55 | + "checkpoint": { "number": 10, "hash": "0x..." } |
| 56 | + }, |
| 57 | + "proven": { |
| 58 | + "block": { "number": 98, "hash": "0x..." }, |
| 59 | + "checkpoint": { "number": 9, "hash": "0x..." } |
| 60 | + }, |
| 61 | + "finalized": { |
| 62 | + "block": { "number": 95, "hash": "0x..." }, |
| 63 | + "checkpoint": { "number": 8, "hash": "0x..." } |
| 64 | + } |
| 65 | +} |
| 66 | +``` |
| 67 | + |
| 68 | +**Migration**: |
| 69 | + |
| 70 | +- Replace `tips.latest` with `tips.proposed` |
| 71 | +- For `checkpointed`, `proven`, and `finalized` tips, access block info via `.block` (e.g., `tips.proven.block.number`) |
| 72 | + |
| 73 | +### Block gas limits reworked |
| 74 | + |
| 75 | +The byte-based block size limit has been removed and replaced with field-based blob limits and automatic gas budget computation from L1 rollup limits. |
| 76 | + |
| 77 | +**Removed:** |
| 78 | + |
| 79 | +```bash |
| 80 | +--maxBlockSizeInBytes <value> ($SEQ_MAX_BLOCK_SIZE_IN_BYTES) |
| 81 | +``` |
| 82 | + |
| 83 | +**Changed to optional (now auto-computed from L1 if not set):** |
| 84 | + |
| 85 | +```bash |
| 86 | +--maxL2BlockGas <value> ($SEQ_MAX_L2_BLOCK_GAS) |
| 87 | +--maxDABlockGas <value> ($SEQ_MAX_DA_BLOCK_GAS) |
20 | 88 | ``` |
21 | 89 |
|
| 90 | +**New (proposer):** |
| 91 | + |
| 92 | +```bash |
| 93 | +--perBlockAllocationMultiplier <value> ($SEQ_PER_BLOCK_ALLOCATION_MULTIPLIER) |
| 94 | +--maxTxsPerCheckpoint <value> ($SEQ_MAX_TX_PER_CHECKPOINT) |
| 95 | +``` |
| 96 | + |
| 97 | +**New (validator):** |
| 98 | + |
| 99 | +```bash |
| 100 | +--validateMaxL2BlockGas <value> ($VALIDATOR_MAX_L2_BLOCK_GAS) |
| 101 | +--validateMaxDABlockGas <value> ($VALIDATOR_MAX_DA_BLOCK_GAS) |
| 102 | +--validateMaxTxsPerBlock <value> ($VALIDATOR_MAX_TX_PER_BLOCK) |
| 103 | +--validateMaxTxsPerCheckpoint <value> ($VALIDATOR_MAX_TX_PER_CHECKPOINT) |
| 104 | +``` |
| 105 | + |
| 106 | +**Migration**: Remove `SEQ_MAX_BLOCK_SIZE_IN_BYTES` from your configuration. Per-block L2 and DA gas budgets are now derived automatically as `(checkpointLimit / maxBlocks) * multiplier`, where the multiplier defaults to 2. You can still override `SEQ_MAX_L2_BLOCK_GAS` and `SEQ_MAX_DA_BLOCK_GAS` explicitly, but they will be capped at the checkpoint-level limits. Validators can now set independent per-block and per-checkpoint limits via the `VALIDATOR_` env vars; when not set, only checkpoint-level protocol limits are enforced. |
| 107 | + |
| 108 | +### Setup phase allow list requires function selectors |
| 109 | + |
| 110 | +The transaction setup phase allow list now enforces function selectors, restricting which specific functions can run during setup on whitelisted contracts. Previously, any public function on a whitelisted contract or class was permitted. |
| 111 | + |
| 112 | +The semantics of the environment variable `TX_PUBLIC_SETUP_ALLOWLIST` have changed: |
| 113 | + |
| 114 | +**v3.x:** |
| 115 | + |
| 116 | +```bash |
| 117 | +--txPublicSetupAllowList <value> ($TX_PUBLIC_SETUP_ALLOWLIST) |
| 118 | +``` |
| 119 | + |
| 120 | +The variable fully **replaced** the hardcoded defaults. Format allowed entries without selectors: `I:address`, `C:classId`. |
| 121 | + |
22 | 122 | **v4.0.0:** |
23 | | -```solidity |
24 | | -// Step 1: Claim STK tokens from faucet |
25 | | -stakingAssetHandler.claim(zkPassportParams); |
26 | 123 |
|
27 | | -// Step 2: Approve rollup to spend tokens |
28 | | -stakingAsset.approve(rollupAddress, amount); |
| 124 | +```bash |
| 125 | +--txPublicSetupAllowListExtend <value> ($TX_PUBLIC_SETUP_ALLOWLIST) |
| 126 | +``` |
| 127 | + |
| 128 | +The variable now **extends** the hardcoded defaults (which are always present). Selectors are now mandatory. An optional flags segment can be appended for additional validation: |
| 129 | + |
| 130 | +``` |
| 131 | +I:address:selector[:flags] |
| 132 | +C:classId:selector[:flags] |
| 133 | +``` |
| 134 | + |
| 135 | +Where `flags` is a `+`-separated list of: |
| 136 | +- `os` — `onlySelf`: only allow calls where msg_sender == contract address |
| 137 | +- `rn` — `rejectNullMsgSender`: reject calls with a null msg_sender |
| 138 | +- `cl=N` — `calldataLength`: enforce exact calldata length of N fields |
| 139 | + |
| 140 | +Example: `C:0xabc:0x1234:os+cl=4` |
| 141 | + |
| 142 | +**Migration**: If you were using `TX_PUBLIC_SETUP_ALLOWLIST`, ensure all entries include function selectors. Note the variable now adds to defaults rather than replacing them. If you were not setting this variable, no action is needed — the hardcoded defaults now include the correct selectors automatically. |
| 143 | + |
| 144 | +### Token removed from default setup allowlist |
| 145 | + |
| 146 | +Token class-based entries (`_increase_public_balance` and `transfer_in_public`) have been removed from the default public setup allowlist. FPC-based fee payments using custom tokens no longer work out of the box. |
| 147 | + |
| 148 | +This change was made because Token class IDs change with aztec-nr releases, making the allowlist impossible to keep up to date with new library releases. In addition, `transfer_in_public` requires complex additional logic to be built into the node to prevent mass transaction invalidation attacks. **FPC-based fee payment with custom tokens won't work on mainnet alpha**. |
| 149 | + |
| 150 | +**Migration**: Node operators who need FPC support must manually add Token entries via `TX_PUBLIC_SETUP_ALLOWLIST`. Example: |
29 | 151 |
|
30 | | -// Step 3: Deposit into rollup (user chooses their own withdrawer) |
31 | | -rollup.deposit(attester, withdrawer, publicKeyG1, publicKeyG2, signature, moveWithLatestRollup); |
| 152 | +```bash |
| 153 | +TX_PUBLIC_SETUP_ALLOWLIST="C:<tokenClassId>:<increaseBalanceSelector>:os+cl=3,C:<tokenClassId>:<transferInPublicSelector>:cl=5" |
| 154 | +``` |
| 155 | + |
| 156 | +Replace `<tokenClassId>` with the deployed Token contract class ID and `<increaseBalanceSelector>`/`<transferInPublicSelector>` with the respective function selectors. Keep in mind that this will only work on local network setups, since even if you as an operator add these entries, other nodes will not have them and will not pick up these transactions. |
| 157 | + |
| 158 | +### Sequencer environment variable renames |
| 159 | + |
| 160 | +Several sequencer environment variables have been renamed: |
| 161 | + |
| 162 | +| Old variable | New variable | |
| 163 | +|---|---| |
| 164 | +| `SEQ_TX_POLLING_INTERVAL_MS` | `SEQ_POLLING_INTERVAL_MS` | |
| 165 | +| `SEQ_MAX_L1_TX_INCLUSION_TIME_INTO_SLOT` | `SEQ_L1_PUBLISHING_TIME_ALLOWANCE_IN_SLOT` | |
| 166 | +| `SEQ_MAX_TX_PER_BLOCK` | `SEQ_MAX_TX_PER_CHECKPOINT` | |
| 167 | +| `SEQ_MAX_BLOCK_SIZE_IN_BYTES` | Removed (see [Block gas limits reworked](#block-gas-limits-reworked)) | |
| 168 | + |
| 169 | +**Migration**: Search your configuration for the old variable names and replace them. The node will not recognize the old names. |
| 170 | + |
| 171 | +### Double signing slashing |
| 172 | + |
| 173 | +New slashable offenses have been introduced for duplicate proposals and duplicate attestations. Penalty amounts are currently set to 0, but the detection infrastructure is active. |
| 174 | + |
| 175 | +If you run redundant sequencer nodes, you **must** enable high-availability signing with PostgreSQL to prevent accidental double signing: |
| 176 | + |
| 177 | +```bash |
| 178 | +VALIDATOR_HA_SIGNING_ENABLED=true |
| 179 | +VALIDATOR_HA_DATABASE_URL=postgresql://<user>:<password>@<host>:<port>/<database> |
| 180 | +VALIDATOR_HA_NODE_ID=<unique-id-per-node> |
| 181 | +``` |
| 182 | + |
| 183 | +Run the database migration before starting your nodes: |
| 184 | + |
| 185 | +```bash |
| 186 | +aztec migrate-ha-db up --database-url <url> |
32 | 187 | ``` |
33 | 188 |
|
34 | | -**Removed functions:** |
35 | | -- `addValidator()` - replaced by `claim()` + direct rollup deposit |
36 | | -- `reenterExitedValidator()` |
37 | | -- `setValidatorsToFlush()`, `setMintInterval()`, `setDepositsPerMint()`, `setWithdrawer()` |
38 | | -- `setSkipMerkleCheck()`, `setDepositMerkleRoot()` |
| 189 | +**Migration**: If you run a single node, no action is required. If you run redundant nodes for high availability, configure HA signing immediately. See the [High Availability Sequencers](../../operators/setup/high-availability.md) guide for details. |
| 190 | + |
| 191 | +### Blob-only data publication |
| 192 | + |
| 193 | +Transaction data is now published entirely via EIP-4844 blobs. The calldata fallback has been removed. |
| 194 | + |
| 195 | +Your consensus client (e.g., Lighthouse, Prysm) must run as a **supernode** or **semi-supernode** to make blobs available for retrieval. Standard pruning configurations will not retain blobs long enough. |
39 | 196 |
|
40 | | -**New functions:** |
41 | | -- `claim(ProofVerificationParams)` - claim STK tokens with ZKPassport proof |
42 | | -- `setFaucetAmount(uint256)` - owner sets claim amount |
43 | | -- `resetNullifier(bytes32)` - owner can reset a nullifier |
| 197 | +You should also configure blob file stores for redundancy: |
44 | 198 |
|
45 | | -**CLI changes:** |
46 | 199 | ```bash |
47 | | -# v3.0.0 |
48 | | -aztec add-l1-validator --merkle-proof <proof> |
| 200 | +BLOB_FILE_STORE_URLS=<comma-separated-read-urls> |
| 201 | +BLOB_FILE_STORE_UPLOAD_URL=<upload-url> |
| 202 | +BLOB_ARCHIVE_API_URL=<archive-api-url> |
| 203 | +``` |
| 204 | + |
| 205 | +**Migration**: Ensure your consensus client is configured as a supernode. If you previously relied on calldata for data availability, switch to blob-based retrieval. See the [Blob Storage](../../operators/setup/blob_storage) guide for configuration details. |
| 206 | + |
| 207 | +### Withdrawal delay increase |
| 208 | + |
| 209 | +The governance execution delay has increased from 7 days to 30 days. This extends the time required for staker withdrawals from approximately 15 days to approximately 38 days. |
49 | 210 |
|
50 | | -# v4.0.0 |
51 | | -aztec add-l1-validator --withdrawer-address <address> |
| 211 | +**Migration**: No configuration changes needed. Be aware that withdrawal processing will take longer after the upgrade. |
| 212 | + |
| 213 | +### Prover architecture change |
| 214 | + |
| 215 | +The prover now runs as a node subsystem rather than a separate standalone process. Start it alongside your node using the `--prover-node` flag: |
| 216 | + |
| 217 | +```bash |
| 218 | +aztec start --node --prover-node |
52 | 219 | ``` |
53 | 220 |
|
54 | | -**Migration**: Users must now call `claim()` to get STK tokens, then deposit into the rollup themselves. The `--merkle-proof` CLI flag is removed; add `--withdrawer-address` instead. |
| 221 | +**Migration**: If you were running the prover as a separate process, update your deployment to run it as part of the node with `--prover-node`. |
55 | 222 |
|
56 | 223 | ## Removed features |
57 | 224 |
|
58 | 225 | ## New features |
59 | 226 |
|
60 | | -### P2P clock tolerance for slot validation |
| 227 | +### Initial ETH per fee asset configuration |
| 228 | + |
| 229 | +A new environment variable `AZTEC_INITIAL_ETH_PER_FEE_ASSET` has been added to configure the initial exchange rate between ETH and the fee asset (AZTEC) at contract deployment. This value uses 1e12 precision. |
| 230 | + |
| 231 | +**Default**: `10000000` (0.00001 ETH per AZTEC) |
| 232 | + |
| 233 | +**Configuration:** |
61 | 234 |
|
62 | | -Added a 500ms tolerance window for P2P messages from the previous slot, following Ethereum's `MAXIMUM_GOSSIP_CLOCK_DISPARITY` approach. This prevents peers from being penalized for valid messages that arrive slightly after the slot boundary due to network latency. |
| 235 | +```bash |
| 236 | +--initialEthPerFeeAsset <value> ($AZTEC_INITIAL_ETH_PER_FEE_ASSET) |
| 237 | +``` |
| 238 | + |
| 239 | +This replaces the previous hardcoded default and allows network operators to set the starting price point for the fee asset. |
| 240 | + |
| 241 | +### `reloadKeystore` admin RPC endpoint |
| 242 | + |
| 243 | +Node operators can now update validator attester keys, coinbase, and fee recipient without restarting the node by calling the new `reloadKeystore` admin RPC endpoint. |
| 244 | + |
| 245 | +What is updated on reload: |
| 246 | + |
| 247 | +- Validator attester keys (add, remove, or replace) |
| 248 | +- Coinbase and fee recipient per validator |
| 249 | +- Publisher-to-validator mapping |
| 250 | + |
| 251 | +What is NOT updated (requires restart): |
63 | 252 |
|
64 | | -The tolerance is hardcoded at 500ms (matching Ethereum's current value) and can be made configurable via environment variables in the future if needed. |
| 253 | +- L1 publisher signers |
| 254 | +- Prover keys |
| 255 | +- HA signer connections |
65 | 256 |
|
66 | | -**Impact**: Improved network stability with no action required from node operators. |
| 257 | +New validators must use a publisher key already initialized at startup. Reload is rejected with a clear error if validation fails. |
67 | 258 |
|
68 | | -### Transaction collection config renamed |
| 259 | +### Admin API key authentication |
69 | 260 |
|
70 | | -The environment variable for selecting the missing transactions collector implementation has been renamed: |
| 261 | +The admin JSON-RPC endpoint now supports auto-generated API key authentication. |
| 262 | + |
| 263 | +**Behavior:** |
| 264 | + |
| 265 | +- A cryptographically secure API key is auto-generated at first startup and displayed once via stdout |
| 266 | +- Only the SHA-256 hash is persisted to `<dataDirectory>/admin/api_key_hash` |
| 267 | +- The key is reused across restarts when `--data-directory` is set |
| 268 | +- Supports both `x-api-key` and `Authorization: Bearer <key>` headers |
| 269 | +- Health check endpoint (`GET /status`) is excluded from auth (for k8s probes) |
| 270 | + |
| 271 | +**Configuration:** |
71 | 272 |
|
72 | | -**v3.0.0:** |
73 | 273 | ```bash |
74 | | ---tx-collection-proposal-tx-collector-type <new|old> ($TX_COLLECTION_PROPOSAL_TX_COLLECTOR_TYPE) |
| 274 | +--admin-api-key-hash <hex> ($AZTEC_ADMIN_API_KEY_HASH) # Use a pre-generated SHA-256 key hash |
| 275 | +--disable-admin-api-key ($AZTEC_DISABLE_ADMIN_API_KEY) # Disable auth entirely |
| 276 | +--reset-admin-api-key ($AZTEC_RESET_ADMIN_API_KEY) # Force key regeneration |
75 | 277 | ``` |
76 | 278 |
|
77 | | -**v4.0.0:** |
| 279 | +**Helm charts**: Admin API key auth is disabled by default (`disableAdminApiKey: true`). Set to `false` in production values to enable. |
| 280 | + |
| 281 | +**Migration**: No action required — auth is opt-out. To enable, ensure `--disable-admin-api-key` is not set and note the key printed at startup. |
| 282 | + |
| 283 | +### Transaction pool error codes for RPC callers |
| 284 | + |
| 285 | +Transaction submission via RPC now returns structured rejection codes when a transaction is rejected by the mempool: |
| 286 | + |
| 287 | +- `LOW_PRIORITY_FEE` — tx priority fee is too low |
| 288 | +- `INSUFFICIENT_FEE_PAYER_BALANCE` — fee payer doesn't have enough balance |
| 289 | +- `NULLIFIER_CONFLICT` — conflicting nullifier already in pool |
| 290 | + |
| 291 | +**Impact**: Improved developer experience — callers can now programmatically handle specific rejection reasons. |
| 292 | + |
| 293 | +### RPC transaction replacement price bump |
| 294 | + |
| 295 | +Transactions submitted via RPC that clash on nullifiers with existing pool transactions must now pay at least X% more in priority fee to replace them. The same bump applies when the pool is full and the incoming tx needs to evict the lowest-priority tx. P2P gossip behavior is unchanged. |
| 296 | + |
| 297 | +**Configuration:** |
| 298 | + |
78 | 299 | ```bash |
79 | | ---tx-collection-missing-txs-collector-type <new|old> ($TX_COLLECTION_MISSING_TXS_COLLECTOR_TYPE) |
| 300 | +P2P_RPC_PRICE_BUMP_PERCENTAGE=10 # default: 10 (percent) |
80 | 301 | ``` |
81 | 302 |
|
82 | | -**Migration**: Update your configuration to use the new environment variable name. The default value (`new`) remains unchanged. |
| 303 | +Set to `0` to disable the percentage-based bump (still requires strictly higher fee). |
| 304 | + |
| 305 | +### Validator-specific block limits |
| 306 | + |
| 307 | +Validators can now enforce per-block and per-checkpoint limits independently from the sequencer (proposer) limits. This allows operators to accept proposals that exceed their own proposer settings, or to reject proposals that are too large even if the proposer's limits allow them. |
| 308 | + |
| 309 | +**Configuration:** |
| 310 | + |
| 311 | +```bash |
| 312 | +VALIDATOR_MAX_L2_BLOCK_GAS=<value> # Max L2 gas per block for validation |
| 313 | +VALIDATOR_MAX_DA_BLOCK_GAS=<value> # Max DA gas per block for validation |
| 314 | +VALIDATOR_MAX_TX_PER_BLOCK=<value> # Max txs per block for validation |
| 315 | +VALIDATOR_MAX_TX_PER_CHECKPOINT=<value> # Max txs per checkpoint for validation |
| 316 | +``` |
| 317 | + |
| 318 | +When not set, no per-block limit is enforced for that dimension — only checkpoint-level protocol limits apply. These do not fall back to the `SEQ_` values. |
| 319 | + |
| 320 | +### Setup allow list extendable via network config |
| 321 | + |
| 322 | +The setup phase allow list can now be extended via the network configuration JSON (`txPublicSetupAllowListExtend` field). This allows network operators to distribute additional allowed setup functions to all nodes without requiring code changes. The local environment variable takes precedence over the network-json value. |
83 | 323 |
|
84 | 324 | ## Changed defaults |
85 | 325 |
|
|
0 commit comments