Playing in the Mina Sandbox

Image by joanshannon from Pixabay

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.

The Coda sandbox node enables creating a single-node private network that you can use to test running a Coda node in a predictable environment. The 3.3 release of the sandbox node includes the new Pickles SNARK and support for tokens.

For a step-by-step guide to completing the Coda Pickles Sandbox challenges see this guide by community member Ducca

The sandbox node contains all of the network’s funds on a single private key, and by default, runs a SNARK worker and block producer so you can test all aspects of node operation.

Additionally, for node operators, you can also easily transition from using the sandbox Docker container to running the Coda daemon via Docker, as outlined in this post.

  • The sandbox node is based on Docker, so you’ll need to install Docker.
  • The sandbox node is resource-intensive as it is running a SNARK worker in addition to a block producer and doing the work of the entire network. As a result, it is recommended to have a minimum of 4 cores and 16GB of RAM. Though if running for a short period of time, you can likely get away with less. If running Docker Desktop on Mac or Windows, you will likely want to adjust the resources allocated to Docker.
  • You can run the sandbox node on your local development machine or a VPS, so long as Docker is installed. It will currently only run on the x86 architecture, so no ARM devices for now (e.g., Raspberry Pi).
  • It is a very large image weighing in at over 4GB, which will need to be downloaded and extracted.

To run the sandbox node, execute the following command, which will create a container named coda, run in detached mode (-d), and expose the GraphQL port to the host machine on port 3085.

docker run \
--publish 3085:3085 \
-d \
--name coda \
codaprotocol/coda-demo:pickles-sandbox

The first time the command is run, it will attempt to download the coda-demo:pickles-sandbox image before starting, which it will only need to do once. Once this has been downloaded, the command will return the container image with the container running in the background. We can see the status of all containers with the command docker container ps.

To follow the logs in real-time run:

docker logs --follow coda

You should see an output that details the node booting up. Note that a GraphQL server has been started, and after a short while, it will start to produce blocks indicated by Producing block in 0 slots. You can exit from following the logs at any time with Ctrl+C.

$ docker logs --follow coda 
2020-09-07 14:53:08 UTC [Info] Coda daemon is booting up; built with commit "d7cd24cc280e181e5be8c666b1f9205e6637e149" on branch "release/0.0.15-beta"
2020-09-07 14:53:08 UTC [Info] Daemon will expire at "2024-12-10 14:00:00-07:00"
2020-09-07 14:53:08 UTC [Info] Booting may take several seconds, please wait
2020-09-07 14:53:08 UTC [Info] Initializing with runtime configuration $config
config: {
"ledger": {
"accounts": [
{
"pk": "B62qrPN5Y5yq8kGE3FbVKbGTdTAJNdtNtB5sNVpxyRwWGcDEhpMzc8g",
"balance": "66000"
}
]
}
}
...
2020-09-07 14:53:49 UTC [Info] Pausing block production while bootstrapping
2020-09-07 14:53:49 UTC [Info] Created GraphQL server at: http://localhost:3085/graphql
2020-09-07 14:53:49 UTC [Info] Daemon ready. Clients can now connect
...
2020-09-07 14:53:49 UTC [Info] Determining next slot to produce block
2020-09-07 14:53:49 UTC [Info] Checking VRF evaluations at epoch: 0, slot: 1
2020-09-07 14:53:49 UTC [Info] Producing block in 0 slots

To test all the functionality of the CLI, we will do so from within the Docker container. Enter the following command to access the container:

docker exec -it coda bash

This opens a bash prompt within the container. From here, we have access to any of the Coda CLI commands. For example, running coda client status provides an overview of the node status, and you should see the block height increasing as blocks will be produced approximately every 3 mins.

coda client status
Coda daemon status
-----------------------------------
Global number of accounts: 2
Block height: 5
...

There are many other commands to explore, including many of the new token commands, which are detailed later in this article.

As noted in the logs output, the sandbox node starts a GraphQL server so you can make use of the Coda GraphQL API. On the host where Docker is running, visit localhost:3085/graphql. If you are using a publicly available cloud instance, you should block port 3085 to external traffic; otherwise, it will be accessible to anyone via the hostname or IP. Once the firewall port is blocked, 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 and then access via localhost:3085/graphql. For more details on the GraphQL API and GraphiQL interface, refer to this article.

GraphQL query for block height
GraphQL query for block height

Tokens are an exciting new feature of this sandbox release. The functionality of tokens are currently limited, and you can simply create them and transfer between accounts. With the release of Snapps, tokens will gain more functionality and flexibility.

However, using the sandbox, we can run through the lifecycle of a token. Namely:

  • Create a token
  • Get the token id
  • Mint new tokens
  • Create token accounts
  • Send tokens between accounts

To create a token issue the following command, after first unlocking the account (the password is empty for the default account):

$ coda accounts unlock -public-key B62qrPN5Y5yq8kGE3FbVKbGTdTAJNdtNtB5sNVpxyRwWGcDEhpMzc8g$ coda client create-token -sender B62qrPN5Y5yq8kGE3FbVKbGTdTAJNdtNtB5sNVpxyRwWGcDEhpMzc8gDispatched create new token command with ID 2cUDm3QoJ1

At this point, you can see the transaction in the mempool via either the CLI or GraphQL:

coda advanced pooled-user-commands

Or via GraphQL:

query MyQuery {
pooledUserCommands {
... on UserCommandNewToken {
id
kind
from
to
fee
feeToken
feePayer {
publicKey
}
}
}
}

Once the transaction has been included in a block, we need to know the token IDfor future token operations. We can get this by querying the public key for available tokens IDs.

$ coda client get-tokens -public-key B62qrPN5Y5yq8kGE3FbVKbGTdTAJNdtNtB5sNVpxyRwWGcDEhpMzc8gAccounts are held for token IDs:
1 2

Or via GraphQL (note that you can also get much more information from this query, such as the balance of all available tokens):

query MyQuery {
accounts(publicKey: "B62qrPN5Y5yq8kGE3FbVKbGTdTAJNdtNtB5sNVpxyRwWGcDEhpMzc8g") {
token
}
}

The native token of Coda is 1, so our newly created token IDis 2. token IDs in Coda are integers and sequential, so in the sandbox where you are the only participant, you will always generate the next available token IDwith the first token created being 2.

Currently, we have a new token, but it has a balance of 0. We can see this with the following command:

$ coda client get-balance -token 2 -public-key B62qrPN5Y5yq8kGE3FbVKbGTdTAJNdtNtB5sNVpxyRwWGcDEhpMzc8gBalance: 0 tokens

To mint new tokens, we issue a mint-tokens command. By default, this will create the tokens in the account of the sender of the transaction. The following command mints 1000 tokens for the token IDof 2:

$ coda client mint-tokens -sender B62qrPN5Y5yq8kGE3FbVKbGTdTAJNdtNtB5sNVpxyRwWGcDEhpMzc8g -token 2 -amount 1000Dispatched create new token command with ID G8k9HJXpug4J4thR9me9Ft7CfHwAma7dN7xJyRSJvmuR7C2wmgXHyZP3NVjTbZr38YXNenZkDMf2PnxMsKs7x2qop8JEGjFyNGrJbur7csfc7i7pNTPzFaue8Ak1NgZXwYDsfrduZjshhr2QV9pD5Jx2JqsqPauxykrp5A6ekBoT5FHPPVTsdmdun8fbNjS8CQHPbuMHtvQ89SxdYfVjgkhgLT9vjtSS5ZszkccoYLmR5nxXecR6e2iFPdLY8z3wy2JETwYXGcxhiqvZcEPWeSceXShTFsaWRKdawuTFtXAt6cfQaPPGpwg6CY1WctYTA5135ewyd4xVMXX9qUG9BMfCfsBtczY5KaFeiLUP9pjH6FkLUtsKH2YevwPf1QvRMNruPozTZ

We can also mint tokens using the mintTokens mutation in GraphQL. Note that in the GraphQL API, all values are in nanocoda (there are 1 billion nanocoda in a Coda), whereas in the CLI, all values are in Coda.

Mint a token with the GraphQL API

Once that transaction is included in a block, we can see the balance using the CLI:

$ coda client get-balance -token 2 -public-key B62qrPN5Y5yq8kGE3FbVKbGTdTAJNdtNtB5sNVpxyRwWGcDEhpMzc8gBalance: 1000 tokens

Or via the GraphQL query:

query MyQuery {
account(publicKey: "B62qrPN5Y5yq8kGE3FbVKbGTdTAJNdtNtB5sNVpxyRwWGcDEhpMzc8g", token: "2") {
balance {
total
}
}
}

There are many other options available for this mint-tokens command, such as minting tokens directly to an alternative token account. See the -help of the command for all the details.

$ coda client mint-tokens -help
Mint more of a token owned by the command's sender
coda client mint-tokens=== flags ===-amount VALUE Number of new tokens to create
-sender KEY Public key from which you want to send the
transaction
-token TOKEN_ID The ID of the token to mint
[-fee FEE] Amount you are willing to pay to process
the transaction (default: 0.1) (minimum:
0.001)
...

Before an account can receive tokens, an account for that token needs to be created. When creating tokens, a token account is created automatically for the token owner. For all other accounts, we must explicitly create a token account.

As the sandbox node only has a single account, let’s start by creating a new one.

$ coda accounts create
Password for new account:
Again to confirm:
😄 Added new account!
Public key: B62qpq8sA8uef6T5htApSgjeNKLE2BUAeuRFHWvxCzbjca7SpkfSuZE

To create the token account (for a token IDof 2) issue the following command, replacing receiver with the account you just created:

coda client create-token-account -sender B62qrPN5Y5yq8kGE3FbVKbGTdTAJNdtNtB5sNVpxyRwWGcDEhpMzc8g -receiver B62qpq8sA8uef6T5htApSgjeNKLE2BUAeuRFHWvxCzbjca7SpkfSuZE -token 2

You can also perform this operation using the createTokenAccount mutation of the GraphQL API.

mutation MyMutation {
createTokenAccount(input: {fee: "1000000", receiver: "B62qpq8sA8uef6T5htApSgjeNKLE2BUAeuRFHWvxCzbjca7SpkfSuZE", token: "2", tokenOwner: "B62qrPN5Y5yq8kGE3FbVKbGTdTAJNdtNtB5sNVpxyRwWGcDEhpMzc8g"}) {
createNewTokenAccount {
kind
hash
id
}
}
}

Now that we have some tokens and token accounts, let’s finally send a token from one to another by issuing the following command:

coda client send-payment -sender B62qrPN5Y5yq8kGE3FbVKbGTdTAJNdtNtB5sNVpxyRwWGcDEhpMzc8g -receiver B62qpq8sA8uef6T5htApSgjeNKLE2BUAeuRFHWvxCzbjca7SpkfSuZE -token 2 -memo "First token tx" -amount 50

For some inspiration, I used the sandbox node to develop my block explorer to include full token support for the upcoming public testnet. On the token page, after running all the commands above, we can see all the generated transactions.

Enabling token support with the sandbox node

If you are looking for a challenge, why not:

  • Build a simple UI to output the result of the above queries.
  • Create some scripts using the CLI or GraphQL API for members to bootstrap their sandbox nodes, creating tokens, token accounts, and sending some sample transactions.

You can repurpose anything you build for the sandbox node for the next deployment of the testnet. If you haven’t already done so, sign up for the Genesis program and get ready for the next public testnet.

Technical writer, data wrangler and (former) full stack dev

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store