# 运行节点

> 运行 NeuroChain 节点——从源码构建（先构建合约）、启动单个测试节点或多验证者网络、Docker Compose、数据目录结构、密钥、快照、用 Prometheus 和 Grafana 监控、备份与恢复。

Source: https://docs.nro.world/zh/operate/node

## 环境要求

- Rust（stable），并安装 `wasm32-unknown-unknown` target
- C++ 工具链和 `clang`（RocksDB 从源码构建）
- 运行 gateway 需要 Node.js 18+
- 构建需要几 GB 的磁盘空间

## 构建

节点内嵌了两个系统合约，因此要**先**构建它们：

```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
```

如果跳过合约这一步，节点构建会以 `couldn't read …/nrc20.wasm` 失败。`--allow-undefined` 标志让合约的宿主导入能在当前 Rust 版本下完成链接；新合约也可以改为声明 `#[link(wasm_import_module = "env")]`（参见 [NeuroWASM](/zh/neurowasm/#a-minimal-contract)）。

首次构建需要几分钟（RocksDB）；之后的构建只需几秒。本地测试以外的场景请使用 `--release`。

## 单个本地节点

```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` 会开启水龙头并放宽签名检查，供开发使用。任何正式用途都不要设置它（即采用 mainnet 规则）。
- 未设置 `NEUROCHAIN_GENESIS_VALIDATORS` 时，节点会把自己设为唯一的验证者（`neuro:node-1.node`），并立即开始出块。在 mainnet 规则下它需要一个所有者：将 `NEUROCHAIN_VALIDATOR_OWNER` 设为运营它的 `.human` 钱包，否则节点拒绝启动。
- `NEUROCHAIN_MIN_VALIDATORS=1` 会关闭验证者少于 7 个时的警告。

检查节点：

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

然后启动 [gateway](./gateway)。

## 多验证者网络 {#a-multi-validator-network}

所有验证者都必须从**同一个创世配置**启动，其中列出了每个验证者及其共识公钥。仓库为本地网络提供了自动化脚本：

```bash
cd neurochain
scripts/net-test/net-test.sh keys 4    # 创建 4 个验证者密钥，写入共享的创世验证者集合
scripts/net-test/net-test.sh up 4      # 启动它们（先启动节点 1，其余节点从它引导）
scripts/net-test/net-test.sh check     # 高度一致、持续出块、赞助 gas 一致
scripts/net-test/net-test.sh down
```

它使用 9941 起的 RPC 端口、30341 起的 P2P 端口，数据放在 `.net-test/` 下，因此不会影响普通的 `./data` 节点。

手动操作：

1. **为每个验证者创建密钥。** 用各自的 `NEUROCHAIN_DATA_DIR`、`NEUROCHAIN_NODE_ADDR` 和端口将每个节点启动一次。它会把密钥写入 `<data dir>/shard0/bft_key.bin` 并输出日志：
   ```
   Consensus validator … — ML-DSA-65 pubkey (put in NEUROCHAIN_GENESIS_VALIDATORS): 6e80bab8…
   ```
   停止节点，删除 `<data dir>/shard0/state_rdb` 和 `<data dir>/shard0/wal`。**保留 `bft_key.bin`。**
2. **编写创世验证者集合**——每个节点使用相同的值：
   ```
   NEUROCHAIN_GENESIS_VALIDATORS='neuro:val1.node|host1:30333|1000000|0.9|<pubkey1>|neuro:<owner1>.human,neuro:val2.node|host2:30333|1000000|0.9|<pubkey2>|neuro:<owner2>.human,…'
   ```
   字段依次为：验证者地址、其 P2P 地址（必须与该节点的 `NEUROCHAIN_NODE_ADDR` 一致）、以 NRO 计的质押量、初始信任值（仅用于展示）、ML-DSA-65 公钥，以及**所有者**——运营该验证者的 `.human` 钱包（资料、解除监禁、质押、佣金）。`bft_key.bin` 中的共识密钥只用于签署区块，永远不控制验证者的账户。没有公钥的条目会被排除在共识之外；在 mainnet 规则下，没有所有者的条目会使节点在启动时停止。
3. **启动**第一个节点，然后用 `NEUROCHAIN_BOOTSTRAP=host1:30333` 启动其余节点。如果验证者数量少于 7，将 `NEUROCHAIN_MIN_VALIDATORS` 设为实际的验证者数量。

共识消息通过同一个 P2P 端口传输；没有单独的共识端口。节点通过将 `NEUROCHAIN_NODE_ADDR` 与创世集合中的 P2P 地址匹配来识别自己是哪个验证者。

::: tip 创世验证者集合永不改变
之后加入的验证者通过注册 `.node` 并质押来加入（参见[质押](/zh/learn/staking)）；他们不会修改 `NEUROCHAIN_GENESIS_VALIDATORS`。使用不同创世集合或余额启动的节点会拒绝其他节点的区块，并输出日志 `STATE DIVERGENCE`。
:::

## Docker Compose

在仓库根目录下：

```bash
cp .env.example .env        # 按需修改
docker compose up -d        # 节点、gateway、Web 应用
docker compose --profile monitoring up -d   # 外加 Prometheus 和 Grafana
```

镜像会分阶段构建合约和节点。节点数据存放在 `node1-data` 卷中；AI 模型文件以只读方式从 `neurochain/models` 挂载。

## 数据目录

| 路径 | 内容 |
|------|---------|
| `<data dir>/shard<N>/bft_key.bin` | 节点的共识与签名密钥——**务必备份，切勿泄露** |
| `<data dir>/shard<N>/state_rdb/` | 分片 N 的 RocksDB 链状态 |
| `<data dir>/shard<N>/wal/` | 共识预写日志，重启后重放 |

## 从快照启动

新节点可以从运行中的节点加载签名的状态快照，从而跳过历史重放：

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

在空数据目录上，节点会获取 `/api/v1/state/snapshot`，应用它，然后从该高度开始追赶。快照会暴露所有余额和质押；请用 `NEUROCHAIN_SNAPSHOT_TOKEN` 保护该端点（客户端随后需发送 `Authorization: Bearer <token>`）。

## 暴露范围与 TLS

- 在 mainnet 规则下 RPC 监听 `localhost`，在 `CHAIN_ENV=testnet` 下监听 `0.0.0.0`；可通过 `NEUROCHAIN_RPC_HOST` 指定。
- 设置 `NEUROCHAIN_TLS_CERT` 和 `NEUROCHAIN_TLS_KEY`（PEM 路径）即可通过 HTTPS 提供 RPC。
- 面向用户的应是 gateway，而不是节点。
- `NEUROCHAIN_INTERNAL_TOKEN` 通过 `X-Internal-Token` 请求头保护内部端点（oracle 日志写入、AI 数据导出）。

## 监控

`GET /metrics` 提供 Prometheus 指标：

| 指标 | 含义 |
|--------|---------|
| `nc_block_height`, `nc_bft_round` | 链的进度 |
| `nc_bft_validators_active`, `nc_bft_quorum_size` | 验证者集合 |
| `nc_peer_count`, `nc_mempool_size`, `nc_tx_total` | 网络与负载 |
| `nc_total_staked`, `nc_base_fee`, `nc_fees_burned` | 经济指标（金额以 uNRO 计） |
| `nc_deploy_rejected_total{rule_id}` | 被 VMGuardian 拒绝的部署，按规则统计 |
| `nc_model_active_count`, `nc_model_voting_count`, `nc_model_version{…}`, `nc_model_confirms_needed`, `nc_model_voting_deadline_remaining_blocks` | AI 模型注册表 |
| `nc_sentinel_flagged_total{category}`, `nc_sentinel_held_total`, `nc_sentinel_released_total{how}` | Sentinel |

`monitoring/` 中包含 Prometheus 抓取配置和预置的 Grafana 仪表盘，并带有针对内存池过大、对等节点少于 2 个以及部署被集中拒绝的告警。

## 备份与恢复

```bash
./scripts/backup.sh [data_dir] [backup_dir]     # 在线复制；节点继续运行
./scripts/restore.sh <backup_dir> [data_dir]    # 先停止节点
```

备份中包含 `bft_key.bin`——请像保管密钥本身一样安全地保管备份。

## 值得了解的日志

| 日志行 | 含义 |
|----------|---------|
| `consensus decided, committing height=…` | 一个区块已最终确定 |
| `Below minimum: n/7 active validators` | 验证者数量少于 `NEUROCHAIN_MIN_VALIDATORS` |
| `STATE DIVERGENCE` | 本节点的状态与提议者的不一致；在问题解决前它拒绝投票 |
| `genesis validator(s) missing ML-DSA pubkey` | 创世集合中有条目缺少公钥，已被排除 |

全部变量：[环境变量](./env)。
