One-Block-Org/FlashStat
GitHub: One-Block-Org/FlashStat
针对 Unichain 的实时排序器监控与欺诈检测系统,结合 TEE 硬件认证验证与主动链上罚没机制来保障 OP-Stack 网络共识安全。
Stars: 2 | Forks: 1
# FlashStat
**FlashStat** 是一个实时的 Unichain 排序器监控和欺诈检测系统。它监视 OP-Stack 排序器的违规行为——软重组、模棱两可和双重支付尝试——并在检测到违规行为时,可以通过 Guardian Wallet 自主提交链上罚没证明。
该系统将加密的 TEE (Intel TDX) 认证验证与持久化的区块置信度模型以及用于排序器地址的实时信誉评分引擎相结合,通过 JSON-RPC API、终端仪表板和生产就绪的 Docker 套件进行展示。
## 目录
- [TypeScript SDK](#typescript-sdk)
- [@flashstat/core](#flashstatcore)
- [@flashstat/viem](#flashstatviem)
- [@flashstat/react](#flashstatreact)
- [功能](#features)
- [架构](#architecture)
- [工作区布局](#workspace-layout)
- [前置条件](#prerequisites)
- [配置](#configuration)
- [基于文件的配置](#file-based-configuration)
- [环境变量覆盖](#environment-variable-overrides)
- [完整参考](#full-reference)
- [运行系统](#running-the-system)
- [1. 核心监控器 (`flashstat`)](#1-core-monitor-flashstat)
- [2. RPC 服务器 (`flashstat-server`)](#2-rpc-server-flashstat-server)
- [3. 终端仪表板 (`flashstat-tui`)](#3-terminal-dashboard-flashstat-tui)
- [4. 取证模拟器 (`flashstat-simulate`)](#4-forensic-simulator-flashstat-simulate)
- [Guardian Wallet (主动保护)](#guardian-wallet-active-protection)
- [私钥模式](#private-key-mode)
- [Keystore 模式](#keystore-mode)
- [Slashing 合约 ABI](#slashing-contract-abi)
- [JSON-RPC API 参考](#json-rpc-api-reference)
- [方法](#methods)
- [订阅](#subscriptions)
- [置信度模型](#confidence-model)
- [信誉评分](#reputation-scoring)
- [TEE / TDX 认证](#tee--tdx-attestation)
- [证明编码](#proof-encoding)
- [Crate 参考](#crate-reference)
- [测试](#testing)
- [CI](#ci)
- [贡献](#contributing)
- [许可证](#license)
- [开发说明](#development-notes)
## 功能
| 能力 | 详情 |
|---|---|
| **实时区块监控** | 通过 WebSocket 订阅 Unichain,支持 HTTP 轮询回退 |
| **软重组检测** | 立即标记同高度的区块哈希冲突 |
| **模棱两可检测** | 识别同高度、同签名者、不同哈希的冲突 |
| **冲突分析** | 对比冲突区块间的交易;识别被丢弃的交易和双重支付 |
| **TEE 签名验证** | 从 OP-Stack 的 `extra_data` 中恢复 ECDSA 签名者,并与配置的排序器进行比对验证 |
| **Intel TDX 认证** | 可选的 TDX Quote V4 结构验证和 MRENCLAVE 比对 |
| **区块置信度评分** | 将持久性深度和 TEE 验证结合为 `0–99%` 的置信度分数 |
| **信誉引擎** | 跟踪每个排序器签署的区块、连续记录、认证、重组和模棱两可行为 |
| **主动罚没** | Guardian Wallet 向 SlashingManager 合约提交 RLP 编码的链上模棱两可证明 |
| **JSON-RPC 服务器** | 完整的请求/响应 API,加上用于实时区块和重组流的 WebSocket 发布/订阅 |
| **终端 UI** | 实时仪表板,包含区块动态、置信度条、排序器排行榜和重组日志 |
| **持久化存储** | 内嵌 [redb](https://github.com/cberner/redb) 键值数据库——无外部依赖 |
## TypeScript SDK
FlashStat 提供了三个 TypeScript 包,用于将实时区块置信度集成到任何 JavaScript 应用程序中。所有包均位于 `sdks/typescript/` 中。
| 包 | 安装 | 用途 |
|---|---|---|
| `@flashstat/core` | 零依赖 | 任何 Node.js / 浏览器应用 |
| `@flashstat/viem` | 对等依赖: `viem >=2` | OP-Stack / Unichain 构建者 |
| `@flashstat/react` | 对等依赖: `react >=18` | dApp 前端 |
### @flashstat/core
独立的 HTTP + WebSocket 客户端。无外部依赖。
```
import { FlashStatClient } from '@flashstat/core';
const client = new FlashStatClient({ url: 'http://127.0.0.1:9944' });
// Query confidence for a specific block hash
const confidence = await client.getConfidence('0xabc...');
if (confidence > 95) {
console.log('✓ Safe to act — high-confidence Flashblock');
}
// Subscribe to live blocks
const unsub = client.subscribeBlocks((block) => {
console.log(`Block #${block.number} — ${block.confidence.toFixed(1)}% (${block.status})`);
});
// Subscribe to reorg / equivocation events
client.subscribeEvents((event) => {
if (event.severity === 'Equivocation') {
console.error('🚨 Sequencer equivocation at block', event.blockNumber);
}
});
// Clean up
unsub();
client.destroy();
```
### @flashstat/viem
只需一行设置,即可使用 FlashStat 操作扩展任何 Viem `PublicClient`。
```
import { createPublicClient, http } from 'viem';
import { unichain } from 'viem/chains';
import { flashStatActions } from '@flashstat/viem';
const client = createPublicClient({
chain: unichain,
transport: http(),
}).extend(flashStatActions({ url: 'http://127.0.0.1:9944' }));
// All standard Viem methods still work, plus:
const confidence = await client.getFlashConfidence('0xabc...');
const latest = await client.getLatestFlashBlock();
const reorgs = await client.getFlashRecentReorgs(10);
const rankings = await client.getFlashSequencerRankings();
```
### @flashstat/react
用于实时 UI 更新的 React hooks 和上下文提供者。
```
import { FlashStatProvider, useFlashConfidence, useReorgEvents } from '@flashstat/react';
// 1. Wrap your app once
function App() {
return (
);
}
// 2. Use hooks anywhere in the tree
function TransactionStatus({ hash }: { hash: string }) {
const { confidence, status, isLoading } = useFlashConfidence(hash);
if (isLoading) return
;
return (
Status: {status}
Confidence: {confidence.toFixed(1)}%
{confidence > 95 &&
✅ Safe to proceed
}
);
}
// 3. Alert users to reorg events in real time
function ReorgAlert() {
const { events } = useReorgEvents(5);
const equivocations = events.filter(e => e.severity === 'Equivocation');
if (equivocations.length === 0) return null;
return
🚨 Sequencer equivocation detected!;
}
```
**可用的 hooks:**
| Hook | 描述 |
|---|---|
| `useFlashConfidence(hash)` | 针对区块哈希的实时更新置信度分数 |
| `useLatestFlashBlock()` | 最近的一个区块,通过 WebSocket 更新 |
| `useReorgEvents(limit?)` | 最近的重组/模棱两可事件,实时更新 |
| `useSequencerRankings(pollMs?)` | 信誉排行榜,定时轮询 |
| `useFlashHealth(pollMs?)` | 节点健康状态快照 |
#### 运行 Next.js 示例
```
# 终端 1 — 启动 Rust 服务器(Docker 最简单)
docker compose up -d
# 或者,从源代码运行:
# cargo run --release --bin flashstat-server
# 终端 2 — 启动仪表板
cd sdks/typescript/examples/nextjs-dashboard
npm install && npm run dev
# 打开 http://localhost:3000
```
## 架构
```
┌─────────────────────────────────────────┐
│ Unichain (OP-Stack) │
│ WebSocket / HTTP RPC │
└─────────────────┬───────────────────────┘
│ blocks
▼
┌───────────────────────┐
│ FlashMonitor │
│ (flashstat-core) │
│ │
│ verify_tee_signature() │
│ classify_reorg() │
│ update_reputation() │
│ spawn_watchtower_task()│
└─────────┬───────────────┘
│
┌───────────────────┼────────────────────────┐
▼ ▼ ▼
┌──────────────┐ ┌──────────────────┐ ┌────────────────────┐
│ RedbStorage │ │ block_tx channel │ │ event_tx channel │
│ (flashstat-db)│ │ (FlashBlock) │ │ (ReorgEvent) │
└──────────────┘ └────────┬─────────┘ └─────────┬──────────┘
│ │
┌─────────┴─────────────────────────┴──────────┐
│ FlashServer │
│ (flashstat-server) │
│ │
│ JSON-RPC / WebSocket on :9944 │
└────────────────────────────────────────────────┘
│
┌───────────────────┼───────────────────┐
▼ ▼ ▼
┌──────────────────┐ ┌──────────────┐ ┌──────────────────┐
│ flashstat-tui │ │ External RPC │ │ Guardian Wallet │
│ (Terminal UI) │ │ Clients │ │ → SlashingMgr │
└──────────────────┘ └──────────────┘ └──────────────────┘
```
## 工作区布局
```
FlashStat/
├── bin/
│ ├── flashstat/ # Core monitor entry point
│ ├── flashstat-server/ # JSON-RPC + WebSocket server
│ ├── flashstat-tui/ # Terminal dashboard
│ ├── flashstat-simulate/ # Forensic simulation tool
│ └── flashstat-watchtower-test/ # Integration test harness (+ manual smoke-test binary)
│
└── crates/
├── flashstat-common/ # Config, shared types, data models
├── flashstat-core/ # Monitor logic, TEE, wallet, proof encoding
│ ├── src/monitor.rs # FlashMonitor + all helper functions
│ ├── src/tee.rs # TeeVerifier (ECDSA recovery + TDX V4)
│ ├── src/wallet.rs # GuardianWallet (on-chain slashing)
│ └── src/proof.rs # RLP proof encoders
├── flashstat-db/ # RedbStorage persistence layer
└── flashstat-api/ # jsonrpsee #[rpc] trait definition
```
## 使用 Docker 快速开始
运行整个 FlashStat 基础设施(服务器 + Watchtower)最快的方法是使用 Docker Compose。
```
# 1. 克隆仓库
git clone https://github.com/One-Block-Org/FlashStat.git
cd FlashStat
# 2. 在 flashstat.toml 中配置你的 RPC 端点(可选)
# 或设置环境变量
# 3. 启动基础设施
docker compose up -d
```
这将启动:
- **`server`**:在 `localhost:9944` 上提供 RPC/WebSocket API。
- **`watchtower`**:连接到服务器的主动监控代理。
## 前置条件
| 需求 | 版本 |
|---|---|
| Rust | stable (edition 2024) |
| Unichain (或 OP-Stack) RPC 节点 | 任何支持 `eth_subscribe` 的节点 |
| Guardian Wallet | 可选 — Ethereum 私钥或 ERC-55 keystore |
| Slashing 合约 | 可选 — 已部署的 `SlashingManager` 合约地址 |
通过 [rustup](https://rustup.rs/) 安装 Rust:
```
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
```
构建所有工作区二进制文件:
```
cargo build --release
```
## 配置
FlashStat 使用 [`config`](https://docs.rs/config) crate。它从以下位置加载配置:
1. `flashstat.toml`(可选,位于当前工作目录中)
2. 以 `FLASHSTAT__` 为前缀,以 `__` 为分隔符的环境变量
两个来源将被合并,环境变量具有优先权。
### 基于文件的配置
在运行二进制文件的目录中创建 `flashstat.toml`:
```
[rpc]
ws_url = "wss://unichain-sepolia.rpc.example.com"
http_url = "https://unichain-sepolia.rpc.example.com"
[storage]
db_path = "./flashstat.db"
[tee]
sequencer_address = "0xYourSequencerAddress"
attestation_enabled = false
# expected_mrenclave = "deadbeef..." # 可选:用于 TDX pinning 的十六进制 MRENCLAVE
[guardian]
# 选择 private_key 或 keystore_path 其中之一:
# private_key = "0xYourPrivateKey"
# keystore_path = "/path/to/keystore.json"
slashing_contract = "0xYourSlashingManagerAddress"
```
### 环境变量覆盖
每个配置键都映射到 `FLASHSTAT__
__`(全部大写,双下划线分隔符):
```
export FLASHSTAT__RPC__WS_URL="wss://unichain-sepolia.rpc.example.com"
export FLASHSTAT__RPC__HTTP_URL="https://unichain-sepolia.rpc.example.com"
export FLASHSTAT__STORAGE__DB_PATH="./flashstat.db"
export FLASHSTAT__TEE__SEQUENCER_ADDRESS="0xYourSequencerAddress"
export FLASHSTAT__TEE__ATTESTATION_ENABLED="false"
export FLASHSTAT__GUARDIAN__PRIVATE_KEY="0xYourPrivateKey"
export FLASHSTAT__GUARDIAN__SLASHING_CONTRACT="0xSlashingManagerAddress"
```
### 完整参考
| 键 | 类型 | 必填 | 默认值 | 描述 |
|---|---|---|---|---|
| `rpc.ws_url` | String | ✅ | — | 用于区块订阅的 WebSocket 端点 |
| `rpc.http_url` | String | ✅ | — | 用于轮询回退和链上调用的 HTTP 端点 |
| `storage.db_path` | String | ✅ | — | 嵌入式 redb 数据库的文件系统路径 |
| `tee.sequencer_address` | Address | ✅ | — | 预期的 Unichain 排序器 Ethereum 地址 |
| `tee.attestation_enabled` | bool | ✅ | `false` | 启用 Intel TDX 认证引用验证 |
| `tee.expected_mrenclave` | String | ❌ | — | 用于 TDX 引用绑定的十六进制编码预期 MRENCLAVE |
| `guardian.private_key` | String | ❌ | — | Guardian Wallet 的原始十六进制私钥 |
| `guardian.keystore_path` | String | ❌ | — | ERC-55 keystore JSON 文件的路径 |
| `guardian.slashing_contract` | Address | ✅ | — | 已部署的 `SlashingManager` 合约地址 |
## 运行系统
### 1. 核心监控器 (`flashstat`)
通过 WebSocket 连接到 Unichain,处理新区块,并将所有检测结果记录到标准输出。
```
cargo run --release --bin flashstat
```
监控器使用一个**监督循环**:如果 WebSocket 断开,它会自动回退到以 2 秒间隔进行 HTTP 轮询,并在每个监督周期重试 WebSocket 连接。
### 2. RPC 服务器 (`flashstat-server`)
内部启动 `FlashMonitor`,并在 `127.0.0.1:9944` 上公开一个带有 WebSocket 发布/订阅功能的 JSON-RPC 2.0 服务器。
```
cargo run --release --bin flashstat-server
```
这是所有其他客户端(TUI、模拟器、外部工具)连接到的进程。服务器还在内存中跟踪实时统计信息(运行时间、总区块数、总重组数、数据库大小)。
### 3. 终端仪表板 (`flashstat-tui`)
一个全功能的终端 UI,连接到位于 `http://127.0.0.1:9944` 的 `flashstat-server` 并呈现一个实时仪表板。
```
cargo run --release --bin flashstat-tui
```
**键盘控制:**
| 按键 | 动作 |
|---|---|
| `q` | 退出 |
| `↑` / `↓` | 滚动排序器排行榜 |
**仪表板面板:**
| 面板 | 内容 |
|---|---|
| **区块动态** | 已摄取区块的实时流——编号、置信度百分比、哈希、状态徽章 |
| **排序器信誉** | 排名排行榜——分数、总区块数、连续记录、认证、违规次数 |
| **重组日志** | 最近的重组事件——严重程度、区块编号、冲突哈希 |
| **系统健康** | 运行时间、已处理总区块数、重组数量、数据库大小 |
### 4. 取证模拟器 (`flashstat-simulate`)
通过 `flash_ingestBlock` RPC 方法将合成的区块场景注入到运行中的 `flashstat-server` 中,用于测试和演示。
```
# 模拟 3 个 equivocation 场景(默认)
cargo run --release --bin flashstat-simulate -- --count 3
# 模拟 5 个标准顺序区块
cargo run --release --bin flashstat-simulate -- --count 5 --severity standard
# 指定非默认服务器
cargo run --release --bin flashstat-simulate -- --url http://192.168.1.10:9944
```
**参数:**
| 标志 | 默认值 | 描述 |
|---|---|---|
| `--url` / `-u` | `http://127.0.0.1:9944` | 目标 RPC 服务器 URL |
| `--count` / `-c` | `1` | 要注入的场景数量 |
| `--severity` / `-s` | `equivocation` | 场景类型:`equivocation` 或 `standard` |
`equivocation` 模拟会注入两个高度相同但哈希和 `extra_data` 签名不同的区块,从而触发重组检测、信誉惩罚以及(如果已配置)链上证明提交。
## Guardian Wallet (主动保护)
当配置了 Guardian Wallet 时,监控器在检测到模棱两可的情况时会**自动提交链上罚没证明**。这就是主动 Watchtower 模式。
Guardian 钱包提交两种证明类型:
- **模棱两可证明**:RLP 编码的区块号、签名者地址、两个冲突签名以及两个冲突区块哈希
- **双重支付证明**:RLP 编码的冲突交易哈希对、发送者地址和 nonce
### 私钥模式
```
[guardian]
private_key = "0xabc123..."
slashing_contract = "0xSlashingManager"
```
### Keystore 模式
```
[guardian]
keystore_path = "/secure/path/keystore.json"
slashing_contract = "0xSlashingManager"
```
通过环境变量设置 keystore 密码(绝不要写在配置文件中):
```
export FLASHSTAT__GUARDIAN__PASSWORD="your-keystore-password"
```
### Slashing 合约 ABI
`SlashingManager` 合约必须实现:
```
function submitEquivocationProof(bytes calldata proof) external;
function submitDoubleSpendProof(bytes calldata proof) external;
```
有关 `proof` 参数的确切 RLP 编码格式,请参见[证明编码](#proof-encoding)。
## JSON-RPC API 参考
所有方法都使用 `flash_` 命名空间。服务器默认绑定到 `127.0.0.1:9944`。
- **HTTP**: `http://127.0.0.1:9944`
- **WebSocket**: `ws://127.0.0.1:9944`
### 方法
#### `flash_getLatestBlock`
返回最近处理的 `FlashBlock`,如果监控器尚未看到任何区块,则返回 `null`。
```
{ "jsonrpc": "2.0", "id": 1, "method": "flash_getLatestBlock", "params": [] }
```
**响应:**
```
{
"number": "0x3B9AC9FF",
"hash": "0xabc...",
"parent_hash": "0xdef...",
"confidence": 95.5,
"status": "Stable",
"signer": "0xSequencerAddress",
"timestamp": "2024-01-01T00:00:00Z"
}
```
#### `flash_getRecentBlocks`
返回最近处理的 `N` 个区块,最新的排在最前。
```
{ "jsonrpc": "2.0", "id": 1, "method": "flash_getRecentBlocks", "params": [10] }
```
#### `flash_getConfidence`
返回特定区块哈希的 `confidence` 分数(`0.0–100.0`)。对于区块返回 `0.0`。
```
{ "jsonrpc": "2.0", "id": 1, "method": "flash_getConfidence", "params": ["0xBlockHash"] }
```
#### `flash_getRecentReorgs`
返回最近的 `N` 个重组事件(包括软重组和模棱两可)。
```
{ "jsonrpc": "2.0", "id": 1, "method": "flash_getRecentReorgs", "params": [20] }
```
#### `flash_getEquivocations`
仅返回被归类为 `Equivocation` 严重程度的最近 `N` 个事件。
```
{ "jsonrpc": "2.0", "id": 1, "method": "flash_getEquivocations", "params": [10] }
```
#### `flash_getSequencerRankings`
返回所有被跟踪的排序器地址,按信誉分数降序排列。
```
{ "jsonrpc": "2.0", "id": 1, "method": "flash_getSequencerRankings", "params": [] }
```
#### `flash_getHealth`
返回当前系统健康状态快照。
```
{ "jsonrpc": "2.0", "id": 1, "method": "flash_getHealth", "params": [] }
```
**响应:**
```
{
"uptime_secs": 3600,
"total_blocks": 12500,
"total_reorgs": 3,
"db_size_bytes": 2097152
}
```
#### `flash_ingestBlock`
手动将原始 Ethereum 区块注入监控器管道。供取证模拟器和集成测试使用。
```
{
"jsonrpc": "2.0",
"id": 1,
"method": "flash_ingestBlock",
"params": [{ "number": "0x...", "hash": "0x...", "parentHash": "0x...", "timestamp": "0x..." }]
}
```
### 订阅
仅限 WebSocket。使用 `eth_subscribe` 风格的 jsonrpsee 订阅。
#### `flash_subscribeBlocks`
为监控器处理的每个区块流式传输 `FlashBlock` 通知。
#### `flash_subscribeEvents`
每次检测到软重组或模棱两可时,流式传输 `ReorgEvent` 通知。
## 置信度模型
监控器处理的每个区块都会被分配一个 `confidence` 分数(`0.0–100.0`),表示该区块成为规范区块且不会被重组移除的概率。
该模型使用两个独立的信号:
### 1. 持久性深度
当观察到更高高度的区块且没有冲突时,置信度会增加:
```
base_confidence = (1 - 0.5^persistence) × 100
```
每当观察到更高的、无冲突的新区块时,`persistence` 就会递增。一个区块先前的置信度会影响下一个区块的持久性估算。
### 2. TEE 验证覆盖
如果区块在其 `extra_data` 中携带了来自预期排序器的有效 ECDSA 签名,则 TEE 信号将完全覆盖持久性估算:
| 条件 | 置信度 |
|---|---|
| 未找到签名 | 仅基于持久性 |
| 签名来自错误的签名者 | 仅基于持久性 |
| 有效的排序器签名,认证已禁用 | **90%** |
| 认证已启用,缺少引用 | **85%** |
| 认证已启用,TDX 检查失败 | **45%** |
| 认证已启用,TDX 检查出错 | **70%** |
| 认证已启用,TDX Quote V4 有效 | **99%** |
`confidence > 95.0` 的区块被分类为 **`Stable`**。所有其他区块保持 **`Pending`** 状态。
## 信誉评分
每个排序器地址都会积累一个从所有观察到的事件中计算得出的 `reputation_score`:
```
score = total_blocks_signed
+ total_attested_blocks ← permanent +1 per hardware-attested block
+ (current_streak / 100) × 10 ← streak bonus: +10 for every 100-block streak
− (total_soft_reorgs × 50) ← soft reorg deduction
− (total_equivocations × 1000) ← equivocation deduction (20× heavier)
```
**惩罚规则:**
- 任何违规行为(软重组或模棱两可)都会**将签名连续记录重置为零**
- 对具有悠久历史的排序器发生单次模棱两可行为,通常会导致分数变为深度负值
- 每次事件时都会完全重新计算分数——不存在增量漂移
排行榜通过 `flash_getSequencerRankings` 公开,并在 TUI 仪表板中呈现。
## TEE / TDX 认证
当 `tee.attestation_enabled = true` 时,FlashStat 包含一个 `TeeVerifier`,它会执行两层硬件认证验证。
### 第 1 层:ECDSA 签名恢复
排序器签名是从区块 `extra_data` 字段的**最后 65 个字节**中提取的(与 OP-Stack Flashblocks 约定一致)。ECDSA 签名者通过 `ecrecover` 恢复,并与 `tee.sequencer_address` 进行比对。
### 第 2 层:Intel TDX Quote V4 验证
如果 `extra_data` 中签名之后存在 TDX 认证引用(字节 `[97..]`),则会执行结构验证:
1. **头部检查**:Quote 版本必须为 `4` (TDX Quote V4);认证类型必须为 `2` (TDX)
2. **MRENCLAVE 绑定**(可选):如果设置了 `tee.expected_mrenclave`,则会将引用偏移量 `96–128` 处的 32 字节 MRENCLAVE 与配置的十六进制值逐字节进行比较
## 证明编码
提交给 `SlashingManager` 合约的两种证明类型均经过 RLP 编码。
### 模棱两可证明
```
RLP([
block_number, ← U256
signer, ← Address (20 bytes)
signature_1, ← Bytes (65 bytes, ECDSA from old block)
signature_2, ← Bytes (65 bytes, ECDSA from new block)
block_hash_1, ← H256
block_hash_2 ← H256
])
```
### 双重支付证明
```
RLP([
tx_hash_1, ← H256 (original transaction)
tx_hash_2, ← H256 (replacement transaction at same nonce)
sender, ← Address (20 bytes)
nonce ← U256
])
```
## Crate 参考
| Crate | 作用 |
|---|---|
| `flashstat-common` | 共享数据类型(`FlashBlock`, `ReorgEvent`, `SequencerStats`, `Config`)和配置加载器 |
| `flashstat-db` | `FlashStorage` trait + `RedbStorage` 实现(嵌入式 redb) |
| `flashstat-api` | `jsonrpsee` `#[rpc]` proc-macro trait — 生成服务器和客户端存根 |
| `flashstat-core` | `FlashMonitor`, `TeeVerifier`, `GuardianWallet`, RLP 证明编码器 |
| `flashstat` (bin) | 独立的核心监控器入口点 |
| `flashstat-server` (bin) | 包装监控器的 JSON-RPC 服务器 |
| `flashstat-tui` (bin) | 基于 `ratatui` 的终端仪表板 |
| `flashstat-simulate` (bin) | CLI 取证模拟工具 |
| `flashstat-watchtower-test` (bin + tests) | 手动冒烟测试二进制文件 + Cargo 集成测试套件 |
## 测试
运行完整测试套件:
```
cargo test --all-features
```
该套件包含跨三个类别的**27 个测试**:
### 单元测试 — `flashstat-db` (14 个测试)
针对临时数据库测试所有 `RedbStorage` 操作:
- 区块保存、按哈希获取、最新区块跟踪、最近区块排序和限制执行
- 重组保存和检索,仅模棱两可过滤
- 排序器统计信息更新插入、覆盖和完整枚举
### 单元测试 — `flashstat-core` (13 个测试)
测试监控逻辑、信誉引擎和提取辅助函数:
- 信誉评分、连续记录奖励计算、软重组与模棱两可惩罚比较
- `handle_new_block`:区块持久性、最新区块跟踪、广播通道发送
- 重组检测:冲突哈希触发事件;顺序区块不触发(无误报);重组事件被持久化
- `extract_signature_from_block`:正确的 65 字节尾部提取;短的 `extra_data` 返回 `None`
- `extract_quote_from_block`:从偏移量 97 处正确提取;缺少引用时返回 `None`
- `encode_equivocation_proof` 和 `encode_double_spend_proof` 序列化往返测试
### 集成测试 — `flashstat-watchtower-test` (11 个测试)
使用进程内监控器和临时数据库进行端到端管道测试——**无需实时 RPC 节点**:
- 单区块摄取和检索
- 连续区块不产生重组事件
- 最新区块始终反映最近摄取的区块
- 同高度哈希冲突上的软重组检测;持久化到存储;重复哈希的幂等性
- 信誉累积;模棱两可惩罚导致分数变为负数;连续记录奖励计算
- 广播通道为每个摄取的区块触发
- 完整的 Watchtower 模棱两可场景:两个冲突的已签名区块 → 触发并持久化重组事件
## CI
GitHub Actions 在每次推送到 `main` 和 `dean` 分支,以及所有针对这些分支的 Pull Request 时运行。
`.github/workflows/ci.yml` 运行两个作业:
| 作业 | 步骤 |
|---|---|
| **Check & Lint** | `cargo fmt --all -- --check` → `cargo clippy --all-targets --all-features -- -D warnings` |
| **Test** | `cargo test --all-features` |
在 CI 中,所有的 Clippy 警告都会被视为硬性错误。
## 贡献
我们欢迎您的贡献!有关设置说明和编码标准,请参阅 [CONTRIBUTING.md](CONTRIBUTING.md)。
## 许可证
本项目基于 MIT 许可证授权 - 详情请参阅 [LICENSE](LICENSE) 文件。
## 开发说明
### 日志
所有二进制文件均使用 `tracing-subscriber`。通过 `RUST_LOG` 控制日志级别:
```
RUST_LOG=flashstat_core=debug,flashstat_server=info cargo run --bin flashstat-server
```
### 添加新的 RPC 方法
1. 在 `crates/flashstat-api/src/lib.rs` 中的 `#[rpc]` trait 内添加方法签名
2. 在 `bin/flashstat-server/src/main.rs` 中的 `FlashServer` 上实现它
3. `flashstat-api` proc 宏会自动生成服务器 trait 和 `FlashApiClient` 存根
### 添加新的存储操作
1. 将方法添加到 `crates/flashstat-db/src/lib.rs` 中的 `FlashStorage` trait 中
2. 在同一文件中的 `RedbStorage` 上实现它
3. 在同一文件的 `mod tests` 块中添加相应的 `#[tokio::test]`
### 配置优先级
`flashstat.toml` < 环境变量。没有 CLI 标志层——所有运行时配置都只通过配置文件和环境变量进行。
### 数据库
FlashStat 使用 [redb](https://github.com/cberner/redb),一个纯 Rust 的嵌入式键值存储。数据库文件是位于 `storage.db_path` 的单个文件。可以安全地复制它进行备份。删除该文件可重置所有状态。标签:API接口, Docker, Flashblocks, GNU通用公共许可证, Intel TDX, JSON-RPC, Layer 2, Node.js, OP Stack, PE 加载器, Rollup安全, Slashing, TEE验证, TypeScript, Unichain, 信心评分, 加密验证, 区块链安全, 双重花费, 可信执行环境, 可视化界面, 声誉引擎, 子域名变形, 子域名枚举, 安全插件, 安全防御评估, 排序器监控, 欺诈检测, 系统安全, 罚没机制, 请求拦截, 软重组检测, 通知系统, 链上证明