Playing in the Mina Sandbox
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.
Before we begin
- 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.
Start the sandbox node
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
CLI
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.
GraphQL API
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.
Tokens
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
Create Tokens
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
}
}
}
}
Get the token id
Once the transaction has been included in a block, we need to know the token ID
for 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 ID
is 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 ID
with the first token created being 2
.
Mint tokens
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 ID
of 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.
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 sendercoda 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)
...
Creating token accounts
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 ID
of 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
}
}
}
Send tokens
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
Examples
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.
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.