Skip to main content
note

A new version of Mina Docs is coming soon! This page will be rewritten.

Archive Node

Mina nodes are succinct by default, meaning they don't need to maintain historical information about the network, block, or transactions. For some usecases, it is useful to maintain this historical data, which you can do by running an Archive Node.

An Archive Node is just a regular mina daemon that is connected to a running archive process. The daemon will regularly send blockchain data to the archive process, which will store it in a Postgres database.

Running an archive node therefore requires some knowledge of managing a Postgres database instance. In this section, we'll set up a database, run the Archive Node, connect it to a daemon, and try some queries on the data. Let's get started by installing what we need.

Installation

  1. Install the latest version of mina. If you haven't upgraded to the latest version of the daemon, head back to the docs to get the latest version. You can run mina -help to check if the installation succeeded.

  2. Install Postgres.

  3. Install the archive node package.

    • Ubuntu/Debian:

      sudo apt-get install mina-archive=1.3.0-9b0369c
    • Docker:

      minaprotocol/mina-archive:1.3.0-9b0369c-bullseye

Setup

Below are some basic instructions on how to set up everything required to get an archive node running locally. These will be slightly different if you're connecting to a cloud instance of postgres, if your deployment uses docker, or if you want to run these processes on different machines.

note

Note: Some of these instructions may depend on how your operating system installs postgres (and assume that it is installed in the first place).

  1. Start a local postgres server. This will just run it in the foreground for testing, you will likely want to run it in the background or use your OS's service manager (like systemd) to run it for you. Alternatively, you may use a postgres service hosted by a cloud provider.
postgres -p 5432 -D /usr/local/var/postgres

For macOS, run brew services start postgres to start a local postgres server.

  1. Create database (here called archive) on server and load the schema into it. This will only need to be done the first time the archive node is set up.
createdb -h localhost -p 5432 -e archive

psql -h localhost -p 5432 -d archive -f <(curl -Ls https://raw.githubusercontent.com/MinaProtocol/mina/master/src/app/archive/create_schema.sql)
  1. Start archive process on port 3086, connecting to the postgres database we started on port 5432 in step 1.
mina-archive run \
--postgres-uri postgres://localhost:5432/archive \
--server-port 3086
  1. Start the daemon, connecting it to the archive process that we just started on port 3086. If you want to connect to an archive process on another machine, you can specify a hostname as well, like localhost:3086.
mina daemon \
.....
--archive-address 3086\

Upgrading/Repairing the Archive Data

Due to a bug in the originally released archive node version 1.1.5, some early transactions may not be represented properly in your database. See here for complete instructions on migrating your archive database.

Using the Archive Node

Now that we've got the archive node running, let's take a look at the tables in the database.

To list the tables in the database, you can run the \dt command, in psql. View the full schema of the tables here.

Below are some 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

There are two join tables in the archive database, which links 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

Try a query

Now that we've taken a look at the structure of the data, let's try a query.

Example 1: Find all blocks that have been 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 you’ve 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;