Community

Rosetta and Archive Program Details (APPENDIX)

The primary goal for Archive Node Operators in the Trailblazers program (Mesa Upgrade Testnet) is to validate the upgrade path for existing Berkeley-era Rosetta deployments, ensuring they function correctly under the new Mesa protocol rules.

Program Details

Last Revised: May 27, 2026

The primary goal for Archive Node Operators in the Trailblazers program (Mesa Upgrade Testnet) is to validate the upgrade path for existing Berkeley-era Rosetta deployments, ensuring they function correctly under the new Mesa protocol rules. Archive Node Operators run an Archive Node, Rosetta API, and Archive Node API.

There were no significant Rosetta changes introduced in Mesa so this is primarily regression testing.

Please refer to Archive Node API github repository for setup guide: https://github.com/o1-labs/Archive-Node-API

If something goes wrong at any stage — missing blocks, unexpected fork point, replayer failure, Rosetta reconciliation drift, etc. — find detailed information at https://docs.minaprotocol.com/network-upgrades/mesa and post in the operator Discord channel: #mesa-upgrade-testnet. Do not try to recover silently; other operators may be hitting the same issue.

Rosetta Operator Responsibilities

Rosetta Operators participating in the MUT program are expected to execute the following steps:

STAGE 1: Berkeley-based Test Network
MUT Network Start (Prior to Trailblazers start -3 days)

Goals:

  • Archive Node Operators join Mesa Upgrade Testnet

Runbook:

  1. Archive Node Operators sync with network and validate services
    1. Archive 
      1. Ensure no missing blocks  by running missing block auditor. Daemon mode is preferred as it will run continuously in the background. See DOCS for more details

                                    1. One shot

 mina-missing-blocks-auditor --archive-uri "$PG_URI" 
echo "exit=$?" # 0 means clean  

                                     2. As Daemon

DB_USERNAME=.. \
PGPASSWORD=... \
DB_HOST=... \
DB_PORT=... \
DB_NAME=.. \
MINA_NETWORK=... \
PRECOMPUTED_BLOCKS_URL=.... \
TIMEOUT=600 \
mina-missing-blocks-guardian daemon

                                 ii. Ensure successful replayer run.

                                            1. First time

# Convert genesis ledger to replayer input file. genesis_ledger.json can be obtained from daemon node docker or debian (by default stored in /var/lib/coda/config_{commit}.json)

jq '{genesis_ledger: .ledger}' genesis_ledger.json > replayer_input.json 

mina-replayer \ 
--input-file replayer_input.json \ 
--archive-uri {CONNECTION_STRING_TO_DB} \ 
--checkpoint-interval 10000 \ 
--checkpoint-output-folder ./checkpoints \ 
--log-level Info --log-json | tee replayer.log

                           2. Nth time (it is a good idea to run it every 12 hours to replay new canonical blocks)

# replayer checkpoint will be produced after first time run

 jq '{genesis_ledger: .ledger}' genesis_ledger.json > replayer_input.json                                                                                                    
                                                                                                                                                                                                           
  mina-replayer \                                                                                                                                                                                          
    --input-file ./checkpoints/replayer_checkpoint_XXXX.json \                                                                                                                                                                     
    --archive-uri {CONNECTION_STRING_TO_DB} \                                                                                                                                                                              
    --output-file replayer_output.json \
    --checkpoint-interval 10000 \                                                                                                                                                                          
    --checkpoint-output-folder ./checkpoints \                                                                                                                                                             
    --log-level Info --log-json | tee replayer.log

            b. Rosetta

                     i. Ensure you are connected to correct network

# ROSETTA_URL env var points to base rosetta url (e.g. http://localhost:3087)

curl -s -X POST $ROSETTA_URL/network/list -H 'Content-Type: application/json' -d '{}' | jq .                                                                                                             
  
# Expect: { "network_identifiers":[{"blockchain":"mina","network":"testnet"}] }                                                                                                                           
                                                                                                                                                                                                           
curl -s -X POST $ROSETTA_URL/network/status -H 'Content-Type: application/json' \                                                                                                                        
    -d "{\"network_identifier\":{\"blockchain\":\"mina\",\"network\":\"testnet\"}}" | jq '.current_block_identifier, .genesis_block_identifier'    

Gotcha: Rosetta reports the network identifier that the daemon advertises, which is not always the value you expect.  Always resolve the real network name via /network/list before using it anywhere else.

                    ii. Query some transactions and blocks

# Get network id

NID=$("curl -s -X POST $ROSETTA_URL/network/status -H 'Content-Type: application/json' \   
    -d "{\"network_identifier\":{\"blockchain\":\"mina\",\"network\":\"testnet\"}}")               
                                                                                       
      # Latest block

curl -s -X POST $ROSETTA_URL/block -H 'Content-Type: application/json' \                                             
    -d "{\"network_identifier\":$NID,\"block_identifier\":{}}" | \
     jq '.block.block_identifier, .block.transactions | length'
                                                                     
      # Block by height

curl -s -X POST $ROSETTA_URL/block -H 'Content-Type: application/json' \     
    -d "{\"network_identifier\":$NID,\"block_identifier\":{\"index\":100}}" | jq '.block.block_identifier'   

  # Specific tx in a block   
                                                                                                                                                                              
curl -s -X POST $ROSETTA_URL/block/transaction -H 'Content-Type: application/json' \      
    -d "{\"network_identifier\":$NID,\"block_identifier\":{\"index\":100,\"hash\":\"<state_hash>\"},\"transaction_identifier\":{\"hash\":\"<tx_hash>\"}}" | jq .

⚠ ROSETTA_URL:  Should point to URL of your rosetta instance. E.g. http://localhost:3087

Find more detailed information in the docs (https://docs.minaprotocol.com/network-upgrades/mesa) and reach out in Discord if you experience any issues.

STAGE 2: UMT testing 

Step 1 – State Finalization Period – Stop-slot release (day 2)

Goals:

  • Test halting the Network using the stop-slot-release

Runbook:

  1. Archive Node Operators upgrade to the stop-slot-release
  2. Ensure the Archive Node and Rosetta API processed all the blocks and TXs were added after the upgrade

            a. Run again missing block auditor

  mina-missing-blocks-auditor --archive-uri "$PG_URI"; echo "exit=$?"    

          b. Ensure height of canonical blocks

psql "$PG_URI" -c "SELECT MAX(height), MAX(global_slot_since_genesis) FROM blocks WHERE chain_status='canonical';"     

 

This check can be performed just couple times before stop-transaction-slot 

      3. MUT Network stops accepting new transactions at the predefined stop-transaction-slot

             a. Monitor no new transaction after stop-transaction-slot

 
# Fetch slots from runtime config:   
      
STOP_TX_SLOT=$(jq -r '.daemon.stop_transaction_slot'  runtime_config.json) 
STOP_NET_SLOT=$(jq -r '.daemon.stop_network_slot'     runtime_config.json) 
                               
# No new *user* txs after stop_transaction_slot       
psql "$PG_URI" <<SQL              
  SELECT COUNT(*) FROM user_commands uc                                                                                                                                 
  JOIN blocks_user_commands buc ON buc.user_command_id=uc.id     
  JOIN blocks b ON b.id=buc.block_id    
  WHERE b.global_slot_since_genesis > $STOP_TX_SLOT;   -- want 0
  SQL

⚠ This check can be performed a couple of times between stop-transaction-slot and stop-network-slot. Periodic spot checks are sufficient. A single check shortly before the stop slot is enough — you do not need to watch this continuously for the full stop window. Confirm the result once before the slot and once after.

             b. Ensure no new blocks until the network comes to a halt and stop-network-slot

# No new blocks past stop_network_slot     

watch -n 30 "psql '$PG_URI' -tAc \"SELECT MAX(global_slot_since_genesis) FROM blocks;\""   

# Value should plateau at <= $STOP_NET_SLOT    

# Optional GraphQL liveness check on the daemon:

curl -s $GRAPHQL_URL -H 'Content-Type: application/json' \   
    -d '{"query":"{ bestChain(maxLength:1){ protocolState{ consensusState{ slotSinceGenesis blockHeight } } } }"}' | jq .

 This check can be performed a couple of times between stop-network-slot and mesa genesis

      4. Archive Operators upgrade archives to Mesa schema after the stop-network-slot.

             a. Run upgrade script:

  psql "$PG_URI" -v ON_ERROR_STOP=1 \   
    -f /etc/mina/archive/upgrade_to_mesa.sql 2>&1 | tee mesa_upgrade.log
       
  # Verify migration recorded success        
  psql "$PG_URI" -c "SELECT * FROM migration_history ORDER BY commit_start_at DESC LIMIT 1;"   
  # current_protocol_version='3.0.0' target='4.0.0' end_at IS NOT NULL AND success=true   

Note: the upgrade script ships inside the Mesa archive Docker image as well as debian package at /etc/mina/archive/upgrade_to_mesa.sql (underscores, not hyphens). If the image is not mounted on the archive host, extract it:

docker run –rm <MINA_ARCHIVE_IMAGE> \
cat /etc/mina/archive/upgrade_to_mesa.sql > upgrade_to_mesa.sql

⚠ Script can also be run multiple times. If you need to revert it use (/etc/mina/archive/downgrade_to_mesa.sql).

⚠ PG_URI: stands for db connection string e.g. postgres://postgres:pass@localhost:5432/archiv

Find more detailed information in the docs and reach out in Discord if you experience any issues.

Step 2 – Hard Fork Transition using Legacy Mode (day 3)

Goals:

  • All nodes running legacy mode (manual upgrade similar to Berkeley HF) will transition over to the new fork

Runbook:

  1. Mesa build is distributed by o1Labs.  Archive/Rosetta Operators start upgrading their nodes 

                a. Archive Node

                        i. Ensure you have fork point block as canonical

  # Distinct protocol versions seen in the archive 
  psql "$PG_URI" -c "    
    SELECT pv.transaction, pv.network, pv.patch, COUNT(*) AS blocks
    FROM blocks b    
    JOIN protocol_versions pv ON pv.id = b.protocol_version_id
    GROUP BY 1,2,3     
    ORDER BY 1,2,3;"    
  
  # Post-fork blocks must use transaction=4    
  psql "$PG_URI" -c "         
    SELECT MIN(b.height) AS first_mesa_block, MAX(b.height) AS latest_mesa_block   
    FROM blocks b   
    JOIN protocol_versions pv ON pv.id = b.protocol_version_id
    WHERE pv.transaction = 4 AND b.chain_status = 'canonical';"   
         
  Expected after Step 3 (post-fork): a non-empty row with transaction = 4. Pre-fork blocks keep transaction = 3 — that's correct, history isn't rewritten.   

⚠ PG_URI: stands for db connection string e.g. postgres://postgres:pass@localhost:5432/archive

                        ii. Ensure no missing blocks

  mina-missing-blocks-auditor --archive-uri "$PG_URI"; echo "exit=$?"

⚠ PG_URI: stands for db connection string e.g. postgres://postgres:pass@localhost:5432/archive


Find more detailed information in the docs and reach out in Discord if you experience any issues.

Step 3 – Post Hard fork Network Monitoring (day 3 – end of Stage 2)

Goals:

  • Monitor Mesa network after hard fork transition

Runbook:

  1. Block production starts approximately 2 hours after mainnet-based network halts
  2. Mesa Network is monitored

              a. Archive nodes have no gaps and show correct data (e.g. new coinbase, slot duration)

                        i. Ensure mesa blocks correctness (360 MINA for Coinbase)

                        ii. Ensure 90 seconds slot duration

                        iii. Ensure archive data consistency (no missing blocks , chain continuity)

 According to the trailblazer plan Archive/Rosetta testers will be split into 3 category regarding how fast they will join Mesa network after hardfork: 

                a) immediately mesa release is published, 

                b) post-HF, between 100-290 blocks

                c) post-HF, between 291~400 blocks


There is no difference in checks we will ask you to perform. Just be mindful, the later you join the network, the more blocks you will have to patch. 

See: https://docs.minaprotocol.com/node-operators/archive-node/backfilling-missing-blocks for more details

  # Coinbase: expect 360000000000 nanomina on post-fork blocks    
  psql "$PG_URI" <<'SQL'  
  SELECT b.height, ic.hash, ic.command_type, ic.fee    
  FROM blocks b  
  JOIN blocks_internal_commands bic ON bic.block_id=b.id    
  JOIN internal_commands ic ON ic.id=bic.internal_command_id
  WHERE ic.command_type='coinbase'   
    AND b.global_slot_since_hard_fork IS NOT NULL
    AND b.global_slot_since_hard_fork > 0    
  ORDER BY b.height DESC LIMIT 20;       
  SQL   

⚠ PG_URI: stands for db connection string e.g. postgres://postgres:pass@localhost:5432/archive

                         1. Slot duration equal to 90 seconds

  # Slot duration: timestamps between consecutive canonical blocks should step by ~90 * slots_delta seconds             

  psql "$PG_URI" <<'SQL'  
  WITH c AS (       
    SELECT height, global_slot_since_hard_fork AS slot, timestamp::bigint AS ts   
    FROM blocks WHERE chain_status='canonical' AND global_slot_since_hard_fork IS NOT NULL
    ORDER BY height DESC LIMIT 50  
  )  
  SELECT height, slot,   
         (ts - LAG(ts) OVER (ORDER BY height))/1000        AS delta_sec,
         (slot - LAG(slot) OVER (ORDER BY height))         AS delta_slots, 
         ((ts - LAG(ts) OVER (ORDER BY height))/1000)     
           / NULLIF(slot - LAG(slot) OVER (ORDER BY height),0) AS sec_per_slot  
  FROM c ORDER BY height;                                                                                                                                                                                  
  SQL  

  # sec_per_slot should be 90

 

⚠ PG_URI: stands for db connection string e.g. postgres://postgres:pass@localhost:5432/archive

                          iv. Ensure no missing blocks.

  mina-missing-blocks-auditor --archive-uri "$PG_URI"; echo "exit=$?"    

⚠ PG_URI: stands for db connection string e.g. postgres://postgres:pass@localhost:5432/archive

 

                          v. Ensure successful replayer run

# Replayer from the fork point onwards    
  mina-replayer \   
    --input-file post_fork_replayer_input.json \
    --archive-uri "$PG_URI" \     
    --output-file post_fork_replayer_output.json \  
    --checkpoint-interval 10000 --checkpoint-output-folder ./checkpoints-mesa \
    --log-level Info --log-json | tee replayer-mesa.log    
                                                            
# NOTE post_fork_replayer_input.json file is produced by berkeley replayer with options  --hard-fork-target mesa \
  --stop-slot-config-file "$STOP_SLOT_CONFIG" \
  --hard-fork-output-file post_fork_replayer_input.json \
Best way to do it is via docker (with assumption that stop slot config is stored at cwd )

docker run -v .:/workdir minaprocotol/mina-archive:{BERKELEY_VERION} mina-replayer \
  --archive-uri "$PG_CONN" \
  --input-file "$LAST_CHECKPOINT_FILE" \
  --hard-fork-target mesa \
  --stop-slot-config-file "$STOP_SLOT_CONFIG" \
  --hard-fork-output-file post_fork_replayer_input.json \
  --log-json \
  --log-level spam

⚠ PG_URI: stands for db connection string e.g. postgres://postgres:pass@localhost:5432/archive

              b. Rosetta

                     1. Ensure you are connected to correct network

# ROSETTA_URL env var point to base rosetta url (e.g. http://localhost:5000)

curl -s -X POST $ROSETTA_URL/network/list -H 'Content-Type: application/json' -d '{}' | jq .             
  
# Expect: { "network_identifiers":[{"blockchain":"mina","network":"devnet"}] }  
                                                                                 
curl -s -X POST $ROSETTA_URL/network/status -H 'Content-Type: application/json' \   
    -d "{\"network_identifier\":{\"blockchain\":\"mina\",\"network\":\"$MINA_NETWORK\"}}" | jq '.current_block_identifier, .genesis_block_identifier'    


⚠ ROSETTA_URL:  Should point to URL of your rosetta instance. E.g. http://localhost:3087

                     2. You can query transactions and blocks

# Get network id

NID=$("curl -s -X POST $ROSETTA_URL/network/status -H 'Content-Type: application/json' \    
    -d "{\"network_identifier\":{\"blockchain\":\"mina\",\"network\":\"testnet\"}}")    
 
         # Latest block

curl -s -X POST $ROSETTA_URL/block -H 'Content-Type: application/json' \  
    -d "{\"network_identifier\":$NID,\"block_identifier\":{}}" | jq '.block.block_identifier, .block.transactions | length'

 # Block by height

curl -s -X POST $ROSETTA_URL/block -H 'Content-Type: application/json' \                                                                                                                                 
    -d "{\"network_identifier\":$NID,\"block_identifier\":{\"index\":100}}" | jq '.block.block_identifier'     

    # Specific tx in a block           
curl -s -X POST $ROSETTA_URL/block/transaction -H 'Content-Type: application/json' \ 
    -d "{\"network_identifier\":$NID,\"block_identifier\":{\"index\":100,\"hash\":\"<state_hash>\"},\"transaction_identifier\":{\"hash\":\"<tx_hash>\"}}" | jq .

⚠ ROSETTA_URL:  Should point to URL of your rosetta instance. E.g. http://localhost:3087

Find more detailed information in the docs and reach out in Discord if you experience any issues.

 

About Mina Protocol

Mina is the world’s lightest blockchain, powered by participants. Rather than apply brute computing force, Mina uses advanced cryptography and recursive zk-SNARKs to design an entire blockchain that is about 22kb, the size of a couple of tweets. It is the first layer-1 to enable efficient implementation and easy programmability of zero knowledge smart contracts (zkApps). With its unique privacy features and ability to connect to any website, Mina is building a private gateway between the real world and crypto—and the secure, democratic future we all deserve.

More from our Blog

SEE ALL POSTS
Community / 2026-06-18 / o1Labs
Additional Mesa-Mesa Autonode HF (Appendix)
As validation continues ahead of Mina's Mainnet Mesa Upgrade, the Trailblazers Program will run an additional hard fork this weekend (Friday 19th to Sunday 21st of June) to finalize outstanding fixes and validate Automode functionality.
Read more
Community / 2026-05-28 / o1Labs
Launching Mesa Trail Mina Nodes
Read more
Community / 2026-05-28 / o1Labs
Emergency Hardfork Test Details (APPENDIX)
Read more
Community, Ecosystem Update / 2026-05-13 / o1Labs
Wizard Battle: The first PvP game on Mina Mainnet!
Read more

About the Tech

AboutTechCta

Mina uses advanced cryptography and recursive zk-SNARKs to deliver true decentralization at scale.

Get Started

GetStartedCta

Getting started with ZK on Mina is simple.

Cookie Consent with Real Cookie Banner