All pages

Run a local chain

Start a one-validator chain on your machine and send a transaction on it. Every step below was run against version 0.2.3, and the numbers shown are from that run.

Build

You need the source and the Rust toolchain. chain/rust-toolchain.toml pins the compiler, so rustup fetches the right one. The first build compiles RocksDB and takes a few minutes. From the repository root:

cd chain
cargo build --release -p qubits-node -p qubits-cli
export PATH="$PWD/target/release:$PATH"

This gives two binaries: qubits-node runs the chain, qubits holds keys and talks to a node.

Create keys

Make one key for the validator and one each for two accounts. Each command asks for a password and writes an encrypted key file. Add --password-file FILE to read the password from the first line of a file instead.

mkdir ~/qubits-local && cd ~/qubits-local
qubits key new --out validator.json
qubits key new --out alice.json
qubits key new --out bob.json

Keys use ML-DSA-65 unless you pass --scheme slh-dsa-sha2-192s.

Write the genesis file

The validator is listed by public key and an account by address. key show needs no password.

VALIDATOR=$(qubits key show --key validator.json | awk '/public key/ {print $3}')
ALICE=$(qubits address --key alice.json)
BOB=$(qubits address --key bob.json)

cat > genesis.json <<JSON
{
  "chain_id": "local",
  "timestamp_ms": 1778112000000,
  "params": { "min_fee_per_byte": 10000000000, "max_block_transactions": 1000 },
  "validators": [{ "key": "$VALIDATOR", "payout": "$BOB" }],
  "accounts": [{ "address": "$ALICE", "balance": "1000000000000000000000" }]
}
JSON

payout is the address the validator's fees go to, Bob's here. Balances are decimal strings in base units. The native token has 18 decimals, so this gives Alice 1,000 coins. min_fee_per_byte is in base units too: 10,000,000,000 is 0.00000001 coin a byte.

Start the node

qubits-node init --genesis genesis.json --data-dir data
initialized chain `local` in data
genesis hash: 3fde3d75f6238d4bd9344302e0c81e46d61bc4476fa60f7da9a25cebd6fcedcf

Your hash will differ, because it depends on your keys. Run the validator in a second terminal:

qubits-node run --data-dir data --validator-key validator.json

The HTTP API is now on http://127.0.0.1:8545, which is where qubits looks by default. Set QUBITS_RPC or pass --rpc for another address.

curl http://127.0.0.1:8545/v1/status
{
  "chain_id": "local",
  "genesis_hash": "3fde3d75f6238d4bd9344302e0c81e46d61bc4476fa60f7da9a25cebd6fcedcf",
  "height": 0,
  "latest_hash": "3fde3d75f6238d4bd9344302e0c81e46d61bc4476fa60f7da9a25cebd6fcedcf",
  "latest_timestamp_ms": 1778112000000,
  "state_root": "00488fdc1b6c8f6dac496c334ec1933702b9b3aa8e2621a39f6a131642b2ec2f",
  "min_fee_per_byte": 10000000000,
  "mempool_size": 0,
  "state_from": 0,
  "blocks_from": 1
}

The height stays at 0. An idle chain makes no blocks, and that is deliberate: see the idle pause.

Send a transaction

Send 5 coins from Alice to Bob. Amounts on the command line are base units.

qubits transfer --key alice.json --to "$BOB" --amount 5000000000000000000 --wait
transaction acdde6a6edbae30b95949621724f05340347421d22c857bbd14e6fbdfe16e478 submitted (fee 54320000000000)
included in block 1

The fee is the size of the signed transaction, 5,432 bytes, times min_fee_per_byte. This first transaction is large because it carries Alice's public key, which the chain has not seen: an address is only the hash of a policy. See Accounts and addresses.

qubits account "$BOB"
qubits account "$ALICE"

Bob now holds 5000000000000000000, and has no auth yet because he has signed nothing. Alice has nonce 1, and her policy is on chain.

Claim the fee

Bob is the validator's payout address, so the fee Alice paid is waiting for him in the pool:

qubits validators rewards "$BOB"
{
  "payout": "qb15kn7e2wnxnvjja9nvzxdgjsj9w8q5z203zf0x2m5drtympmdr8pst7tjv6",
  "seated": true,
  "claimable": "54320000000000"
}

Anyone can send the claim and pay for it, and the coins only ever go to the payout address:

qubits validators claim --payout "$BOB" --key alice.json --wait
transaction 7b1a7266cc7253dd5b57d88ab369ca11810bb7b206e1f9f3518d08686df7dc63 submitted (fee 34500000000000)
included in block 3

Bob now holds 5000054320000000000. The claim's own fee is the next reward, so validators rewards shows 34500000000000. See Rewards.

Where next

To start again, stop the node and delete data. To keep the chain, stop it with Ctrl-C and run the same command later: it resumes from its tip.

Source

chain/crates/qubits-cli, chain/crates/qubits-node/src/main.rs and chain/crates/qubits-types/src/genesis.rs.