Running a Sequencer
Overview
This guide covers sequencer lifecycle management on the Aztec network: keystore configuration, node setup, registration, ongoing operations, and eventual exit.
Sequencer nodes are critical infrastructure responsible for ordering transactions and producing blocks. They perform three key actions:
- Assemble unprocessed transactions and propose the next block
- Attest to correct execution of transactions in proposed blocks (when part of the sequencer committee)
- Submit successfully attested blocks to L1
Before publication, blocks must be validated by a committee of sequencer nodes who re-execute public transactions and verify private function proofs. Committee members attest to validity by signing the block header.
Once sufficient attestations are collected (two-thirds of the committee plus one), the block can be submitted to L1.
Minimum Hardware Requirements
- 2 core / 4 vCPU (released in 2015 or later)
- 16 GB RAM
- 1 TB NVMe SSD
- 25 Mbps network connection
These requirements are subject to change as the network throughput increases.
Before proceeding: Ensure you've reviewed and completed the prerequisites for the Docker Compose method. This guide uses Docker Compose, which is the recommended approach for sequencer nodes.
Keystore Explanation
Sequencers require private keys to identify themselves as valid proposers and attesters. These keys are configured through a keystore file.
Keystore Structure
The keystore file (keystore.json) uses the following structure:
{
"schemaVersion": 1,
"validators": [
{
"attester": {
"eth": "ETH_PRIVATE_KEY",
"bls": "BLS_PRIVATE_KEY"
},
"coinbase": "ETH_ADDRESS"
}
]
}
The attester field contains both Ethereum keys (for node operation) and BLS keys (for staking).
Field Descriptions
attester (required)
Your sequencer's identity. Contains both Ethereum and BLS keys:
- Format: Object with
ethandblsfields - eth: Ethereum private key used to sign block proposals and attestations - the derived address is your sequencer's unique identifier
- bls: BLS private key required for staking onchain (automatically generated)
- Purpose: Signs attestations and proposals (eth), participates in staking (bls)
publisher (optional)
Private key for sending block proposals to L1. This account needs ETH funding to pay for L1 gas.
- Format: Array of Ethereum private keys
- Default: Uses attester key if not specified Rule of thumb: Ensure every publisher account maintains at least 0.1 ETH per attester account it serves. This balance allows the selected publisher to successfully post transactions when chosen.
If you're using the same key for both attester and publisher, you can omit the publisher field entirely from your keystore, but you will still need to fund the attester account according to the rule of thumb above.
coinbase (optional)
Ethereum address that receives all L1 block rewards and tx fees.
- Format: Ethereum address
- Default: Uses attester address if not specified
Generating Keys
Use the Aztec CLI's keystore utility to generate keys:
aztec validator-keys new \
--fee-recipient [YOUR_AZTEC_FEE_RECIPIENT_ADDRESS]
This command:
- Automatically generates a mnemonic for key derivation (or provide your own with
--mnemonic) - Creates a keystore with Ethereum keys (for node operation) and BLS keys (for staking)
- Outputs your attester address and BLS public key
- Saves the keystore to
~/.aztec/keystore/key1.jsonby default
Save the following from the output:
- Attester address: Your sequencer's identity (needed for registration)
- BLS public key: Required for staking registration
For deterministic key generation or to recreate keys later, provide your own mnemonic:
aztec validator-keys new \
--fee-recipient [YOUR_AZTEC_FEE_RECIPIENT_ADDRESS] \
--mnemonic "your twelve word mnemonic phrase here"
For detailed instructions, advanced options, and complete examples, see the Creating Sequencer Keystores guide.
Setup with Docker Compose
Step 1: Set Up Directory Structure
Create the directory structure for sequencer data storage:
mkdir -p aztec-sequencer/keys aztec-sequencer/data
cd aztec-sequencer
touch .env
Step 2: Move Keystore to Docker Directory
If you haven't already generated your keystore with BLS keys, do so now (see Generating Keys above).
Move or generate your keystore directly in the Docker directory:
# Option 1: Move existing keystore
cp ~/.aztec/keystore/key1.json aztec-sequencer/keys/keystore.json
# Option 2: Generate directly in the Docker directory
aztec validator-keys new \
--fee-recipient [YOUR_AZTEC_FEE_RECIPIENT_ADDRESS] \
--mnemonic "your twelve word mnemonic phrase here" \
--data-dir aztec-sequencer/keys \
--file keystore.json
Your keystore will have this structure:
{
"schemaVersion": 1,
"validators": [
{
"attester": {
"eth": "ETH_PRIVATE_KEY",
"bls": "BLS_PRIVATE_KEY"
},
"coinbase": "ETH_ADDRESS"
}
]
}
We strongly recommend using the Aztec CLI to generate keystores. Manual creation requires properly formatted BLS keys and signatures, which is error-prone. Use the CLI utility unless you have specific advanced requirements.
Publisher accounts submit block proposals to L1. Each publisher operates independently, and the system does not retry with another publisher if a transaction fails due to insufficient funds.
Examples:
- 3 attesters with 1 publisher → Maintain ≥ 0.3 ETH in that publisher account
- 3 attesters with 2 publishers → Maintain ≥ 0.15 ETH in each publisher account (0.3 ETH total)
Maintaining these minimum balances prevents failed block publications caused by low gas funds.
Step 3: Configure Environment Variables
Add the following to your .env file:
DATA_DIRECTORY=./data
KEY_STORE_DIRECTORY=./keys
LOG_LEVEL=info
ETHEREUM_HOSTS=[your L1 execution endpoint, or a comma separated list if you have multiple]
L1_CONSENSUS_HOST_URLS=[your L1 consensus endpoint, or a comma separated list if you have multiple]
P2P_IP=[your external IP address]
P2P_PORT=40400
AZTEC_PORT=8080
AZTEC_ADMIN_PORT=8880
Find your public IP address with: curl ipv4.icanhazip.com
Step 4: Create Docker Compose File
Create a docker-compose.yml file in your aztec-sequencer directory:
services:
aztec-sequencer:
image: "aztecprotocol/aztec:2.0.4"
container_name: "aztec-sequencer"
ports:
- ${AZTEC_PORT}:${AZTEC_PORT}
- ${AZTEC_ADMIN_PORT}:${AZTEC_ADMIN_PORT}
- ${P2P_PORT}:${P2P_PORT}
- ${P2P_PORT}:${P2P_PORT}/udp
volumes:
- ${DATA_DIRECTORY}:/var/lib/data
- ${KEY_STORE_DIRECTORY}:/var/lib/keystore
environment:
KEY_STORE_DIRECTORY: /var/lib/keystore
DATA_DIRECTORY: /var/lib/data
LOG_LEVEL: ${LOG_LEVEL}
ETHEREUM_HOSTS: ${ETHEREUM_HOSTS}
L1_CONSENSUS_HOST_URLS: ${L1_CONSENSUS_HOST_URLS}
P2P_IP: ${P2P_IP}
P2P_PORT: ${P2P_PORT}
AZTEC_PORT: ${AZTEC_PORT}
AZTEC_ADMIN_PORT: ${AZTEC_ADMIN_PORT}
entrypoint: >-
node
--no-warnings
/usr/src/yarn-project/aztec/dest/bin/index.js
start
--node
--archiver
--sequencer
--network testnet
networks:
- aztec
restart: always
networks:
aztec:
name: aztec
This configuration includes only essential settings. The --network testnet flag applies network-specific defaults—see the CLI reference for all available configuration options.
Step 5: Start the Sequencer
Start the sequencer:
docker compose up -d
Verification
Once your sequencer is running, verify it's working correctly:
Check Sync Status
Check the current sync status (this may take a few minutes):
curl -s -X POST -H 'Content-Type: application/json' \
-d '{"jsonrpc":"2.0","method":"node_getL2Tips","params":[],"id":67}' \
http://localhost:8080 | jq -r ".result.proven.number"
Compare the output with block explorers like Aztec Scan or Aztec Explorer.
Check Node Status
curl http://localhost:8080/status
View Logs
docker compose logs -f aztec-sequencer
Registering a Sequencer
After your sequencer node is set up and running, you must register it with the network to join the sequencer set.
Registration Process
Use the Aztec CLI to register your sequencer onchain. You'll need:
- Your attester address (from your keystore at
validators[0].attester.eth) - A withdrawer address (typically the same as your attester address)
- Your BLS private key (from your keystore at
validators[0].attester.bls) - An L1 RPC endpoint
- A funded Ethereum account to pay for the registration transaction
- The rollup contract address for your network
Register your sequencer:
aztec add-l1-validator \
--l1-rpc-urls [YOUR_L1_RPC_URL] \
--network [NETWORK_NAME] \
--private-key [FUNDING_PRIVATE_KEY] \
--attester [YOUR_ATTESTER_ADDRESS] \
--withdrawer [YOUR_WITHDRAWER_ADDRESS] \
--bls-secret-key [YOUR_BLS_PRIVATE_KEY] \
--rollup [ROLLUP_CONTRACT_ADDRESS]
Parameter descriptions:
--l1-rpc-urls: Your Ethereum L1 RPC endpoint--network: Network identifier (e.g.,testnet,staging-public)--private-key: Private key of an Ethereum account with ETH to pay for gas (this is NOT your sequencer key)--attester: Your sequencer's attester address from the keystore--withdrawer: Ethereum address that can withdraw your stake (typically same as attester)--bls-secret-key: Your BLS private key from the keystore (validators[0].attester.bls)--rollup: The rollup contract address for your network
Extract values from your keystore:
# Get your attester address
jq -r '.validators[0].attester.eth' aztec-sequencer/keys/keystore.json
# Get your BLS private key (this will be used for --bls-secret-key)
jq -r '.validators[0].attester.bls' aztec-sequencer/keys/keystore.json
The --private-key parameter is for a funding account that pays for the registration transaction gas fees. This should NOT be your sequencer's attester or publisher key. Use a separate account with ETH specifically for funding this transaction.
Your sequencer will be added to the validator set once the transaction is confirmed onchain.
Preparing BLS Keys for Staking Dashboard
The staking dashboard requires your BLS keys from the keystore you created earlier (in Step 2) to be converted into an expanded JSON format with G1 and G2 public key points.
What you already have:
From your keystore at aztec-sequencer/keys/keystore.json, you have:
attester.eth: Your Ethereum attester addressattester.bls: Your BLS private key (32-byte hex string)
What the staking dashboard needs:
The staking dashboard requires this JSON format with expanded BLS key material (G1 and G2 public key points):
[
{
"attester": "0xYOUR_ATTESTER_ADDRESS",
"publicKeyG1": {
"x": "FIELD_ELEMENT_AS_DECIMAL_STRING",
"y": "FIELD_ELEMENT_AS_DECIMAL_STRING"
},
"publicKeyG2": {
"x0": "FIELD_ELEMENT_AS_DECIMAL_STRING",
"x1": "FIELD_ELEMENT_AS_DECIMAL_STRING",
"y0": "FIELD_ELEMENT_AS_DECIMAL_STRING",
"y1": "FIELD_ELEMENT_AS_DECIMAL_STRING"
},
"signature": {
"x": "FIELD_ELEMENT_AS_DECIMAL_STRING",
"y": "FIELD_ELEMENT_AS_DECIMAL_STRING"
}
}
]
Field descriptions:
attester: Your Ethereum attester address fromkeystore.json→validators[0].attester.ethpublicKeyG1: Your BLS public key on the G1 curve, derived fromattester.bls(x, y coordinates as decimal strings)publicKeyG2: Your BLS public key on the G2 curve, derived fromattester.bls(x0, x1, y0, y1 coordinates as decimal strings)signature: Proof of possession signature to prevent rogue key attacks (x, y coordinates as decimal strings)
Your keystore contains the BLS private key at attester.bls. You can derive most of the required registration format using the Aztec CLI and TypeScript utilities.
Step 1: Extract your keystore values
# Extract your attester address
jq -r '.validators[0].attester.eth' aztec-sequencer/keys/keystore.json
# Extract your BLS private key
jq -r '.validators[0].attester.bls' aztec-sequencer/keys/keystore.json
If the second command returns null, regenerate your keystore with --mnemonic or --ikm (see Generating Keys).
Step 2: Compute G1 and G2 public keys
You can use the Aztec foundation library to compute the public keys from your BLS private key. Create a TypeScript file:
import { computeBn254G1PublicKey, computeBn254G2PublicKey } from '@aztec/foundation/crypto';
const blsPrivateKey = 'YOUR_BLS_PRIVATE_KEY_FROM_KEYSTORE'; // 0x-prefixed hex
const attesterAddress = 'YOUR_ATTESTER_ETH_ADDRESS'; // from keystore
async function generateRegistrationData() {
// Compute G1 public key (uncompressed)
const g1 = await computeBn254G1PublicKey(blsPrivateKey);
// Compute G2 public key
const g2 = await computeBn254G2PublicKey(blsPrivateKey);
const registrationData = {
attester: attesterAddress,
publicKeyG1: {
x: g1.x.toString(),
y: g1.y.toString(),
},
publicKeyG2: {
x0: g2.x.c0.toString(),
x1: g2.x.c1.toString(),
y0: g2.y.c0.toString(),
y1: g2.y.c1.toString(),
},
// signature: { x: "...", y: "..." } // TODO: Proof of possession signature
};
console.log(JSON.stringify([registrationData], null, 2));
}
generateRegistrationData();
Step 3: Generate proof of possession signature
The signature prevents rogue key attacks by proving you control the private key corresponding to the public keys. Once available, you'll be able to add the signature field to complete your registration JSON.
Monitoring Sequencer Status
You can query the status of any sequencer (attester) using the Rollup and GSE (Governance Staking Escrow) contracts on L1.
Prerequisites
- Foundry installed (
castcommand) - Ethereum RPC endpoint
- Registry contract address for your network
Get Contract Addresses
First, get the canonical Rollup contract address from the Registry:
# Get the canonical rollup address
cast call [REGISTRY_CONTRACT_ADDRESS] "getCanonicalRollup()" --rpc-url [YOUR_RPC_URL]
Then get the GSE contract address from the Rollup:
# Get the GSE contract address
cast call [ROLLUP_ADDRESS] "getGSE()" --rpc-url [YOUR_RPC_URL]
Query Sequencer Status
Check the complete status and information for a specific sequencer:
# Get full attester view (status, balance, exit info, config)
cast call [ROLLUP_ADDRESS] "getAttesterView(address)" [ATTESTER_ADDRESS] --rpc-url [YOUR_RPC_URL]
This returns an AttesterView struct containing:
- status - The sequencer's current status (see Status Codes below)
- effectiveBalance - The sequencer's effective stake balance
- exit - Exit information (if the sequencer is exiting)
- config - Attester configuration (withdrawer address and public key)
Status Codes
| Status | Name | Meaning |
|---|---|---|
| 0 | NONE | The sequencer does not exist in the sequencer set |
| 1 | VALIDATING | The sequencer is currently active and participating in consensus |
| 2 | ZOMBIE | The sequencer is not active (balance fell below ejection threshold, possibly due to slashing) but still has funds in the system |
| 3 | EXITING | The sequencer has initiated withdrawal and is in the exit delay period |
Performance Monitoring
Track your sequencer's performance by monitoring:
- Effective balance - Should remain above the ejection threshold
- Status - Should be VALIDATING for active participation
- Attestation rate - How many attestations you've successfully submitted
- Proposal success rate - How many of your proposed blocks were accepted
- Network participation metrics - Overall participation in network consensus
Exiting a Sequencer
Information about the exit process will be added when the mechanism is finalized. Check the Aztec Discord for the latest information on exiting the sequencer set.
Troubleshooting
Port forwarding not working
Issue: Your node cannot connect to peers.
Solutions:
- Verify your external IP address matches the
P2P_IPsetting - Check firewall rules on your router and local machine
- Test connectivity using:
nc -zv [your-ip] 40400
Sequencer not syncing
Issue: Your node is not synchronizing with the network.
Solutions:
- Check L1 endpoint connectivity
- Verify both execution and consensus clients are fully synced
- Review logs for specific error messages
- Ensure L1 endpoints support high throughput
Keystore issues
Issue: Keystore not loading or errors about invalid keys.
Solutions:
- Ensure
keystore.jsonis properly formatted - Verify private keys are valid Ethereum private keys
- Check file permissions on the keys directory
Docker issues
Issue: Container won't start or crashes.
Solutions:
- Ensure Docker and Docker Compose are up to date
- Check disk space availability
- Verify the
.envfile is properly formatted - Review container logs:
docker compose logs aztec-sequencer
Common Issues
See the Operator FAQ for additional common issues and resolutions.
Next Steps
- Monitor your sequencer's performance and attestation rate
- Join the Aztec Discord for operator support
- Review creating and voting on proposals for participating in governance
- Set up high availability to run your sequencer across multiple nodes for redundancy
- Learn about advanced keystore patterns for running multiple sequencer identities or complex configurations