Skip to main content

Archive Node

Mina nodes are succinct by default, so they don't need to maintain historical information about the network, block, or transactions.

For some use cases, it is useful to maintain this historical data on an archive node.

tip

A zkApp can retrieve events and actions from one or more Mina archive nodes. If your smart contract needs to fetch events and actions from an archive node, see How to Fetch Events and Actions.

An archive node is a regular mina daemon that is connected to a running archive process.

The daemon regularly sends blockchain data to the archive process that stores it in a PostgreSQL database.

Running an archive node requires some knowledge of managing a PostgreSQL database instance. You must set up a database, run the archive node, connect it to a daemon, and run queries on the data.

Install Mina, PostgreSQL, and the archive node package

  1. Install the latest version of Mina.

    You must upgrade to the latest version of the daemon. Follow the steps in Getting Started.

  2. Download and install PostgreSQL.

  3. Install the archive node package.

    • Ubuntu/Debian:

      sudo apt-get install mina-archive=1.4.0-c980ba8
    • Docker:

      minaprotocol/mina-archive:1.4.0-c980ba8-bullseye

Set up the archive node

These steps might be different for your operating system, if you're connecting to a cloud instance of PostgreSQL, if your deployment uses Docker, or if you want to run these processes on different machines.

For production, run the archive database in the background, use your operating system service manager (like systemd) to run it for you, or use a postgres service hosted by a cloud provider.

To run a local archive node to run it in the foreground for testing:

  1. Start a local postgres server and connect to port 5432:

    postgres -p 5432 -D /usr/local/var/postgres

    For macOS:

    brew services start postgres
  2. Create a local postgres database called archive:

    createdb -h localhost -p 5432 -e archive
  3. Load the mina archive schema into the archive database:

    psql -h localhost -p 5432 -d archive -f <(curl -Ls https://raw.githubusercontent.com/MinaProtocol/mina/master/src/app/archive/create_schema.sql)
  4. Start the archive process on port 3086 and connect to the postgres database that runs on port 5432:

    mina-archive run \
    --postgres-uri postgres://localhost:5432/archive \
    --server-port 3086
  5. Start the mina daemon and connect it to the archive process that you started on port 3086:

    mina daemon \
    .....
    --archive-address 3086\

    To connect to an archive process on another machine, specify a hostname with localhost:3086.

Set up the archive node using Docker

To get started with installing and running the archive node using Docker, follow the steps below.

  1. Install Docker on your machine. For more information, see Docker.

  2. Pull the archive node image from Docker Hub.

    docker pull minaprotocol/mina-archive:1.3.0-9b0369c-bullseye
  3. Pull and install the postgres image from Docker Hub.

    docker pull postgres
  4. Start the postgres container and expose it's networking to other containers.

    docker run --name postgres -p 5432:5432 -e POSTGRES_PASSWORD=postgres -d postgres
  5. Create a local postgres database called archive.

    docker exec -it postgres createdb -U postgres archive
  6. Load the mina archive schema into the archive database.

    curl -Ls https://raw.githubusercontent.com/MinaProtocol/mina/master/src/app/archive/create_schema.sql | docker exec -i postgres psql -U postgres -d archive
  7. Create a local directory to store the archive node data.

    mkdir -p /tmp/archive
  8. Start the archive node.

    docker run \
    --name archive \
    -p 3086:3086 \
    -v /tmp/archive:/data \
    minaprotocol/mina-archive:1.4.0-c980ba8-bullseye \
    mina-archive run \
    --postgres-uri postgres://postgres:postgres@postgres:5432/archive \
    --server-port 3086

  9. Start the mina daemon and connect it to the archive process that you started on port 3086:

    mina daemon \
    .....
    --archive-address 3086\

Set up the archive node using Docker Compose

Docker Compose is a tool for defining and running multi-container Docker applications. With Compose, you use a YAML file to configure your application's services. Then, with a single command, you create and start all the services from your configuration.

To run the archive node using Docker Compose:

  1. Install Docker on your machine. For more information, see Docker.

  2. Install Docker Compose on your machine. For more information, see Docker Compose.

  3. Pull the archive node image from Docker Hub.

    docker pull minaprotocol/mina-archive:1.3.0-9b0369c-bullseye
  4. Pull and install the postgres image from Docker Hub.

     docker pull postgres
  5. Create a local directory to store the archive node data.

    mkdir -p /tmp/archive
  6. Create a docker-compose.yml file with the following contents:

    version: '3.8'
    services:
    postgres:
    image: postgres
    environment:
    POSTGRES_PASSWORD: postgres
    volumes:
    - './postgres-data:/var/lib/postgresql/data'
    ports:
    - '5432:5432'
    archive:
    image: 'minaprotocol/mina-archive:1.4.0-c980ba8-bullseye'
    command: >-
    mina-archive run --postgres-uri
    postgres://postgres:postgres@postgres:5432/archive --server-port 3086
    volumes:
    - '/tmp/archive:/data'
    ports:
    - '3086:3086'
    depends_on:
    - postgres
  7. Start the archive node.

    # If you are running Docker Compose V1:
    docker-compose up

    # If you are running Docker Compose V2:
    docker compose up
  8. Start the mina daemon and connect it to the archive process that you started on port 3086:

    mina daemon \
    .....
    --archive-address 3086\

Using the Archive Node

Take a look at the tables in the database.

To list the tables, run the \dt command in psql.

Review the full schema at /archive/create_schema.sql.

Notable fields in each table:

Table 1: user_commands

This table keeps track of transactions made on the network.

...
user_command_type Type of transaction being made
Possible values: `'payment', 'delegation'
To see a specific type of transaction, i.e. payments or creating a token, specify this field in your queries.
source_id public key of the sender
receiver_id public key of the receiver
amount amount being sent from the sender to the receiver
token ID of a token **If you are querying for different type of token transactions, specify this field.**

Table 2: internal_commands

This table keeps track of rewards earned from SNARK work or block producing.

...
internal_command_type represents whether the command is a `fee_transfer` from SNARK work or a `coinbase` reward from block producing.
Use this field for information about block rewards and SNARK rewards (there is also an extra fee_transfer added to support sending all the transaction fees summed together to the block_creator)
receiver_id public key ID of the receiver
fee amount being sent from the protocol to the receiver
token ID of a token **If you are querying for different type of token transactions, specify this field.**

Table 3: blocks

...
id
parent_id ID of the previous block in the blockchain
Use this field for information about block rewards and SNARK rewards (there is also an extra fee_transfer added to support sending all the transaction fees summed together to the block_creator)
creator_id public key of the block creator

Join tables

Two join tables in the archive database link blocks to transactions.

By linking the block table and command tables, these tables allow you to identify specific transactions within blocks.

Join table 1: blocks_user_commands

...
block_id ID of the block containing the user command
user_command_id ID of the user command
sequence_no 0-based order of the user command among the block transactions

Join table 2: blocks_internal_commands

...
block_id ID of the block containing the internal command
internal_command_id ID of the internal command
sequence_no 0-based order of the internal command among the block transactions
secondary_sequence_no 0-based order of a fee transfer within a coinbase internal command

Query the database

Now that you know the structure of the data, try a query.

Example 1: Find all blocks that were created by your public key:

SELECT *
FROM blocks AS b
INNER JOIN public_keys AS pk1 ON b.creator_id = pk1.id
WHERE value = 'MY_PK'

Example 2: Find all payments received by your public key:

SELECT *
FROM user_commands AS uc
JOIN blocks_user_commands AS buc ON uc.id = buc.user_command_id
JOIN public_keys AS pk ON uc.receiver_id = pk.id
WHERE value = 'MY_PK'
AND type = 'payment'

Example 3: Find the block at height 12 on the canonical chain:

WITH RECURSIVE chain AS (
(SELECT ... FROM blocks b WHERE height = (select MAX(height) from blocks)
ORDER BY timestamp ASC
LIMIT 1)

UNION ALL

SELECT ... FROM blocks b
INNER JOIN chain
ON b.id = chain.parent_id AND chain.id <> chain.parent_id
) SELECT ..., pk.value as creator FROM chain c
INNER JOIN public_keys pk
ON pk.id = c.creator_id
WHERE c.height = 12

Example 3: List the counts of blocks created by each public key and sort them in descending order"

SELECT p.value, COUNT(*) FROM blocks
INNER JOIN public_keys AS p ON creator_id = ip.id
GROUP BY p.value
ORDER BY count DESC;

Example 4: List the counts of applied payments created by each public key and sort them in descending order:

SELECT p.value, COUNT(*) FROM user_commands
INNER JOIN public_keys AS p ON source_id = p.id
WHERE status = 'applied'
AND type = 'payment'
GROUP BY p.value ORDER BY count DESC;