Running Coda with Docker

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.12-beta-feature-bump-genesis-timestamp-3e9b174 daemon \
-peer <PEER_1> \
-peer <PEER_2>

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.12-beta-feature-bump-genesis-timestamp-3e9b174 daemon \
-block-producer-key /root/keys/my-wallet \
-peer <PEER_1> \
-peer <PEER_2>

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.

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.

$ docker run -d --name coda \
-p 8305:8305 \
--memory 8g \
--cpus 4 \
--restart always \
codaprotocol/coda-daemon:0.0.12-beta-feature-bump-genesis-timestamp-3e9b174 daemon \
-run-snark-worker <PUBLIC_KEY> \
-snark-worker-fee 0.25 \
-work-selection seq \
-peer <PEER_1> \
-peer <PEER_2> \
-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.12-beta-feature-bump-genesis-timestamp-3e9b174 daemon \
-insecure-rest-server \
-peer <PEER_1> \
-peer <PEER_2>

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.

Coda GraphQL API

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.