Post-Upgrade
Exactly 3 hours after the network reaches the stop-network-slot, at the predefined Mesa genesis timestamp, block production starts and the network is successfully upgraded.
This page helps you verify your node is healthy and running on the Mesa chain.
The checks are split into separate tabs for Rosetta API and Exchange because the two roles overlap but are not the same. Rosetta API here means an operator running the mina-rosetta integration layer (typically alongside an archive node). Exchange means an operator running the customer-facing platform that ingests Mina balances and submits payments. Most exchanges use Rosetta, so they will work through both tabs; a handful operate without Rosetta (custom GraphQL integrations) and can skip the Rosetta tab.
Verify Your Node
First, confirm your node is on the Mesa chain — this check is identical for every role:
# If using automode, check the activation file exists
ls ~/.mina-config/auto-fork-mesa-mainnet/activated
# Check node status
mina client status
You should see:
- Sync status:
Synced - Chain ID matching the Mesa chain ID for your network. The chain ID changes at the fork and is network-specific (mainnet, devnet, and preflight each get their own) — the exact value is published in the Mesa release announcement alongside the first Mesa packages.
- Git SHA-1 matching the published Mesa daemon commit
- Genesis timestamp matching the published Mesa genesis timestamp
- Block height advancing
Then run the role-specific checks below.
- Block Producer
- SNARK Coordinator / Worker
- Archive Node
- Rosetta API
- Exchange
Verify block production
Verify block production the same way you would on Berkeley — see Block Producer Node for the relevant mina client status fields and checks. If you are a Delegation Program participant, your uptime continues to be tracked on the Mesa chain.
Check logs for errors
# Look for any errors in recent logs
journalctl -u mina --since "1 hour ago" --no-pager | grep -i error
# For Docker
docker logs mina --since 1h 2>&1 | grep -i error
Verify SNARK workers are connected
# Check that workers are producing proofs
mina client status | grep -i snark
SNARK workers are not compatible across the fork — the transaction SNARK changed in Mesa, so a Berkeley-era worker cannot produce valid work for a Mesa coordinator. After the fork, every worker must run a Mesa-compatible release. Workers spawned by the coordinator pick up the new binary automatically; standalone workers must be redeployed.
To restart a standalone worker against the coordinator:
/usr/lib/mina/mesa/mina internal snark-worker \
--proof-level full \
--shutdown-on-disconnect false \
--daemon-address <coordinator-ip>:<port>
The automode dispatcher does not route mina internal subcommands, and mina-mesa is not on PATH in the Docker image — invoke the Mesa worker binary by its full install path (/usr/lib/mina/mesa/mina) as shown above.
1. Verify archive data integrity
# Check the schema-version table
psql -U <user> -d <db> -c "SELECT * FROM migration_history;"
# Run the hardfork toolbox verification
mina-archive-hardfork-toolbox verify-upgrade \
--postgres-uri postgres://<user>:<pass>@localhost:5432/<db> \
--protocol-version <version> \
--migration-version <version>
2. Check for missing blocks
Query the archive database to see if blocks are being captured:
psql -U <user> -d <db> -c "SELECT height, state_hash FROM blocks ORDER BY height DESC LIMIT 5;"
If blocks are missing, use the archive tooling to backfill. See In-Depth Validation below.
1. Complete the Archive Node checks above first
Rosetta depends on a healthy archive database.
2. Verify Rosetta is responding
curl -s http://localhost:3088/network/list \
-H 'Content-Type: application/json' \
-d '{"metadata":{}}' | jq .
You should see mainnet in the response.
3. Test a balance lookup
curl -s http://localhost:3088/account/balance \
-H 'Content-Type: application/json' \
-d '{
"network_identifier": {"blockchain":"mina","network":"mainnet"},
"account_identifier": {"address":"<your-address>"}
}' | jq .
1. Verify your integration stack
- Confirm Rosetta API is responding (if used)
- Confirm archive database is up to date (if used directly)
- Test a small internal MINA transfer before re-enabling customer-facing operations
2. Re-enable deposits and withdrawals
Only re-enable MINA deposits and withdrawals after:
- Block production is confirmed (blocks are advancing)
- Your integration is verified end to end
- You have confirmed balances match expectations
In-Depth Validation
The checks in the tabs above cover basic health. This section provides deeper validation procedures for operators who want thorough verification.
- Daemon
- Archive Node
- Rosetta API
- Network-Level
-
Verify signature kind — query the GraphQL endpoint to confirm the correct signature kind:
query {
signatureKind
}For mainnet, this should return
mainnet. -
Verify connectivity — ensure your node has peers and is connected to the network. Check that the node is receiving and gossiping blocks.
Use the mina-archive-hardfork-toolbox to verify the upgrade. All commands require --postgres-uri postgresql://<user>:<password>@<host>:<port>/<db>. See the Archive Upgrade page for full toolbox documentation.
Verify schema upgrade:
mina-archive-hardfork-toolbox verify-upgrade \
--postgres-uri <uri> \
--protocol-version <version> \
--migration-version <version>
You can also verify manually:
SELECT * FROM migration_history;
Validate fork block integrity (after the fork activates):
mina-archive-hardfork-toolbox validate-fork \
--postgres-uri <uri> \
--fork-state-hash <hash> \
--fork-slot <slot>
Verify no commands after fork point:
mina-archive-hardfork-toolbox fork-candidate no-commands-after \
--postgres-uri <uri> \
--fork-state-hash <hash> \
--fork-slot <slot>
Verify extended zkApp state columns exist:
SELECT column_name FROM information_schema.columns
WHERE table_name = 'zkapp_states_nullable'
AND column_name LIKE 'element%'
ORDER BY column_name;
Confirm columns element0 through element31 exist.
Check for missing blocks:
mina-missing-blocks-auditor --archive-uri postgres://<user>:<password>@<address>:<port>/<db>
Compare block heights — the archive height should match or be close to the daemon's reported height:
SELECT MAX(height) FROM blocks;
Use rosetta-cli to verify the API conforms to the Rosetta specification:
# Spec check
rosetta-cli check:spec --configuration-file config.json
# Data check — aim for reconciliation coverage above 60%
rosetta-cli check:data --configuration-file config.json
# Construction check (after block production starts)
rosetta-cli check:construction --configuration-file config.json --start-block 2
-
Verify seed connectivity — confirm all seeds listed in
https://bootnodes.minaprotocol.com/networks/mainnet.txtare connectable. -
Verify block production — monitor that blocks are being produced at the expected cadence via block explorers and your node's logs.
-
Verify empty blocks during finalization — confirm that all blocks between the stop-transaction-slot and stop-network-slot were empty (no user transactions, no coinbase, no fee transfers):
SELECT b.height, b.state_hash
FROM blocks b
WHERE b.global_slot_since_genesis > <stop_transaction_slot>
AND b.global_slot_since_genesis <= <stop_network_slot>
AND (
EXISTS (SELECT 1 FROM blocks_user_commands buc WHERE buc.block_id = b.id)
OR EXISTS (SELECT 1 FROM blocks_internal_commands bic WHERE bic.block_id = b.id)
);This query should return zero rows.
In rare cases a non-empty block can appear after the stop-transaction-slot — for example if a block producer and an archive operator both ran a build without the stop-slot release. As long as the majority of stake upgraded, such a block lands on a short fork and does not affect the hard fork block, so it is not a problem for the upgrade.
Help Monitor the Network
The Node Status reporting service is enabled by default on the Mesa daemon. If you want to keep it on and point it at the o1Labs collection endpoints, pass:
--simplified-node-stats
--node-status-url https://nodestats.minaprotocol.com/submit/stats
--node-error-url https://nodestats.minaprotocol.com/submit/stats
--simplified-node-stats(no value) makes the reported payload a minimal, non-sensitive subset (version, sync status, peer count).--node-status-urlis the endpoint that receives status reports.--node-error-urlis the endpoint that receives crash reports the daemon emits just before terminating.
To opt out of the Node Status service entirely, pass --disable-node-status (no value). Note: the previously-documented --node-stats-type full|none argument was never accepted by the daemon — --simplified-node-stats and --disable-node-status are the actual flag names in the Mesa release.
Report Issues
If you encounter any problems after the upgrade:
Flag and Configuration Reference
The flags below are unchanged from Berkeley — if your node was running correctly before the fork, the same flags will work on Mesa. This section is provided as a reference for operators setting up fresh nodes or verifying their configuration.
For full details, see the Mesa release notes.
- Only if you manually manage your genesis config or genesis ledgers, repoint
--genesis-ledger-dirand-config-fileat the Mesa-specific files. Operators who rely on the package-installed genesis config — including all automode users — do not need to change anything. If you do override them, both ship inside the Mesa Debian/Docker package:--genesis-ledger-dirshould be/var/lib/coda/mesa(or the equivalent path your package installed), and-config-fileshould be the Mesa runtime config (typically/etc/mina/mesa/daemon.json). - All other flags carry over unchanged —
--block-producer-key,--libp2p-keypair,--peer-list-url,--external-ip/port, log flags, etc. behave the same on Mesa as on Berkeley.
Block Producer flags
mina daemon
--block-producer-key <path to the wallet private key file>
--config-directory <path to the mina configuration directory>
--file-log-rotations 500
--libp2p-keypair <keyfile path>
--log-json
--peer-list-url https://bootnodes.minaprotocol.com/networks/mainnet.txt
ENVIRONMENT VARIABLES
RAYON_NUM_THREADS=6
MINA_LIBP2P_PASS
MINA_PRIVKEY_PASS
SNARK Coordinator flags
mina daemon
--config-directory <path to the mina configuration directory>
--enable-peer-exchange true
--file-log-rotations 500
--libp2p-keypair <keyfile path>
--log-json
--peer-list-url https://bootnodes.minaprotocol.com/networks/mainnet.txt
--run-snark-coordinator <public key>
--snark-worker-fee 0.001
--work-selection [seq|rand|roffset]
ENVIRONMENT VARIABLES
MINA_LIBP2P_PASS
SNARK Worker flags
mina internal snark-worker
--proof-level full
--shutdown-on-disconnect false
--daemon-address <snark coordinator IP:port>
ENVIRONMENT VARIABLES
RAYON_NUM_THREADS=8
Archive Node flags
Running an Archive Node involves a non-block-producing daemon connected to the archive process and a PostgreSQL database. For more information, see Archive Node.
Daemon (non-block-producing):
mina daemon
--archive-address <archive_address>:3086
--config-directory <path to mina config>
--enable-peer-exchange true
--file-log-rotations 500
--libp2p-keypair <keyfile path>
--log-json
--peer-list-url https://bootnodes.minaprotocol.com/networks/mainnet.txt
ENVIRONMENT VARIABLES
MINA_LIBP2P_PASS
Archive process:
mina-archive run
--metrics-port <port>
--postgres-uri postgres://<user>:<password>@<address>:<port>/<db>
--server-port 3086
--log-json
--log-level DEBUG
Rosetta API
Once your Archive Node stack is running:
docker run \
--name rosetta --rm \
-p 3088:3088 \
--entrypoint '' \
minaprotocol/mina-rosetta:<mesa-version>-bullseye-mainnet \
/usr/local/bin/mina-rosetta \
--archive-uri "${PG_CONNECTION_STRING}" \
--graphql-uri "${GRAPHQL_URL}" \
--log-json \
--log-level ${LOG_LEVEL} \
--port 3088