Skip to content

Run a node ​

Requirements ​

  • Rust (stable) with the wasm32-unknown-unknown target
  • A C++ toolchain and clang (RocksDB is built from source)
  • Node.js 18+ for the gateway
  • A few GB of disk for the build

Build ​

The node embeds two system contracts, so build them first:

bash
cd neurochain
rustup target add wasm32-unknown-unknown

for c in nrc20 ncert; do
  (cd contracts/$c && RUSTFLAGS="-C link-arg=--allow-undefined" \
     cargo build --release --target wasm32-unknown-unknown)
done

cargo build -p neurochain-node --bin neurochain        # → target/debug/neurochain

Without the contract step the node build fails with couldn't read …/nrc20.wasm. The --allow-undefined flag lets the contracts' host imports link with current Rust; new contracts can declare #[link(wasm_import_module = "env")] instead (see NeuroWASM).

The first build takes several minutes (RocksDB); later builds take seconds. Use --release for anything beyond local testing.

A single local node ​

bash
CHAIN_ENV=testnet \
NEUROCHAIN_DATA_DIR=./data \
NEUROCHAIN_MODELS_DIR=./models \
NEUROCHAIN_P2P_PORT=30333 \
NEUROCHAIN_RPC_PORT=9933 \
NEUROCHAIN_NODE_ADDR=localhost:30333 \
NEUROCHAIN_MIN_VALIDATORS=1 \
RUST_LOG=neurochain=info \
./target/debug/neurochain
  • CHAIN_ENV=testnet turns on the faucet and relaxes signature checks for development. Leave it unset (mainnet rules) for anything real.
  • Without NEUROCHAIN_GENESIS_VALIDATORS the node makes itself the only validator (neuro:node-1.node) and starts producing blocks at once.
  • NEUROCHAIN_MIN_VALIDATORS=1 silences the warning about having fewer than 7 validators.

Check it:

bash
curl -s http://localhost:9933/health
# {"status":"ok","height":6,"validator_count":1,"bft_quorum":1,"bft_ready":false,…}

Then start the gateway.

A multi-validator network ​

Every validator must start from the same genesis, which lists every validator with its consensus public key. The repository automates this for a local network:

bash
cd neurochain
scripts/net-test/net-test.sh keys 4    # create 4 validator keys, write the shared genesis set
scripts/net-test/net-test.sh up 4      # start them (node 1 first, the rest bootstrap from it)
scripts/net-test/net-test.sh check     # heights agree, blocks are produced, sponsored gas is consistent
scripts/net-test/net-test.sh down

It uses RPC ports 9941+, P2P ports 30341+ and data under .net-test/, so it does not touch a normal ./data node.

To do it by hand:

  1. Create each validator's key. Start each node once with its own NEUROCHAIN_DATA_DIR, NEUROCHAIN_NODE_ADDR and ports. It writes its key to <data dir>/shard0/bft_key.bin and logs:
    Consensus validator … — ML-DSA-65 pubkey (put in NEUROCHAIN_GENESIS_VALIDATORS): 6e80bab8…
    Stop it and delete <data dir>/shard0/state_rdb and <data dir>/shard0/wal. Keep bft_key.bin.
  2. Write the genesis set — the same value for every node:
    NEUROCHAIN_GENESIS_VALIDATORS='neuro:val1.node|host1:30333|1000000|0.9|<pubkey1>,neuro:val2.node|host2:30333|1000000|0.9|<pubkey2>,…'
    Fields: validator address, its P2P address (must equal that node's NEUROCHAIN_NODE_ADDR), stake in NRO, initial trust (reported only), ML-DSA-65 public key. An entry without a public key is left out of consensus.
  3. Start the first node, then the others with NEUROCHAIN_BOOTSTRAP=host1:30333. Set NEUROCHAIN_MIN_VALIDATORS to your validator count if it is below 7.

Consensus messages travel over the same P2P port; there is no separate consensus port. A node recognises which validator it is by matching NEUROCHAIN_NODE_ADDR with the P2P address in the genesis set.

The genesis set never changes

Validators that join later register a .node and stake (see Staking); they do not edit NEUROCHAIN_GENESIS_VALIDATORS. A node started with a different genesis set or balance refuses the others' blocks and logs STATE DIVERGENCE.

Docker Compose ​

From the repository root:

bash
cp .env.example .env        # edit as needed
docker compose up -d        # node, gateway, web app
docker compose --profile monitoring up -d   # plus Prometheus and Grafana

The images build the contracts and the node in stages. Node data lives in the node1-data volume; AI model files are mounted read-only from neurochain/models.

Data directory ​

PathContent
<data dir>/shard<N>/bft_key.binThe node's consensus and signing key — back it up, never share it
<data dir>/shard<N>/state_rdb/RocksDB chain state of shard N
<data dir>/shard<N>/wal/Consensus write-ahead log, replayed after a restart

Starting from a snapshot ​

A new node can skip replaying history by loading a signed state snapshot from a running node:

bash
NEUROCHAIN_CHECKPOINT_URL=http://trusted-node:9933 ./target/debug/neurochain

On an empty data directory the node fetches /api/v1/state/snapshot, applies it, and catches up from that height. A snapshot reveals every balance and stake; protect the endpoint with NEUROCHAIN_SNAPSHOT_TOKEN (clients then send Authorization: Bearer <token>).

Exposure and TLS ​

  • The RPC listens on localhost under mainnet rules and on 0.0.0.0 under CHAIN_ENV=testnet; set NEUROCHAIN_RPC_HOST to choose.
  • Set NEUROCHAIN_TLS_CERT and NEUROCHAIN_TLS_KEY (PEM paths) to serve the RPC over HTTPS.
  • Put the gateway, not the node, in front of users.
  • NEUROCHAIN_INTERNAL_TOKEN protects internal endpoints (oracle log writes, AI data export) with an X-Internal-Token header.

Monitoring ​

GET /metrics serves Prometheus metrics:

MetricMeaning
nc_block_height, nc_bft_roundChain progress
nc_bft_validators_active, nc_bft_quorum_sizeValidator set
nc_peer_count, nc_mempool_size, nc_tx_totalNetwork and load
nc_total_staked, nc_base_fee, nc_fees_burnedEconomics (amounts in uNRO)
nc_deploy_rejected_total{rule_id}Deploys refused by VMGuardian, per rule
nc_model_active_count, nc_model_voting_count, nc_model_version{…}, nc_model_confirms_needed, nc_model_voting_deadline_remaining_blocksAI model registry
nc_sentinel_flagged_total{category}, nc_sentinel_held_total, nc_sentinel_released_total{how}Sentinel

monitoring/ holds the Prometheus scrape config and a provisioned Grafana dashboard, with alerts for a large mempool, fewer than 2 peers and a burst of rejected deploys.

Backup and restore ​

bash
./scripts/backup.sh [data_dir] [backup_dir]     # live copy; the node keeps running
./scripts/restore.sh <backup_dir> [data_dir]    # stop the node first

Backups include bft_key.bin — store them as securely as the key itself.

Logs worth knowing ​

Log lineMeaning
consensus decided, committing height=…A block was finalised
Below minimum: n/7 active validatorsFewer validators than NEUROCHAIN_MIN_VALIDATORS
STATE DIVERGENCEThis node's state differs from the proposer's; it refuses to vote until resolved
genesis validator(s) missing ML-DSA pubkeyAn entry in the genesis set has no public key and is excluded

All variables: Environment.