Skip to main content

Examples

The walkthroughs below follow concrete operators through the four Mesa upgrade phases (Pre-Upgrade, State Finalization, Upgrade, Post-Upgrade) for different roles and setups. Click to expand the example that matches your situation.

Example: Block Producer Upgrading with Automode (Debian)

Imagine you are Alice, a block producer running on a Debian server. Here is what your upgrade looks like end to end.

Weeks before the fork — Alice checks hardware requirements and installs the automode packages:

sudo apt-get update
sudo apt-get install mina-mainnet-automode=4.x.x

She starts her node normally. The dispatcher (installed as /usr/local/bin/mina) needs one automode-specific setting: MINA_HARDFORK_STATE_DIR must point at her config directory — it must match --config-directory, because that is where the dispatcher looks for the auto-fork-mesa-mainnet/activated marker to choose between the pre-fork and Mesa runtime. Export the variable and pass the matching flag:

export MINA_HARDFORK_STATE_DIR=~/.mina-config

mina daemon \
--block-producer-key ~/keys/my-wallet \
--config-directory ~/.mina-config \
--libp2p-keypair ~/keys/libp2p-key \
--peer-list-url https://bootnodes.minaprotocol.com/networks/mainnet.txt \
--file-log-rotations 500 \
--log-json

The automode dispatcher runs the pre-fork binary until the fork activates. To preview which runtime and arguments the dispatcher will exec without running it, prefix the command with MINA_DISPATCHER_DRYRUN=1.

For the full preparation checklist, see Requirements.

Hours before the fork (State Finalization) — The network reaches the stop-transaction-slot. Alice's node keeps producing blocks — she does nothing. Empty blocks are produced for 100 slots (exactly 5 hours) until all nodes agree on the final state.

For details on this phase, see State Finalization.

Fork day (Upgrade) — The network halts at the stop-network-slot. Alice's daemon generates the Mesa configuration, writes the activated marker file, and shuts down cleanly (exit code 0). Because Alice uses systemd with Restart=always, the daemon restarts automatically. On restart, the dispatcher detects the activated file and launches the Mesa binary. Alice does nothing — this all happens automatically.

For what happens if you chose manual mode instead, see Upgrade. For details on the restart mechanism, see Upgrade Modes - Details.

After the fork (Post-Upgrade) — Exactly 3 hours after the stop-network-slot, the first Mesa block is produced. Alice verifies:

# Check if the activated file exists (path depends on your config directory and network ID)
ls ~/.mina-config/auto-fork-mesa-mainnet/activated

# Confirm Mesa chain ID
mina client status
Dispatcher and non-daemon commands

The automode dispatcher only supports daemon and client status subcommands. For other commands, invoke the version-specific binary by its full path (/usr/lib/mina/mesa/mina or /usr/lib/mina/berkeley/mina) directly. See Troubleshooting for details.

She's done. Her node is producing blocks on Mesa.

For post-upgrade verification, monitoring, and flag reference, see Post-Upgrade.

Example: Block Producer — Manual Mode (Docker)

Carlos runs a block producer using Docker and prefers manual control over the upgrade.

Weeks before the fork — Carlos pulls the stop-slot Docker image and starts his node:

docker pull minaprotocol/mina-daemon:<version>-bullseye-mainnet

docker run --name mina -d \
--restart=always \
-v mina-config:/root/.mina-config \
minaprotocol/mina-daemon:<version>-bullseye-mainnet \
daemon \
--block-producer-key /keys/my-wallet \
--config-directory /root/.mina-config \
--libp2p-keypair /keys/libp2p-key \
--peer-list-url https://bootnodes.minaprotocol.com/networks/mainnet.txt \
--file-log-rotations 500 \
--log-json

For the full preparation checklist, see Requirements.

Hours before the fork (State Finalization) — Carlos keeps his node running. He does nothing during this phase.

For details on this phase, see State Finalization.

Fork day (Upgrade) — The network halts at the stop-network-slot. Carlos waits for the Mesa release announcement, then swaps to the new image.

Throughout these examples, <mesa-version> is a placeholder for the Mesa release tag announced for your target network. For the Mesa Trail test network the current value is published on Mesa Trail Network; for devnet/mainnet the value will be published with the corresponding release announcement.

docker stop mina && docker rm mina

docker pull minaprotocol/mina-daemon:<mesa-version>-bullseye-mainnet

docker run --name mina -d \
--restart=always \
-v mina-config:/root/.mina-config \
minaprotocol/mina-daemon:<mesa-version>-bullseye-mainnet \
daemon \
--block-producer-key /keys/my-wallet \
--config-directory /root/.mina-config \
--libp2p-keypair /keys/libp2p-key \
--peer-list-url https://bootnodes.minaprotocol.com/networks/mainnet.txt \
--file-log-rotations 500 \
--log-json

For detailed upgrade instructions, see Upgrade.

After the fork (Post-Upgrade) — Exactly 3 hours after the stop-network-slot, block production starts. Carlos verifies:

docker exec mina mina client status   # confirms Mesa chain ID

For post-upgrade verification, monitoring, and flag reference, see Post-Upgrade.

Example: Archive Node / Explorer Operator

Eve runs an archive node, a Rosetta API instance, and a block explorer. She needs to upgrade both the daemon and the database.

Weeks before the fork — Eve installs the stop-slot release and decides on her upgrade method:

sudo apt-get update
sudo apt-get install mina-mainnet=3.x.x

She chooses the trustless path — running the upgrade script early, while her archive is still online:

# Install the Mesa archive package — it ships the upgrade script at
# /etc/mina/archive/upgrade_to_mesa.sql. The upgrade is backward-compatible,
# so her Berkeley archive keeps running normally afterwards.
sudo apt-get update
sudo apt-get install mina-archive-mainnet=4.x.x

# Back up the database first
pg_dump -U <user> archive_db > berkeley-archive-backup.sql

# Run the shipped upgrade script (completes in under 1 minute)
psql -U <user> -d archive_db -f /etc/mina/archive/upgrade_to_mesa.sql

# Verify
psql -U <user> -d archive_db -c "SELECT * FROM migration_history;"

The script is backward-compatible — her existing Berkeley archive node keeps working normally after the upgrade.

For the full archive upgrade guide, see Archive Upgrade.

Hours before the fork (State Finalization) — Eve keeps her archive node running to capture all finalized blocks.

For details on this phase, see State Finalization.

Fork day (Upgrade) — The network halts. Eve installs the Mesa archive release and points it at her already-upgraded database:

sudo systemctl stop mina-archive
sudo systemctl stop mina

sudo apt-get update
sudo apt-get install mina-archive-mainnet=4.x.x mina-mainnet=4.x.x

# Start archive process pointing to the upgraded DB
mina-archive run \
--postgres-uri postgres://<user>:<pass>@localhost:5432/archive_db \
--server-port 3086 \
--log-json --log-level DEBUG

# Start the non-block-producing daemon connected to the archive
mina daemon \
--archive-address localhost:3086 \
--config-directory ~/.mina-config \
--libp2p-keypair ~/keys/libp2p-key \
--peer-list-url https://bootnodes.minaprotocol.com/networks/mainnet.txt \
--file-log-rotations 500 \
--log-json

She also restarts Rosetta:

docker run --name rosetta --rm -d \
-p 3088:3088 \
--entrypoint '' \
minaprotocol/mina-rosetta:<mesa-version>-bullseye-mainnet \
/usr/local/bin/mina-rosetta \
--archive-uri "postgres://<user>:<pass>@localhost:5432/archive_db" \
--graphql-uri "http://localhost:3085/graphql" \
--log-json --port 3088

For detailed upgrade instructions, see Upgrade.

After the fork (Post-Upgrade) — Block production resumes. Eve verifies data integrity:

# Check the archive is in sync
mina client status

# Run the verification toolbox
mina-archive-hardfork-toolbox verify-upgrade \
--postgres-uri postgres://<user>:<pass>@localhost:5432/archive_db \
--protocol-version <version> \
--migration-version <version>

She checks her explorer UI to confirm new Mesa blocks are appearing and the historical data is intact.

For the full validation workflow, see Post-Upgrade and the Archive Hardfork Toolbox.

Example: zkApp Developer

Frank maintains a zkApp deployed on mainnet. His contract uses on-chain state and he wants to take advantage of Mesa's expanded 32-field state.

Weeks before the fork — Frank updates his o1js dependency to the Mesa-compatible version and tests his zkApp on the Mesa Trail test network:

npm install o1js@3.0.0-mesa.rc2

This release targets the Mesa transaction protocol. o1js@latest currently resolves to a pre-Mesa version and will produce transactions that Mesa nodes reject. See Mesa Trail Network for the matching daemon/archive/rosetta release.

He verifies that:

  • His contract recompiles cleanly against Mesa-compatible o1js and deploys on Mesa Trail
  • Transactions execute end-to-end against the redeployed contract
  • If he plans to use the expanded state fields (indexes 8–31), his updated contract version compiles and deploys on Mesa Trail

For details on testing against Mesa Trail, see Mesa Trail Network.

Hours before the fork (State Finalization) — Frank does nothing. His deployed zkApp keeps running on the Berkeley chain. No transactions can be submitted during this phase anyway.

Fork day (Upgrade) — Frank does nothing during the network halt. His zkApp account and on-chain state values carry over to the Mesa chain automatically (including state fields at indexes 0–7). However, the verification key generated for Berkeley is no longer valid under the Mesa protocol — the contract cannot process transactions on Mesa until it is redeployed.

After the fork (Post-Upgrade) — Block production resumes on Mesa. Frank must redeploy his zkApp before it can accept transactions, regardless of whether he uses the new state fields:

# Required for every zkApp — the Mesa protocol version bump invalidates the Berkeley verification key
zkapp deploy --network mainnet

If he is also adopting the expanded 8–31 state slots, this same deployment step ships the updated contract version that declares the new fields.

For post-upgrade details, see Post-Upgrade.

Example: Exchange Upgrading to Mesa

Bob is an exchange operator. His main concern is avoiding lost deposits.

Bob runs the full Rosetta-based stack, so he upgrades three packages — the node, the archive node, and the Rosetta API — plus his PostgreSQL archive database:

  • mina-mainnet — the daemon
  • mina-archive-mainnet — the archive node
  • mina-rosetta-mainnet — the Rosetta API

(Exchanges on a custom GraphQL integration that do not run Rosetta or an archive only need mina-mainnet.)

Weeks before the fork — Bob tests his integration (Rosetta API, mina-signer) on the Mesa Trail test network. He reviews schema changes and installs the stop-slot release on his node:

sudo apt-get install mina-mainnet=3.x.x

For the full exchange preparation checklist, see Requirements.

Hours before the fork — Before the stop-transaction-slot arrives, Bob disables MINA deposits and withdrawals on his platform and notifies customers about the maintenance window.

danger

Any transactions submitted after the stop-transaction-slot will not exist on the Mesa chain. See State Finalization for the full exchange guidance.

Fork day — The network halts. Bob waits for the Mesa release announcement, then upgrades all three components and migrates his archive database:

# Stop the stack
sudo systemctl stop mina mina-archive

# Install the Mesa releases for the node, archive, and Rosetta
sudo apt-get update
sudo apt-get install mina-mainnet=4.x.x mina-archive-mainnet=4.x.x mina-rosetta-mainnet=4.x.x

# Upgrade the archive schema — the mina-archive package ships the script
psql -U <user> -d archive_db -f /etc/mina/archive/upgrade_to_mesa.sql

# Restart the node and archive, then bring Rosetta back up
sudo systemctl start mina mina-archive

For detailed upgrade instructions, see Upgrade.

After the fork — Block production resumes. Bob verifies his node is on the Mesa chain, confirms Rosetta API is working, then re-enables MINA deposits and withdrawals.

mina client status   # verify Mesa chain ID
# test a small internal transfer before opening to customers

For post-upgrade verification, monitoring, and flag reference, see Post-Upgrade.