Running Mina with Docker
Since writing this post, Coda has rebranded to Mina Protocol. I’ve left the article in its original form but all references to Coda are equivalent to Mina.
Docker provides one of the simplest ways of getting a Coda node up and running while providing the benefits of container isolation. It also resolves issues around dependencies on unsupported systems and allows specifying restart policies should the daemon crash.
It is important to use the correct image for each testnet release. The tags for all releases are available on DockerHub. For testnet 3.2b this tag is 0.0.12-beta-feature-bump-genesis-timestamp-3e9b174
. This image is updated for each testnet, so the image used in the below commands should be updated accordingly.
At its simplest, we can start a Coda node with the following command. We’ll build upon this basic command for other Coda specific functions such as block production and SNARK workers.
$ docker run -d --name coda \
-p 8302:8302 \
-p 8303:8303 \
--restart always \
codaprotocol/coda-daemon:0.0.16-beta7 daemon \
-peer <PEER_1>
In the above command, you should replace <PEER_1>
and <PEER_2>
with the correct peer addresses that are made available.
The command will create a container named coda
and output a container id, with the container running in the background (due to the -d
or --detached
option). The --restart always
option means that if the container exits, it will automatically restart. There are two published ports (8302, 8303) to allow communication on the peer-to-peer network. To view the running container's status, run docker ps
that should display output similar to the below. Checking the status column, it will indicate any potential issues, such as the container crash-looping.
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
ae9f09595a4f codaprotocol/coda-daemon:0.0.12-beta-feature-bump-genesis-timestamp-3e9b174 "/usr/bin/dumb-init …" 25 hours ago Up 25 hours 0.0.0.0:8302-8303->8302-8303/tcp coda
To view the logs of the container, you can tail the log output using the command:
$ docker logs --follow coda
To interact with the Coda daemon, you can exec
into the container to run the available commands. For example, running docker exec -it coda bash
will open a terminal inside the container from where you can run any available coda
commands, such as coda client status
.
Alternatively, you can run from the command line non-interactively, e.g. docker exec coda coda client status
. The format of this command is docker exec container_name <COMMAND TO RUN>
.
Coda daemon status
-----------------------------------
Global number of accounts: 10089
Block height: 4969
Max observed block length: 4969
Local uptime: 6d1h18m32s
...
Running a block producer
As a next step, let’s run a block producer. We’ll remove the current instance via docker rm -f coda
to remove the running container and avoid container name and published port conflicts. To run a block producer, you will need the private key and corresponding password for the key that you wish to stake with.
While this private key may be located anywhere on your host system in the following example, the private key (generated via the Coda keygen tool) is in a subdirectory keys
and named my-wallet
. This key will be bind mounted into the container at /root/keys
. We also pass an environment variable of CODA_PRIVKEY_PASS
to set the password for the key non-interactively.
Ensure you are running the following command from the directory that contains the keys
subdirectory or adjust the bind mount accordingly below, which needs to be an absolute path.
$ docker run -d --name coda \
-e "CODA_PRIVKEY_PASS=<PASSWORD>" \
--mount type=bind,source="$(pwd)"/keys,target=/root/keys \
-p 8302:8302 \
-p 8303:8303 \
--restart always \
codaprotocol/coda-daemon:0.0.16-beta7 daemon \
-block-producer-key /root/keys/my-wallet \
-peer <PEER_1>
Once again, you will be returned a container id, and you can follow the logs to identify any potential issues. The following command should indicate a block producer is running with your public key:
$ docker exec coda coda client status | grep "Block producers"
Block producers running: 1 (4vsRCVGPNFDmHvuCctawApbyUg8J6iWzdHvJ2bNP8AL1GtMeaLwC6P8ZNTavKmAD4mMGbDq8H6DYramtiQP5fcf5xhdqAfYibt7Am9syUUU91oSf7HhLKrA26RPutsoyQSmZiMjPZoe1vDXW)
Running a SNARK worker
Another advantage of running the Coda daemon in Docker is limiting the available resources to the container. These resource constraints are of particular use to SNARK workers that will, by default, use all available resources. By default, a container has no resource constraints. However, you can set limits to, for example, the memory available and the number of cpus to use via the --memory
and --cpus
options.
To run a SNARK worker in the same container you can add the following option to the previous
docker run
command :-run-snark-worker <PUBLIC_KEY>
It is not generally recommended to run a SNARK worker and a block producer on the same machine as it can affect block production. While workarounds exist to disable the SNARK worker at the time of block production, you could alternatively run multiple containers on a machine (adjusting published ports as necessary) with applicable resource constraints.
The following example limits the container running a SNARK worker to 4 CPUs and 8GB of RAM. To avoid port conflicts with the container running the block producer we have specified-external-port
to use an unused port.
$ docker run -d --name coda \
-p 8305:8305 \
--memory 8g \
--cpus 4 \
--restart always \
codaprotocol/coda-daemon:0.0.16-beta7 daemon \
-run-snark-worker <PUBLIC_KEY> \
-snark-worker-fee 0.25 \
-work-selection seq \
-peer <PEER_1> \
-external-port 8305
Accessing the GraphQL API
The GraphQL API is available to interact with the Coda daemon. You can read more about the API in this article.
By default, the GraphQL API is bound to localhost
. To access it outside of the container, you will need to pass the -insecure-rest-server
option allowing the API to listen on all interfaces and then publish this port outside of the container. Crucially, if you do this, you must block the port (3085
by default) from external users via a firewall on the host, as the API is unauthenticated, and anyone with access could gain access to your wallet.
$ docker run -d --name coda \
-e "CODA_PRIVKEY_PASS=xxxxxx" \
--mount type=bind,source="$(pwd)"/keys,target=/root/keys \
-p 8302:8302 \
-p 8303:8303 \
-p 3085:3085 \
--restart always \
codaprotocol/coda-daemon:0.0.16-beta7 daemon \
-insecure-rest-server \
-peer <PEER_1>
Once this is running, on the host where Docker is running, visit localhost:3085/graphql
. If you are using a VM, you can use SSH port forwarding to forward port 3085 on your development machine to the remote machine, e.g., ssh -L3085:127.0.0.1:3085 user@remotehost
.
Additional options
There are many other options available to customize the running daemon, and you should consult the documentation. You can optionally add these options to the docker command, such as -coinbase-receiver
that will direct any coinbase payments to an address other than the block producer key, such as to a cold storage wallet.