# Sentinel

> Sentinel——NeuroChain 的交易异常评分——内置模型及其特征、类别、入口拒绝阈值，以及可选的策略层：它以暂扣或要求确认代替拒绝，并带有信任列表和会话密钥规则。

Source: https://docs.nro.world/zh/ai/sentinel

Sentinel 为每笔传入的转账给出一个从 0（正常）到 1（极不寻常）的**异常分数**。根据设置，节点随后会接受、标记或拒绝该转账，或者——在启用策略层时——将其暂扣一段时间或直到所有者确认。

## 模型

一个内置于节点中的小型网络（8 个输入 → 16 → 8 → 1，289 个参数）。它的输入描述的是转账本身，而不是人：

| 特征 | 来源 |
|------|------|
| 金额大小（对数尺度） | `value` |
| gas 价格 | `gas_price` |
| nonce 间隔 | `nonce` 与最后确认的 nonce 之比较 |
| 收款方是新地址 | 此前向该收款方的转账 |
| 整数金额 | `value` |
| 发送方频率 | 发送方在最近 10 个区块中的转账 |
| 转出余额占比 | `value` 与余额之比较 |
| 自转账 | `from == to` |

在共识中，节点**仅根据已提交的区块**计算这些特征（频率按区块统计，而不是按内存池），因此每个验证者对同一笔交易得到相同的分数。

| 分数 | 类别 | `anomalous` |
|------|------|-------------|
| < 0.5 | `normal` | 否 |
| 0.5 – 0.6 | `suspicious` | 是 |
| 0.6 – 0.8 | `elevated` | 是 |
| ≥ 0.8 | `high_risk` | 是 |

无需发送任何东西即可试用：

```bash
curl -s -X POST "$GATEWAY/api/v1/sentinel/score" -H 'Content-Type: application/json' \
  -d '{"value":45000000,"gas_price":2,"nonce":3,"last_nonce":2,"balance":48000000,
       "tx_count_last_10":1,"recipient_tx_count":0,"is_self_transfer":false}'
# {"anomalous":true,"category":"elevated","score":0.7119}
```

## 转账会经历什么

![Sentinel 决策流程：分数达到或超过 0.85 在入口被拒绝；否则，策略层关闭时转账照常应用（异常则加标记）；策略层开启时，受信任收款方照常应用，分数达到或超过 0.70（会话密钥为 0.60）被暂扣直到所有者确认，分数从 0.60 起被暂扣并在 50 个区块后自动放行](/diagrams/zh/sentinel-policy.svg)

### 始终启用 <Badge type="tip" text="已上线" />

- `sentinel_enabled = 1`：每笔转账到达节点时都会被评分。
- 分数 ≥ `sentinel_reject_threshold`（0.85）→ 以 HTTP 400 拒绝。
- 异常但低于该阈值 → 接受；响应中带有 `sentinel_score`、`sentinel_category` 和 `sentinel_warning`，gateway 会广播 `tx_anomaly`。

### 策略层 <Badge type="warning" text="默认关闭" />

在 `sentinel_policy_enabled = 1` 时，一笔原本会被应用的转账可能被**暂扣**：发送方已扣款，但收款方尚未入账。

| 档位 | 条件 | 结果 |
|------|------|------|
| 受信任 | 收款方在发送方的有效信任列表中 | 照常应用 |
| 暂扣 | 分数 ≥ `sentinel_hold_threshold`（0.60） | 在 `sentinel_hold_blocks`（50）个区块后自动放行；在此之前发送方可以取消 |
| 加强确认 | 分数 ≥ `sentinel_stepup_threshold`（0.70），**或**由会话密钥签名且分数 ≥ `sentinel_agent_confirm_threshold`（0.60） | 等待所有者**用主密钥确认**；若在 `sentinel_confirm_expiry_blocks`（1 000）个区块内未确认则退回 |

被暂扣的转账状态为 `held`；最终结果为 `confirmed`（已放行）、`cancelled` 或 `refunded`。取消或退回时金额返还给发送方；手续费不退。

| 操作 | 端点 |
|------|------|
| 列出被暂扣的转账 | `GET /api/v1/held/:address` |
| 确认（所有者，主密钥） | `POST /api/v1/transactions/:hash/confirm` |
| 取消（所有者） | `POST /api/v1/transactions/:hash/cancel` |

WebSocket 事件：`tx_held`、`tx_released`、`tx_cancelled`。

### 信任列表

所有者可以把收款方标记为受信任；发往这些地址的转账会跳过暂扣。新条目要在 `trust_activation_blocks`（300）个区块之后才生效——这样被盗的密钥就无法添加攻击者的地址并立即使用。

`POST /api/v1/trust/add`、`POST /api/v1/trust/remove`、`GET /api/v1/trust/:owner`。

### 会话密钥不能批准自己

任何以 `neuro:system.trust` 为目标的操作——修改信任列表、确认或取消被暂扣的转账——对会话密钥一律拒绝。AI 代理可以发起一笔有风险的转账；只有所有者的主密钥才能放行。参见[账户抽象](./account-abstraction)。

## 校准 <Badge type="warning" text="实验性" />

该模型基于合成的交易模式训练。真实转账的分数比合成数据所预示的更高：在测试网络上，一笔向新收款方转账 1.5 NRO 的普通交易得分约 **0.62**，实测分数很少超过约 **0.74**。由此带来两个后果：

- 0.85 的拒绝阈值实际上永远不会达到。
- 在默认阈值下，启用策略层会暂扣许多发往新收款方的普通转账。

这些阈值是治理参数；在公共网络上启用策略层之前，会基于真实交易数据调整阈值并重新训练模型。

**测试情况：** 策略层在四个验证者、法定人数为三的环境中通过了七个步骤的测试——自动放行、经由另一个节点的加强确认、到期退回、经由第三个节点取消、节点重启后保持、信任列表生效，以及每个节点上计数器和状态根完全一致。节点单元测试覆盖了每个分支。

## 指标

Prometheus 计数器保存在链上状态中，因此每个节点报告的数字相同：`nc_sentinel_flagged_total{category}`、`nc_sentinel_held_total`、`nc_sentinel_released_total{how}`。
