> For the complete documentation index, see [llms.txt](https://canopy-network.gitbook.io/docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://canopy-network.gitbook.io/docs/app-builder/chain-quickstart.md).

# Chain Quickstart

## Chain Quickstart

This tutorial gets a local single-node Canopy chain running, connects the default Go plugin, and walks you through your first transaction. Plan for about 15 minutes.

At the end you will have:

* A running chain on your local machine
* A funded account in the keystore
* A confirmed send transaction on-chain

***

### **Step 1: Clone and Build**

Clone the Canopy repository, check out the latest stable tag, and build the node binary.

```shell
git clone https://github.com/canopy-network/canopy.git
cd canopy
git checkout $(git describe --tags --abbrev=0)
make build/canopy
```

This compiles the `canopy` binary and installs it to `~/go/bin/canopy`. Depending on your machine it takes 30–90 seconds. You should see output ending with something like:

```
go build -o ~/go/bin/canopy ./cmd/main/...
```

Verify the binary is reachable:

```shell
canopy version
```

If you get `command not found`, make sure `~/go/bin` is on your `PATH` (see Prerequisites).

***

### **Step 2: Build the Go Plugin**

The Go plugin template lives inside the same repo. Build it from the `plugin/go` directory.

```shell
cd plugin/go
make build
```

This produces a `go-plugin` binary in `plugin/go/`. Once `canopy start` is configured to use the Go plugin, it handles launching this binary automatically via `pluginctl.sh`.

***

### **Step 3: Generate the Default Config**

Run the node once to generate the default configuration files, then stop it immediately.

```shell
canopy start
# Wait a few seconds for config to be written, then press Ctrl+C
```

On first run, the node will prompt you for two things before starting:

```
Enter password for your new private key (leave blank for no password):
Enter a nickname for this key (leave blank for "validator"):
```

For local development, press Enter twice to use no password and accept the default nickname `"validator"`. This creates an encrypted keystore entry for your validator's signing key. If you set a password, you'll need it whenever you restart the node.

This creates `~/.canopy/` with the following files:

```
~/.canopy/
├── config.json       # Node configuration
├── genesis.json      # Initial chain state
├── private_key.json  # Validator signing key (auto-generated)
└── keystore/         # Encrypted key storage
```

***

### **Step 4: Configure the Plugin**

Open `~/.canopy/config.json` in your editor. Find the `"plugin"` field (it will be an empty string by default) and set it to `"go"`:

```json
{
  "plugin": "go",
  ...
}
```

Now start the node:

```shell
canopy start
```

When `"plugin": "go"` is set, `canopy start` automatically calls `pluginctl.sh` to launch and manage the plugin process — you don't need to start it separately. You can also invoke `pluginctl.sh` directly (it supports `start`, `stop`, `restart`, and `status`), but letting `canopy start` handle the lifecycle is the standard approach and avoids timing issues.

Watch the output for a line like this confirming the plugin connected:

```
plugin connected: go_plugin_contract (id=1, version=1)
```

If you see connection errors on startup, don't worry — this is normal. The plugin and node race to start, and they will connect within a few seconds.

To monitor plugin logs separately:

```shell
tail -f /tmp/plugin/go-plugin.log
```

Leave the node running and open a new terminal for the remaining steps.

***

### **Step 5: Check Your Validator Account**

When the node first started, it generated a validator key and funded it in genesis. Query the keystore to find your address:

```shell
canopy admin ks
```

Expected output (addresses will differ):

```json
{
  "keys": [
    {
      "address": "dfd3c8dff19da7682f7fe5fde062c813b55c9eee",
      "nickname": "validator",
      "isValidator": true
    }
  ]
}
```

Copy your validator address. Now check its balance:

```shell
canopy query account <your-address>
```

Expected output:

```json
{
  "address": "dfd3c8dff19da7682f7fe5fde062c813b55c9eee",
  "amount": 1000000000000,
  "stakedAmount": 1000000000000
}
```

The `amount` field is the liquid balance in the chain's smallest denomination. The genesis account is pre-funded so you have tokens to work with immediately.

***

### **Step 6: Create a Second Account**

Generate a new keypair to use as a recipient:

```shell
canopy admin ks-new-key --nickname alice
```

Expected output:

```json
{
  "address": "eed6c9dff19da7682f7fe5fde062c813b42c7abc",
  "nickname": "alice"
}
```

Verify the account exists on-chain (it will have a zero balance until it receives funds):

```shell
canopy query account eed6c9dff19da7682f7fe5fde062c813b42c7abc
# Expected: empty response or zero balance — this is correct
```

***

### **Step 7: Send a Transaction**

Send tokens from your validator account to `alice`. Amounts are in the chain's smallest denomination (think of it like sending in microunits).

```shell
canopy admin tx-send \
  <your-validator-address> \
  eed6c9dff19da7682f7fe5fde062c813b42c7abc \
  10000000
```

Using nicknames also works:

```shell
canopy admin tx-send validator alice 10000000
```

Expected output:

```json
{
  "txHash": "a1b2c3d4e5f6...",
  "result": "submitted to mempool"
}
```

The transaction is now in the mempool. It will be included in the next block, which takes up to \~24 seconds (the default block time).

***

### **Step 8: Verify the Result**

Wait one block (about 24 seconds), then query `alice`'s account:

```shell
canopy query account eed6c9dff19da7682f7fe5fde062c813b42c7abc
```

Expected output:

```json
{
  "address": "eed6c9dff19da7682f7fe5fde062c813b42c7abc",
  "amount": 10000000,
  "stakedAmount": 0
}
```

You can also look up the transaction directly by hash:

```shell
canopy query tx <txHash>
```

Expected output:

```json
{
  "hash": "a1b2c3d4e5f6...",
  "height": 4,
  "sender": "dfd3c8dff19da7682f7fe5fde062c813b55c9eee",
  "recipient": "eed6c9dff19da7682f7fe5fde062c813b42c7abc",
  "amount": 10000000,
  "fee": 10000,
  "result": "ok"
}
```

And confirm the current chain height is advancing:

```shell
canopy query height
```

```json
{ "height": 5 }
```

If the height is incrementing, your chain is producing blocks and your plugin is processing transactions correctly.

***

### **Alternative: Docker**

If you prefer not to manage the Go toolchain locally, you can run the same setup in a container. From the repo root:

```shell
make docker/plugin PLUGIN=go
```

Then run the container with the RPC ports exposed:

```shell
docker run -p 50002:50002 -p 50003:50003 \
  -v ~/.canopy:/root/.canopy \
  canopy-go
```

The public RPC (port 50002) and admin RPC (port 50003) are accessible at `localhost` as usual. All the `canopy query` and `canopy admin` commands work the same way against these ports.

***

### **What Just Happened**

Here's a summary of what ran under the hood:

1. **Your plugin started** and connected to the Canopy FSM over a Unix socket.
2. **The node started producing blocks** using NestBFT consensus with a single-validator committee.
3. **When you ran `tx-send`**, the admin RPC on port 50003 built and signed a `MessageSend` transaction and posted it to port 50002.
4. **`CheckTx` ran** on your plugin, validating the addresses and fee.
5. **The transaction entered the mempool** and was included in the next block.
6. **`DeliverTx` ran** on your plugin, updating the sender and recipient balances in the key-value store.
7. **The query** read the new balance from state and returned it.

The default plugin only supports the built-in `send` transaction type. In the next section you'll build your own custom transaction type from scratch.

***

### **Common Issues**

**`canopy: command not found`** — `~/go/bin` is not on your `PATH`. Add `export PATH="$PATH:$HOME/go/bin"` to your shell profile and reload it.

**Plugin keeps failing to connect** — Confirm that `"plugin": "go"` is set in `~/.canopy/config.json` and that you ran `make build` inside `plugin/go` before starting the node. Check `/tmp/plugin/go-plugin.log` for more detail on what the plugin process itself is doing.

**Transaction not showing up after one block** — Block time defaults to \~24 seconds. If the transaction still hasn't landed after 60 seconds, check `canopy query pending` to see if it's stuck in the mempool, and check `/tmp/plugin/go-plugin.log` for plugin errors.

**`insufficient fee` error** — The default minimum fee is set in genesis. Pass `--fee 10000` explicitly to override: `canopy admin tx-send validator alice 10000000 --fee 10000`.

**Balance shows zero after send** — You may be querying before the block has been produced. Wait the full block time and query again.

***

**Next:** [Build a Basic App](/docs/app-builder/build-a-basic-app.md)


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://canopy-network.gitbook.io/docs/app-builder/chain-quickstart.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
