# 共识

> NeuroChain 如何实现最终性——使用 ML-DSA-65 投票的 Malachite（Tendermint）BFT、按质押加权的提议者选择、状态根检查、双签 slashing、追赶同步以及按分片运行的实例。

Source: https://docs.nro.world/zh/learn/consensus

NeuroChain 运行 **Malachite**（Informal Systems）——以 Rust 库形式提供并嵌入节点的 Tendermint BFT。只要持有超过 2/3 质押的验证者对一个区块完成 precommit，该区块即**最终确定**：没有需要等待消解的分叉，也不需要数确认数。

| 属性 | 值 |
|----------|-------|
| 算法 | Tendermint BFT：propose → prevote → precommit |
| 投票权 | 验证者的质押，以 uNRO 计 |
| 提交阈值 | 超过总投票权的 2/3 |
| 容错能力 | `3f + 1` 个验证者中最多 `f` 个故障 |
| 投票与提案签名 | ML-DSA-65（后量子） |
| 最终性 | 提交即最终 |

## 一个高度，逐步分解

![一个共识高度：提议者发送包含 TX 列表、tx_root 和上一状态根的提案；验证者检查后 prevote，再 precommit；超过 2/3 质押完成 precommit 后，每个验证者执行该区块；未按时达到法定人数则开始下一轮并更换提议者](/diagrams/zh/consensus-height.svg)

1. **Propose。** `(height, round)` 对应的提议者从 mempool 构建区块：交易列表、其 Merkle 根 `tx_root`，以及 `prev_state_root`——它在上一个区块之后得到的状态根。
2. **校验。** 其他每个验证者都根据 `tx_root` 检查交易，并将 `prev_state_root` 与自己在上一高度的状态根比较。不一致意味着某一方的状态已经分叉；该验证者拒绝 prevote，并记录 `STATE DIVERGENCE`。
3. **Prevote、precommit。** 验证者为该区块投票；若区块无效或未按时到达，则投 nil。
4. **提交。** 当收到超过 2/3 投票权的 precommit 时，区块即被确定。每个验证者执行其中的交易、拆分手续费、在奖励高度发放质押奖励，并计算新的状态根——全部是确定性的，因此每个诚实节点最终得到相同的状态根。
5. **未按时达到法定人数**时，该高度进入下一轮，更换提议者并延长超时。

轮次超时使用 Malachite 的默认值。区块之间的节奏按节点设置：

| 变量 | 默认值 | 含义 |
|----------|---------|---------|
| `NEUROCHAIN_BLOCK_MS` | 200 | 提议包含交易的区块前的最短等待时间 |
| `NEUROCHAIN_EMPTY_BLOCK_MS` | 2000 | 提议空区块前的最短等待时间，让空闲的链保持安静 |

## 谁来提议

提议者**仅按质押**确定性地选出，因此每个节点算出的结果相同：

1. 取活跃验证者及其质押；将所有质押除以它们的最大公约数，使得只有比例起作用。
2. 对 `SHA3-256("neuro-proposer|" ‖ height ‖ round)` 求哈希，得到一个在总权重上均匀分布的数。
3. 按顺序遍历验证者；该数落在谁的权重区间内，谁就是提议者。

质押翻倍的验证者，提议频率也翻倍。轮次变更会选出一个新数，因此宕机的验证者会被跳过。如果所有验证者都已没有质押，选择会退回到轮询，以保证链继续前进。

## 验证者集合 {#validator-set}

当以下条件**全部**满足时，验证者参与共识：

- 其地址以 `.node` 结尾，且其 ML-DSA-65 共识公钥已上链。
- 其质押至少为 `min_stake`（默认 10 000 NRO）。
- 它未被 slash，也未被 jail。
- 在分片网络中，它属于本分片。

该集合从链上状态重新推导，因此质押变化、slash 和新注册都通过每个验证者已执行的交易生效。

要实现真正的拜占庭容错，协议至少需要 **7 个验证者**（`f = 2`）。验证者数量不足的节点会在启动时记录警告；`GET /health` 报告 `validator_count`、`bft_quorum`（当前集合的 `2f + 1` 数量）和 `bft_ready`。可用 `NEUROCHAIN_MIN_VALIDATORS` 为测试网络覆盖该最小值。

## AI 可以和不可以作用的地方

Tendermint 的安全性证明建立在投票权即质押这一点上。AI 绝不能改变它。

| | 是否允许？ | 状态 |
|---|---|---|
| 改变投票权或 2/3 阈值 | **绝不** | 已强制执行：投票由 Malachite 按质押计数 |
| 移除验证者（jail、slash → 投票权 0） | 是——只能移除，绝不增加权重 | 已上线，由双签证据触发 |
| 按信任度偏置提议者选择 | 原则上允许 | **未启用**：提议者选择仅基于质押 |

**ConsensusAI** 根据每个验证者近期的参与情况计算信任评分。目前该评分**只报告，不使用**：你可以在 `GET /api/v1/validators` 以及每个区块的预言机决策日志中看到它。它之所以被移出提议者选择，是因为每个节点都按自己的视角统计参与情况；一次中断之后，这些视角逐渐偏离，节点对谁可以提议产生分歧，且再也没有重新收敛。要让信任度重新参与提议者选择，所用的参与数据本身必须在共识中达成一致（上一个区块的提交信息随下一个区块一起携带）。

## Slashing 与 jail {#slashing-and-jail}

在同一高度和轮次签署两个不同的投票是可证明的不当行为。当此类证据被提交并在共识中验证后：

| 效果 | 默认值 | 治理参数 |
|--------|---------|----------------------|
| 质押被 slash | `min_stake` 的 5%（以验证者的质押为上限） | `slash_fraction_double_sign_bps` = 500 |
| 举报者奖励 | 被 slash 金额的 1% | `slash_reward_fraction_bps` = 100 |
| 剩余部分 | 销毁 | — |
| Jail（投票权 0） | 10 000 个区块 | `jail_blocks`（环境变量 `NEUROCHAIN_JAIL_BLOCKS`） |

每份证据只执行一次。jail 期结束后，只要其质押仍至少为 `min_stake`，验证者会自动回到集合中。slash 记录列在 `GET /api/v1/slashing/history`。

## 重启与追赶

- **重启。** Malachite 维护一份预写日志（write-ahead log）。重启的验证者会重放它，并可能确定一个它已经提交过的高度；节点会识别出该区块已执行并继续运行，而不是停机。
- **追赶。** 离线过的节点会向对等节点请求它错过的已确定区块——每个都附带提交证书和完整的交易列表——并按顺序执行，与亲自参与时完全一致。对等节点为此保留最近 10 000 个已确定区块（`NEUROCHAIN_SYNC_HISTORY_BLOCKS`）。落后超过这一范围的节点会明显地保持落后，而不会复制它未执行过的区块记录；旧的区块记录同步现在只对节点已持有的区块比较状态根。
- **新节点。** 新节点可以从已签名的状态快照启动，而不必从 genesis 开始重放——见[运行节点](/zh/operate/node)。

## 分片 <Badge type="warning" text="实验性" /> {#sharding}

网络可以拆分为多个分片，每个分片运行**自己的 Malachite 实例**，拥有自己的验证者和区块高度：

- 账户或验证者属于分片 `FNV-1a(address) mod n_shards`。
- 节点服务于 `NEUROCHAIN_SHARD_ID` 指定的分片；分片数为 `NEUROCHAIN_SHARDS`。未设置 `NEUROCHAIN_SHARD_ID` 时，节点运行单个分片，没有跨分片转账。
- 发往另一个分片的转账是两阶段提交：源分片**锁定**金额；目标分片在检查扣款的 Merkle 证明后**提交**它；若 10 个区块（`RELAY_TIMEOUT_BLOCKS`）内未完成，源分片向发送方**退款**。

**测试方式。** 节点中的单元测试覆盖分片分配、按分片过滤的 mempool 和投票、锁定 → 提交路径以及超时退款（`test_cross_shard_2pc_commit`、`test_cross_shard_2pc_timeout_refund`，用 `cargo test -p neurochain-node` 运行）。迄今为止的多验证者网络运行都只使用单个分片；尚未进行多分片、每分片多验证者的运行。运维方面见 [IBC v2 与分片](/zh/operate/ibc)。

## 自行验证

```bash
curl -s "$NODE_RPC/health"                # 高度、轮次、对等节点、validator_count、bft_quorum、bft_ready
curl -s "$NODE_RPC/api/v1/validators"     # 质押、信任评分、已提议区块、已投票数
curl -s "$NODE_RPC/api/v1/blocks?limit=1" # 最新区块：提议者、tx_root、state_root
```
