igors93/nodo
GitHub: igors93/nodo
Nodo 是一个基于 C++20 的实验性区块链协议,以可审计的状态转换、货币完整性和证据驱动的治理为核心,致力于将安全保护工作量化到协议层面。
Stars: 0 | Forks: 0
安全第一的区块链基础设施,提供可验证的保护、可审计的经济学、受控的国库执行、治理证据以及可重建的状态。
## 概述 Nodo 是一个实验性的 C++20 区块链协议基础,专注于使安全工作可量化、状态可审计、经济受控以及终局性历史可重建。 当前的代码库不是生产环境的 mainnet。它包含一个可运行的 localnet runtime、testnet-candidate 基础、严格的存储/重载检查、P2P 传输基础、国库执行证据、治理投票证据以及广泛的测试。Mainnet 被有意封锁,直到托管、网络、经济、存储和运营安全经过审计和强化。 ## 为什么选择 Nodo 许多区块链系统将保护视为后台基础设施。Nodo 将保护视为协议关注点:validators、peers、国库操作、治理决策、奖励、惩罚、存储、重载和终局性都应留下可供其他节点日后验证的证据。 设计目标很简单: - 状态应从历史中重建; - 余额应有来源; - 货币变更应经过授权; - 国库支出应受到策略检查; - 治理决策应有投票证据支持; - 惩罚应有证据要求; - 奖励应与可量化的保护工作挂钩。 ## 核心原则 Nodo 遵循 Proof-of-Protection 规则集: | 原则 | 含义 | | --- | --- | | 未经授权不得增发。 | 货币扩张必须明确且可审计。 | | 余额必须有来源。 | 账户状态必须可追溯到创世、铸造、转账、奖励或罚没历史。 | | 未经策略验证不得动用国库。 | 国库执行必须满足限额、时间锁、审批、余额和 epoch 检查。 | | 没有治理证据不得批准国库支出。 | 批准必须从经过验证的治理生命周期记录中重现。 | | 没有可验证的投票证据不得作出治理决策。 | 投票、计票和决策必须确定性地重建。 | | 没有可量化的保护工作不得奖励。 | 奖励基础应与可审计的网络保护挂钩。 | | 没有可验证的证据不得惩罚。 | Slashing 和惩罚必须是幂等的且有证据支持。 | | 如果无法从历史重建,则不接受状态。 | 重载和审计拒绝非规范或分叉的状态。 | 有关更深入的模型,请参阅 [Proof of Protection](docs/overview/proof-of-protection.md)。 ## 功能 已实现的基础包括: - localnet 开发 pipeline,包括初始化、交易提交、由本地 PRECOMMIT 支持的区块生产、终局性确认、重载和审计; - 基于 CMake 的 C++20 构建,每个 `tests/**/*.cpp` 对应一个测试可执行文件; - 严格的存储 schema 验证和原子持久化助手(`AtomicFile` 防崩溃写入); - 规范的终局性产物,包含货币、国库、治理、validator 和 slashing 部分; - 在区块投票之前进行权威的状态转换执行,并将账户和协议域统一规范重播为确定性的状态/回执根,同时进行硬币批次所有权验证,且 CoinLot 注册表摘要包含在状态根承诺中; - OpenSSL Ed25519 用户签名和 blst BLS12-381 validator 签名; - BFT 共识,Quorum Certificate (QC) 仅需要 PRECOMMIT 投票中 2/3+ 的 validator 权重; - 持久的 QC 持久化:`FinalizedBlockRecordStore` 将每个 QC 证明原子地写入 `{dataDir}/sync/qc/{height}.qc`,在启动时重载所有记录,并恢复内存中的 `BlockFinalizationRegistry` —— 使 fast-path `QC_REQUIRED` 同步模式在重启后依然有效; - P2P 消息、gossip、loopback、TCP、加密 peer-channel、同步和 peer-rate-limiter 基础; - 分布式 node daemon,具备交易 gossip 中继、带有 proposer 身份验证的区块提案中继、PREVOTE/PRECOMMIT 投票以及终局性产物 QC 验证; - 国库策略、支出验证、执行证据和终局性国库审计; - 治理投票证明、投票证据、投票集审计、计票、决策审计、生命周期持久化以及由生命周期支持的国库批准; - 针对冲突投票和 proposer equivocation 的 slashing 证据,在 ValidatorPenaltyLedger、ValidatorRegistry 和 StakingRegistry 中具有确定性的惩罚效果; - testnet-candidate 就绪状态和 operator 诊断基础。 ## 当前状态 | 领域 | 状态 | | --- | --- | | Localnet runtime | 已实现,用于开发和测试。 | | Testnet candidate | 基础已存在;安全门和诊断已激活。 | | Mainnet | 被设计性地封锁。不适合生产环境使用。 | | QC 持久化 | 完全实现;QC 证明可在节点重启后保留。 | | 区块同步 | fast-path(`QC_REQUIRED`)和持久化路径均已实现并经过测试。 | | P2P 网络 | 实现并测试了真实的 socket/gossip 传输、peer 身份验证、发现、封禁/隔离、速率限制和日蚀攻击保护;实现并测试了基于 TCP 的实时分布式共识(proposer 选择、两阶段 prevote/precommit、超时视图切换)(Phase 2 完成)。 | | 密钥和托管 | 存在本地开发密钥;生产环境托管尚未就绪。 | | 治理 | 存在投票证据和生命周期审计基础;公开的治理工作流仍在开发中。 | | 国库 | 存在由证据支持的执行验证;生产环境的 operator 流程仍在开发中。 | | 经济学 | 存在货币、奖励、保护、惩罚和供应审计基础;CoinLot 验证已接入区块预览和状态根;最终的经济激活尚未完成。 | ## 快速开始 ### Windows PowerShell ``` $env:BLST_ROOT="$env:USERPROFILE\.nodo\deps\blst" .\scripts\cmake_build.bat .\scripts\cmake_test_all.bat .\build\nodo.exe help ``` ### Linux, macOS, Git Bash 或 MSYS2 ``` export BLST_ROOT="$HOME/.nodo/deps/blst" ./scripts/cmake_build.sh ./scripts/cmake_test_all.sh ./build/nodo help ``` 如果未安装 `blst`,请参阅 [构建](docs/getting-started/build.md)。 ## 构建 前提条件: - CMake 3.20 或更高版本; - C++20 编译器; - OpenSSL libcrypto 开发文件; - 外部 `blst` 头文件和库,安装在此代码库之外。 Windows: ``` .\scripts\cmake_build.bat ``` Linux/macOS/MSYS2: ``` ./scripts/cmake_build.sh ``` 二进制文件写入到: ``` build/nodo.exe # Windows build/nodo # Unix-like environments ``` ## 运行测试 Windows: ``` .\scripts\cmake_test_all.bat ``` Linux/macOS/MSYS2: ``` ./scripts/cmake_test_all.sh ``` 也可以直接运行 CTest: ``` ctest --test-dir build/cmake --output-on-failure ``` ## CLI / 节点命令 常见的 localnet 流程: ``` build/nodo init --network localnet --data-dir .nodo build/nodo keys create --network localnet --data-dir .nodo build/nodo tx submit --data-dir .nodo build/nodo block produce --data-dir .nodo build/nodo node reload --network localnet --data-dir .nodo build/nodo chain audit --data-dir .nodo build/nodo status --data-dir .nodo build/nodo diagnostics --network localnet --data-dir .nodo ``` 网络配置: - `localnet`:开发 runtime 路径; - `testnet-candidate`:带有安全门的官方 pre-testnet 配置; - `mainnet`:被有意封锁。 更多命令记录在 [CLI](docs/getting-started/cli.md) 中。 ## 项目结构 | 路径 | 用途 | | --- | --- | | `apps/cli/` | CLI 可执行入口点。 | | `include/` | 用于协议、runtime、经济学、存储、P2P 和实用程序的公共头文件。 | | `src/app/` | 命令行编排和本地 operator 流程。 | | `src/core/` | 区块、交易、账户状态、validators 和状态转换基础。 | | `src/consensus/` | 投票、轮次、Quorum Certificates、终局性和 proposer 调度。 | | `src/economics/` | 货币政策、国库、治理、保护奖励、供应审计和惩罚。 | | `src/node/` | Runtime、存储/重载、终局性产物、QC 持久化、诊断、就绪状态和链审计。 | | `src/p2p/` | 消息、gossip、TCP/loopback 传输、同步、加密和 peer 限制。 | | `src/storage/` | 原子文件、区块存储、证据存储和持久化助手。 | | `tests/` | CTest 发现的模块测试(每个文件一个可执行文件,命名为 `{module}_{TestFile}`)。 | | `scripts/` | 构建、测试、清理和依赖助手脚本。 | | `docs/` | 项目文档。 | ### 存储布局 ``` {dataDirectory}/ ├── manifest — latest height, hash, and state root ├── schema — storage schema version ├── blocks/ — finalized block artifact files ├── mempool/ — persistent mempool transactions ├── sync/ │ ├── checkpoint.conf — block sync checkpoint (last synced height) │ └── qc/ │ ├── 1.qc — FinalizedBlockRecord (QC proof) for height 1 │ ├── 2.qc — FinalizedBlockRecord (QC proof) for height 2 │ └── ... └── ... ``` 每个 `.qc` 文件通过临时文件 + 重命名进行原子写入。在启动时,将加载所有 `.qc` 文件,并在同步或共识恢复之前恢复内存中的 `BlockFinalizationRegistry`。 ## 架构 ``` flowchart TD CLI["CLI / App"] --> Runtime["Node Runtime"] Runtime --> Storage["Storage and Reload"] Runtime --> Core["Core State Transition"] Runtime --> Consensus["Consensus and Finality"] Runtime --> P2P["P2P Foundations"] Consensus --> QCStore["FinalizedBlockRecordStore\n(sync/qc/{height}.qc)"] QCStore --> SyncPath["Block Sync\n(QC_REQUIRED fast-path)"] Core --> Economics["Economics"] Economics --> Treasury["Treasury Evidence"] Economics --> Governance["Governance Lifecycle"] Storage --> Audit["Reload and Chain Audit"] Governance --> Treasury ``` 阅读 [架构概述](docs/architecture/architecture-overview.md) 和 [模块映射](docs/architecture/module-map.md)。 ### QC 持久化流程 `FinalizedBlockRecord`(包含 BLS12-381 Quorum Certificate)从四个入口点进行持久化,并在启动时重载: ``` 1. Consensus-driven finalization ConsensusEventLoop → setFinalizedCallback └── persistFinalizedRecord() → sync/qc/{height}.qc 2. Fast-path block sync (QC_REQUIRED) BlockSyncHandler::applyResponses └── finalizationRegistry.recordForHeight() └── persistFinalizedRecord() → sync/qc/{height}.qc 3. Persistent-path batch sync PersistentBlockStateSyncApplier::applyValidatedBatch └── deserialize serializedFinalizedRecord from batch item └── persistFinalizedRecord() → sync/qc/{height}.qc 4. Gossip-received finalized artifact NodeDaemon::processFinalizedArtifacts └── FinalizedBlockRecord::deserialize + verify QC └── FinalizedBlockRecordStore::save() → sync/qc/{height}.qc Startup reload NodeOrchestrator::initOrLoad └── FinalizedBlockRecordStore::loadAll() └── BlockFinalizationRegistry::registerFinalizedBlock() (per record) ``` 由 `buildSyncResponseBatch()` 构建的同步响应包含每个区块的序列化 QC,因此接收方 peer 无需联系第三方即可验证终局性。 ### Daemon 和 Gossip 流程 `NodeDaemon` 封装了 `NodeOrchestrator` 并添加了一个由 tick 驱动的 gossip 处理层: ``` NodeDaemon.tick() ├── NodeOrchestrator.tick() — transport I/O, peer heartbeats, block sync ├── processTransactionGossip() — drain TRANSACTION_GOSSIP inbox │ ├── SeenTransactionCache — LRU+TTL dedup by payloadHash │ ├── PersistentMempoolStore::deserializeGossip() — decode + Ed25519 verify │ ├── TransactionAdmissionValidator — account + domain admission │ └── gossipBroadcast() — relay if newly admitted └── processFinalizedArtifacts() — drain FINALIZED_BLOCK_ARTIFACT inbox ├── FinalizedBlockRecord::deserialize() ├── record.verify() — QC check vs. local validator registry ├── FinalizationRegistry::registerFinalizedBlock() └── FinalizedBlockRecordStore::save() — persist QC to disk ``` `ConsensusEventLoop` 在 `NodeOrchestrator` 内部的一个后台线程中运行。它验证 `BLOCK_PROPOSAL` 消息,在规范链之外保留活跃的候选区块,累积 `PREVOTE` 和 `PRECOMMIT` `VALIDATOR_VOTE` 消息,仅从 PRECOMMIT 投票组装 `QuorumCertificate`,并在达到 Quorum 后将唯一的分布式网络追加操作委托给 `BlockFinalizer`。本地的 `block produce` 命令使用了一个仅限 DEVELOPMENT_LOCAL 的助手,在 testnet-candidate 和生产网络类别上会被拒绝。 ## 文档 从 [docs/README.md](docs/README.md) 开始。 关键入口点: - [项目概述](docs/overview/project-overview.md) - [Proof of Protection](docs/overview/proof-of-protection.md) - [快速开始](docs/getting-started/quick-start.md) - [构建](docs/getting-started/build.md) - [测试](docs/getting-started/testing.md) - [架构概述](docs/architecture/architecture-overview.md) - [持久化区块状态同步](docs/PERSISTENT_BLOCK_STATE_SYNC.md) - [治理投票证据](docs/governance/vote-evidence.md) - [国库执行证据](docs/treasury/treasury-execution-evidence.md) - [安全模型](docs/security/security-model.md) - [路线图](docs/ROADMAP.md) ## 路线图 已完成的基础: - localnet runtime pipeline; - 终局性产物持久化和重载审计; - 货币报告和供应审计基础; - 国库执行证据; - 治理投票证据和生命周期审计; - P2P 传输/gossip/加密通道基础; - testnet-candidate 就绪诊断; - 分布式 node daemon:交易 gossip、带有 proposer 身份验证的区块提案中继、终局性产物 QC 验证; - 持久的 QC 持久化(`FinalizedBlockRecordStore`):QC 证明可在重启后保留,fast-path `QC_REQUIRED` 同步功能齐全,同步响应携带 QC 证明给 peers; - 签名的共识投票恢复:`ConsensusRecoveryStore` 持久化准确的已签名 PREVOTE/PRECOMMIT 记录,以便重启时可以安全地重新提交/重新广播相同的投票,而不会发生重复投票; - 规范的 slashing 惩罚:终局性证据创建一个确定性的惩罚决策,更新 validator 的 jail/tombstone 状态,并向质押注册表应用有界限的 stake slashing; - 实时分布式共识(Phase 2):proposer 选择已接入 daemon,由轮次超时驱动的网络 prevote/precommit,超时时的 proposer 轮换视图切换,所有这些都在真实 TCP 上进行了端到端测试; - 网络强化和 peer 操作(Phase 3):经过身份验证的 peer 握手和加密通道、实时 peer 发现、封禁/隔离、基于消息类型的速率限制、指数退避重连、日蚀攻击子网保护。 进行中: - 官方 testnet runtime 强化; - 生产环境密钥安全和托管边界; - 治理生命周期转换(跨 peers 的提案网络 gossip 尚未接入;决策/执行和审计已实现); - Validator 奖励结算和保护评分。 计划中: - 经过审计的钱包/托管集成; - 基于质押的治理和 validator 经济学; - 完整的生产环境 slashing 生命周期; - Mainnet 就绪门和外部审计流程。 请参阅路线图](docs/ROADMAP.md)。 ## 安全 Nodo 以安全为中心,但不适合生产环境使用。除非未来的版本明确声明这些路径已就绪并通过审计,否则请勿将当前代码用作 mainnet、托管、国库或生产环境 validator 系统。 安全文档: - [SECURITY.md](SECURITY.md) - [安全模型](docs/security/security-model.md) - [威胁模型](docs/security/threat-model.md) - [密钥管理](docs/security/key-management.md) ## 许可证 目前不存在代码库许可证文件。在添加许可证之前,请勿假定拥有超出 GitHub 访问权限所允许的开源再分发权利。 ### 终局性 slashing 证据同步审计 终局性区块同步不再依赖于曾看到过原始 slashing-evidence gossip 的 peer。当同步的终局性区块携带 `SLASHING_EVIDENCE` 记录时,导入路径将重播该区块,验证每个 evidence id 是否恰好产生了一个 `ValidatorPenaltyDecision`,并在发布新的 runtime 状态之前,审计 `ValidatorRegistry` 和 `StakingRegistry` 是否镜像了终局性的 jail/tombstone/slash 效果。如果证据在本地仍处于待处理状态,一旦区块同步完成了对其的惩罚,它就会从待处理证据存储中移除。 ### 强制 P2P 强化边界 实时的 TCP testnet 路径现在将 P2P 安全控制视为强制性的协议准入门,而不是可选的助手。非握手流量必须通过经过身份验证的加密 peer 会话到达,每个信封都要根据网络 ID、链 ID、协议版本、TTL、时钟偏差、重复消息 ID 和 payload hash 进行验证,对每个 peer 和每种消息类型强制执行速率限制,对于屡次滥用的情况将进行隔离并断开 peer 连接,并且在注册之前会通过 `EclipseGuard` 检查 peer 的准入。本地 loopback 测试仍然可以在没有强化配置的情况下实例化 `GossipMesh`,但 `TcpTestnetNodeRuntime` 始终启用强化路径。 ### 发现和重连策略 Bootstrap peers、UDP 发现结果和断开连接的已验证 peers 现在在进行任何 TCP 尝试之前,都会进入一个确定性的重连策略。Daemon 不再通过即时快捷方式连接发现/静态 peers:候选者会被跟踪、植入到发现过程中、通过指数退避进行重试、按 tick 进行封顶,并在 peer 处于隔离状态时予以抑制。这使得 peer 发现在不允许紧密重连循环或绕过强化的 P2P 准入门的情况下依然有用。 ### 经过身份验证的 Peer 交换 Peer 交换现在是一个规范的、经过身份验证的 P2P 消息。节点仅通过经过身份验证的加密会话广播有上限的 `PEER_EXCHANGE` payload,通过严格的 peer-exchange 编解码器解析它们,使用 `EclipseGuard` 筛选每个候选者,将接受的重连候选者与受信任的 peer 元数据分开持久化,并通过 `PeerReconnectionPolicy` 路由每个学习到的 peer,而不是打开直接的 socket。 ### 连接槽策略 TCP testnet 传输现在将连接容量视为一种协议准入策略。待处理的握手依然受总数/IP/子网限制和 token bucket 的限制,而经过身份验证的连接则受总数、入站、出站、每个 IP 和每个 /24 子网槽的限制。当总数或方向性槽位已满时,最旧的可替换连接将被确定性地驱逐;当 IP 或子网饱和时,新 peer 将被拒绝,而不是削弱多样性。这使得发现和 peer 交换依然有用,同时不允许单个地址块占用节点。 ### P2P 信誉和临时封禁 Peer 滥用处理现在是持久的且受时间限制的。反复的无效或速率受限流量会降低 peer 得分,创建审计证据,应用带有 `bannedUntil` 和规范原因的临时封禁,断开与 peer 的连接,在封禁处于活动状态时抑制重连尝试,并在到期后确定性地解除封禁。Peer 惩罚状态连同得分、隔离标志和无效消息计数一起存储在 `peers.conf` 中。标签:Bash脚本, C++, 共识算法, 区块链协议, 去中心化账本, 安全测试工具, 数据擦除, 智能合约, 节点