Tutorial · Divi Games

Run the Gamechain on Your Own Computer

Build divi-gamechain, start a chain of your own that follows Divi testnet, claim GOLD from your own faucet, replay the chain, stop and start it again. Every command below was run as written.

About 15 minutes · Checked 2026-10-21

1What you need

If you want to know why a node needs Divi at all, read What a Divi sidechain is first.

2Get the source

The repository is DiviDomains/divi-games on GitHub. On 2026-10-21 it is still private (an unauthenticated git clone gets a 404), so ask for access on games.divi.domains or clone it with an account that has been added. Once you have it:

git clone git@github.com:DiviDomains/divi-games.git
cd divi-games
ls
ARCHITECTURE.md  assets  bins  bots  Cargo.lock  Cargo.toml  content  crates  deploy  docs  scripts  site  tests  tools  web

The parts this page touches:

PathWhat it is
bins/divi-gamechain/The node: config, HTTP API, sequencer loop, Divi RPC client, anchor and bridge tasks, the house task.
bins/divi-games-site/The web site that fronts a node (play pages, explorer, courses). Not needed here.
crates/dg-core, dg-chainAddresses, signatures, transactions, blocks, the SQLite store and the sequencer.
crates/dg-system, dg-games, dg-market, dg-tdThe modules: tokens, faucet, HTLC, bridge, certificates, tic-tac-toe, blackjack, the market and tower defense.
web/sdk/divigames.js, web/vendor/The JavaScript SDK and the two noble crypto libraries it imports.
ARCHITECTURE.mdThe design document. Worth an hour.

3Build it

Build the node alone (the site binary and the WASM tower-defense crate are not needed):

cargo build --release -p divi-gamechain

The build for this page also added -p divi-games-site (the two binaries share almost every dependency) and compiled 230 crates in 1 min 36 s on a 32-core Linux box; expect several minutes on a laptop. The tail of that build log:

   Compiling divi-games-site v0.1.0 (…/divi-games/bins/divi-games-site)
   Compiling dg-chain v0.1.0 (…/divi-games/crates/dg-chain)
   Compiling divi-gamechain v0.1.0 (…/divi-games/bins/divi-gamechain)
    Finished `release` profile [optimized] target(s) in 1m 36s

The binary is target/release/divi-gamechain. Put it on your PATH or use the full path; the commands below assume it is on the path.

divi-gamechain --help
Divi Games side-chain node

Usage: divi-gamechain [OPTIONS] <COMMAND>

Commands:
  run     Serve the API and produce blocks
  keygen  Create the sequencer key if there is none, and print its address (never the key)
  info    Print the chain head
  replay  Re-execute every block from genesis and check it against the stored headers
  help    Print this message or the help of the given subcommand(s)

Options:
      --config <CONFIG>      TOML config file; every field is optional [env: DG_CONFIG=]
      --data-dir <DATA_DIR>  Overrides `data_dir` from the config file [env: DG_DATA_DIR=]
  -h, --help                 Print help
  -V, --version              Print version

4Make the sequencer key

Your node needs one Divi testnet key: it signs every block and the house's own game moves. keygen makes it inside the data directory and prints only the address. We keep everything for this node under one folder, ~/tut-i/run-the-gamechain/ on this page's machine.

mkdir -p ~/tut-i/run-the-gamechain && cd ~/tut-i/run-the-gamechain
divi-gamechain --data-dir data keygen
/home/bshuler/tut-i/run-the-gamechain/data/sequencer.key created: xxD8ohHuhAGjmxATudgBqfrhwbY6WJR7jM

Run it a second time and nothing changes: it is safe to put in a start script.

divi-gamechain --data-dir data keygen
/home/bshuler/tut-i/run-the-gamechain/data/sequencer.key exists: xxD8ohHuhAGjmxATudgBqfrhwbY6WJR7jM
ls -la data
drwx------ 2 bshuler bshuler 4096 Oct 21 19:55 .
-rw------- 1 bshuler bshuler   53 Oct 21 19:55 sequencer.key
The key file

data/ is created with mode 0700 and sequencer.key with 0600. It holds one WIF (a testnet one starts with c). Never cat it into a terminal, a log or a chat. The node refuses to start if the file is readable by other users (step 9), and it refuses a mainnet key outright.

5Write the config

The config is a TOML file and every field is optional: leave one out and its default applies. The file below lists every field with its default, except data_dir and listen, which we set for this node. Unknown fields are an error (deny_unknown_fields), which catches typos like blockms; you will see that error in step 9.

# gamechain.toml: every field with its default. Leave a line out and the default applies.
data_dir = "/home/bshuler/tut-i/run-the-gamechain/data"
listen = "127.0.0.1:53920"
block_ms = 2000
heartbeat_ms = 60000
divi_rpc = "https://services.divi.domains/api/testnet/rpc/"
divi_poll_ms = 30000
certificate_issuers = []

[anchor]
enabled = false
every = 300
fee_sat = 1000000
poll_ms = 5000

[bridge]
enabled = false
address = ""
confirmations = 6
poll_ms = 30000
lookback = 2000
FieldDefaultMeaning
data_dir$XDG_DATA_HOME/divi-gamechain, else ~/.local/share/divi-gamechainWhere chain.db, sequencer.key and house.secret live. --data-dir or DG_DATA_DIR overrides it.
listen127.0.0.1:7410HTTP address of the API. run --listen overrides it. Keep it on localhost and put nginx in front for the public.
block_ms2000Block interval while the mempool is not empty.
heartbeat_ms60000An empty block after this long without one.
divi_rpcpublic testnet RPCWhere checkpoints come from. Point it at your own divid -testnet if you run one.
divi_poll_ms30000How often to ask Divi for a new checkpoint (tip minus 6).
certificate_issuers[]Addresses allowed to issue certificates. Empty means the sequencer only.
[anchor]off, every 300, fee 1 000 000 sat, poll 5 sWrites DGCH anchors to Divi testnet. Needs testnet DIVI on the sequencer address. See Anchors and the tDIVI bridge.
[bridge]off, address "", 6 confirmations, poll 30 s, lookback 2000Mints TDIVI for deposits to address. Same tutorial.

The chain id, divi-games-testnet-1, is not configurable: it is part of genesis and goes into every signed transaction.

6Run it

Start the node in the background and keep its PID. The default log filter is divi_gamechain=info,tower_http=warn; set RUST_LOG to change it.

cd ~/tut-i/run-the-gamechain
nohup divi-gamechain --config gamechain.toml run --listen 127.0.0.1:53920 > node.log 2>&1 < /dev/null &
echo $! > node.pid

Within a few seconds the log shows the chain opening, the API coming up, the house task making its three opening moves, and the first Divi checkpoint arriving:

2026-10-21T19:55:49.025576Z  INFO divi_gamechain: chain opened chain=divi-games-testnet-1 sequencer=xxD8ohHuhAGjmxATudgBqfrhwbY6WJR7jM height=0
2026-10-21T19:55:49.026420Z  INFO divi_gamechain: serving listen=127.0.0.1:53920
2026-10-21T19:55:49.035510Z  INFO divi_gamechain::house: house action submitted kind="house_commit" pending=0
2026-10-21T19:55:49.036125Z  INFO divi_gamechain: block height=1 txs=1
2026-10-21T19:55:49.036895Z  INFO divi_gamechain::house: house action submitted kind="faucet" pending=0
2026-10-21T19:55:49.217545Z  INFO divi_gamechain: Divi checkpoint reachable height=359936
2026-10-21T19:55:51.028374Z  INFO divi_gamechain: block height=2 txs=1
2026-10-21T19:55:51.029568Z  INFO divi_gamechain::house: house action submitted kind="fund" pending=0
2026-10-21T19:55:53.028319Z  INFO divi_gamechain: block height=3 txs=1

Ask it who it is:

curl -s http://127.0.0.1:53920/v1/info
{"chain_id":"divi-games-testnet-1",
 "divi":{"hash":"e7848cc57438c6bab71aa721b1eb71b6c6e4df277984f79308ba75d7c7a86b69","height":359936},
 "divi_seen":{"hash":"e7848cc5…c7a86b69","height":359936},
 "head_hash":"8997f9183857e66b9cdf185d5244ab73bda00cf5833419d53a8220a8963da8ae",
 "height":3,"mempool":0,
 "modules":["backend","blackjack","bridge","certificate","htlc","market","system","tictactoe","towerdefense"],
 "network":"testnet",
 "sequencer":"xxD8ohHuhAGjmxATudgBqfrhwbY6WJR7jM",
 "time_ms":1792612553027,"tokens":["GOLD","TDIVI"]}

Same shape as the public chain at https://games.divi.domains/chain/v1/info, different sequencer, your own history. The other routes are /v1/blocks, /v1/blocks/{height}, /v1/tx/{txid}, /v1/account/{addr}, /v1/tokens, /v1/games/{game}, POST /v1/tx and the WebSocket /v1/ws.

7Claim GOLD from your own faucet

Now be a player. The SDK is web/sdk/divigames.js in the repo; it imports ../vendor/noble-hashes and ../vendor/noble-secp256k1 by relative path, so copy the whole web/ folder next to your script:

cp -r ~/divi-games/web ~/tut-i/run-the-gamechain/web

claim.mjs makes a player key the first time (saved to player.key, mode 0600, never printed), then sends a faucet action and waits for the receipt:

// claim.mjs: make a player key, claim 1000 GOLD from your own node's faucet, show the account.
import fs from 'node:fs';
import { Key, Chain } from './web/sdk/divigames.js';

const KEYFILE = 'player.key';                 // the player's WIF, mode 0600, never printed
let key;
if (fs.existsSync(KEYFILE)) {
  key = Key.fromWif(fs.readFileSync(KEYFILE, 'utf8'));
} else {
  key = Key.generate('testnet');
  fs.writeFileSync(KEYFILE, key.toWif() + '\n', { mode: 0o600 });
}
console.log('player  ', key.address);

const chain = new Chain('http://127.0.0.1:53920');
const info = await chain.info();
console.log('node    ', info.chain_id, 'height', info.height, 'sequencer', info.sequencer);

const txid = await chain.send(key, { type: 'faucet', token: 'GOLD' });
console.log('txid    ', txid);

const receipt = await chain.waitForReceipt(txid);
console.log('receipt ', JSON.stringify(receipt));

const account = await chain.account(key.address);
console.log('account ', JSON.stringify(account));
node claim.mjs
player   y1baNdNhw5ZkcVoCSTUCANM84E1mhw3cR9
node     divi-games-testnet-1 height 5 sequencer xxD8ohHuhAGjmxATudgBqfrhwbY6WJR7jM
txid     70b4d72e4ee1fe885e95f15a2746445a86ce736b09b491e738f6e7487b851e5e
receipt  {"error":null,"events":[{"data":{"amount":"100000","to":"y1baNdNhw5ZkcVoCSTUCANM84E1mhw3cR9","token":"GOLD"},"kind":"faucet"}],"height":6,"index":0,"ok":true,"txid":"70b4d72e…b851e5e"}
account  {"address":"y1baNdNhw5ZkcVoCSTUCANM84E1mhw3cR9","balances":{"GOLD":"100000"},"next_nonce":1,"nonce":1}

chain.send reads your next nonce, builds the body, signs it with a Divi signed message and POSTs it; waitForReceipt polls /v1/tx/<txid> every 500 ms (for up to 30 s) until the block that holds it is made. "100000" is 1000.00 GOLD. The node stores exactly what you signed:

curl -s http://127.0.0.1:53920/v1/tx/70b4d72e4ee1fe885e95f15a2746445a86ce736b09b491e738f6e7487b851e5e
{"body":"{\"v\":1,\"chain\":\"divi-games-testnet-1\",\"from\":\"y1baNdNhw5ZkcVoCSTUCANM84E1mhw3cR9\",\"nonce\":0,\"action\":{\"type\":\"faucet\",\"token\":\"GOLD\"}}",
 "receipt":{… "height":6,"index":0,"ok":true …},
 "sig":"H8L7sulqOcZlYT4tWfzx4apX2/YLJvfkvcbKuEaeqWnjW4RyXpueEtTfn1RneQZTqsBwrcYdrPR5HIaxWkf5+jQ="}
Run it again

The second run reuses player.key and the faucet says no: the cooldown is 1800 blocks per address. The transaction is still included, with "ok":false and an error, and it uses up nonce 1. That is how the chain treats every valid-but-failed action.

node claim.mjs
player   y1baNdNhw5ZkcVoCSTUCANM84E1mhw3cR9
node     divi-games-testnet-1 height 30 sequencer xxD8ohHuhAGjmxATudgBqfrhwbY6WJR7jM
txid     66cd0ac51de1d821c35f887505f86ed4e20d54f9bcbe32d01849155abd85b0fd
receipt  {"error":"conflict: faucet cooling down; next claim at height 1806","events":[],"height":31,"index":0,"ok":false,"txid":"66cd0ac5…85b0fd"}
account  {"address":"y1baNdNhw5ZkcVoCSTUCANM84E1mhw3cR9","balances":{"GOLD":"100000"},"next_nonce":2,"nonce":2}

8info and replay

Two subcommands open the data directory directly, without the API, and work whether the node is running or not. These were run right after the first faucet claim, at height 6.

divi-gamechain --config gamechain.toml info
chain     divi-games-testnet-1
sequencer xxD8ohHuhAGjmxATudgBqfrhwbY6WJR7jM
height    6
head      827a8052645732b484d0d7ae5c29551f01d2f43b79f8e2e2c04aea3e34124fdc
divi      359936 e7848cc57438c6bab71aa721b1eb71b6c6e4df277984f79308ba75d7c7a86b69
divi-gamechain --config gamechain.toml replay
ok: 7 blocks, 4 txs, 11 state keys, state root 872a6e779d5bb9c06fff0cd658f84431fe687860b9a1b33775e43d2d28adb77d

replay starts from genesis with an empty state, re-executes every transaction in every block in a fresh in-memory store, and compares each block's tx_root and state_root with the stored header. 7 blocks is genesis plus heights 1 to 6; the 4 transactions are the house's three and your faucet claim. The 11 state keys (select key from kv in chain.db) are two nonces, two GOLD balances (yours and the blackjack house's), two faucet cooldown stamps, the two token records, the issuer list, the house's blackjack state and the tower-defense week. If anything had been edited in chain.db by hand, this is where it would show.

9Stop, restart, and the errors you will meet

Stop it by PID. The node catches SIGINT or SIGTERM, logs stopped and exits; the port closes.

kill $(cat node.pid); sleep 2
tail -1 node.log
2026-10-21T19:58:31.307551Z  INFO divi_gamechain: stopped
ss -ltn | grep 53920 || echo 'port 53920 closed'
port 53920 closed

Everything the node knows is in data/: chain.db (SQLite in WAL mode, so you will also see chain.db-wal and chain.db-shm), sequencer.key and house.secret (the dealer's shuffle secret, also 0600). Back up the folder, not the database alone.

Errors, each one provoked on purpose

Key readable by others. The node checks the mode of sequencer.key before it reads it:

chmod 644 data/sequencer.key
divi-gamechain --config gamechain.toml run
Error: /home/bshuler/tut-i/run-the-gamechain/data/sequencer.key is readable by other users (mode 644); chmod 600 it
chmod 600 data/sequencer.key

A mainnet key. A WIF for a mainnet address (D…) is refused, so the chain can never be run against real DIVI by mistake. (This page made a throwaway mainnet WIF into a scratch directory with the SDK, Key.generate('mainnet'), and deleted it afterwards.)

divi-gamechain --data-dir data-mainnet info
Error: data-mainnet/sequencer.key holds a mainnet key; the side-chain only runs on testnet

A different key with an existing database. Genesis names the sequencer. Copy chain.db somewhere, make a new key beside it, and the node refuses the pair:

mkdir -m 700 data-other && cp data/chain.db data-other/
divi-gamechain --data-dir data-other keygen
data-other/sequencer.key created: xxmj4xkdWnJc9KA1TdX6DYaqcmJU1tZha4
divi-gamechain --data-dir data-other info
Error: config: sequencer key is xxmj4xkdWnJc9KA1TdX6DYaqcmJU1tZha4 but genesis names xxD8ohHuhAGjmxATudgBqfrhwbY6WJR7jM

The same guard covers genesis itself: the store keeps the genesis it was created with, and a database whose genesis does not match what the node computes is refused with genesis does not match the one this data directory was created with.

A typo in the config.

printf 'listen = "127.0.0.1:53920"\nblockms = 500\n' > bad.toml
divi-gamechain --config bad.toml info
Error: parsing bad.toml

Caused by:
    TOML parse error at line 2, column 1
      |
    2 | blockms = 500
      | ^^^^^^^
    unknown field `blockms`, expected one of `data_dir`, `listen`, `block_ms`, `heartbeat_ms`, `divi_rpc`, `divi_poll_ms`, `certificate_issuers`, `anchor`, `bridge`

Restart

A two-line start.sh is enough for a workstation (production gets a systemd unit; see step 10):

#!/bin/sh
cd ~/tut-i/run-the-gamechain
nohup divi-gamechain --config gamechain.toml run --listen 127.0.0.1:53920 >> node.log 2>&1 < /dev/null &
echo $! > node.pid
./start.sh; sleep 4; tail -3 node.log
2026-10-21T19:58:33.425560Z  INFO divi_gamechain: chain opened chain=divi-games-testnet-1 sequencer=xxD8ohHuhAGjmxATudgBqfrhwbY6WJR7jM height=6
2026-10-21T19:58:33.425664Z  INFO divi_gamechain: serving listen=127.0.0.1:53920
2026-10-21T19:58:33.658647Z  INFO divi_gamechain: Divi checkpoint reachable height=359936

It opens at height 6, where it stopped, with the same sequencer, and the house does not repeat its opening moves. Your balance survived:

curl -s http://127.0.0.1:53920/v1/account/y1baNdNhw5ZkcVoCSTUCANM84E1mhw3cR9
{"address":"y1baNdNhw5ZkcVoCSTUCANM84E1mhw3cR9","balances":{"GOLD":"100000"},"next_nonce":1,"nonce":1}
Two nodes, one key

Never run two nodes from one data directory or with one sequencer key: they would sign two different chains with the same identity. One directory, one key, one process. If you want a second chain, make a second directory and run keygen there.

10Where to go next

Stuck? Ask the Divi chatbot, or see all tutorials.