Aptos 共识组件深度解析:AptosBFT 协议的 3-hop 排序、乐观提案与源码级安全规则
【免费下载链接】aptos-coreAptos is a layer 1 blockchain built to support the widespread use of blockchain through better technology and user experience.项目地址: https://gitcode.com/GitHub_Trending/ap/aptos-core
本文基于 Aptos 仓库中 consensus/README.md 的核心脉络展开,系统讲解 AptosBFT 共识协议的工作原理:轮次与提案(含乐观提案)、QC 形成、Order Vote 的 3-hop 最小排序、超时与视图切换、跨重启持久化的安全规则。读完后你将理解 Aptos 如何在部分同步模型下做到"安全始终保证、同步期活性有保证",并能通过 consensus/safety-rules 与 consensus/consensus-types 的源码定位到每一条安全不变量的落地实现。
一、AptosBFT 协议总览
Aptos 的共识组件(consensus/)实现了基于AptosBFT协议的状态机复制(State Machine Replication):
- 面向n = 3f+1个验证者网络,容忍至多f个拜占庭故障;
- 安全性(Safety)始终成立,活性(Liveness)在同步期(部分同步模型,partial synchrony)保证;
- 协议思想来源于三个方面:Jolteon 论文提出的2-chain commit(两链提交)、order votes(排序投票,对应 AIP-89)、以及乐观提案(optimistic proposals,对应 AIP-131)。
三者分别解决不同问题:2-chain commit 提供提交判定的基础规则,乐观提案把块时间压缩到单跳网络延迟,order votes 则把排序(ordering)做到理论上 BFT 所需的最少 3 跳。下文按协议流程逐段拆解。
二、轮次、提案与乐观提案
共识按轮次(round)推进,每个轮次有一个指定 leader 负责提案。关键优化在**正常路径(happy path)**上:
乐观提案(OptProposal)
传统流程中 leader 必须等到父块的 QC 才能提案,这引入额外等待。AptosBFT 允许 leader 在父块 QC 尚未到达时就提前发出乐观提案——前提是 leader 已经看到过父块提案,并信任它最终会被认证。这样块时间可以压缩到单次网络跳数。
乐观提案的结构与普通提案不同:由于父 QC 尚不存在,它携带的是grandparent_qc(r-2 轮的 QC)而不是父 QC。各验证者将乐观提案缓冲,待父 QC 到达后转换为普通提案,再应用标准安全规则。
从源码可以看到这一结构的落地:opt_proposal_msg.rs 中的OptProposalMsg围绕block_data.grandparent_qc()进行签名校验与轮次检查(例如对grandparent_qc().certified_block().round()的最高认证轮次做断言),验证逻辑即 README 所述"缓冲后转换、再套用标准安全规则"。
普通提案(回退路径)
当乐观提案不可行时(例如出现背压 backpressure,或轮次超时后),leader 回退到普通提案,直接携带父块 QC。对应的消息类型是ProposalMsg(见 proposal_msg.rs)。
投票与 QC 形成
验证者在检查安全规则后对提案投票。投票规则的分离(cleanly separated)是有意为之的可审计性设计——投票逻辑集中在独立的 safety-rules 子组件中。在解耦执行(decoupled execution)下,投票的对象是提案块本身,而非执行结果;执行在排序之后异步进行。
2f+1 个投票构成一个 Quorum Certificate(QC),证明超级多数已就某个块达成一致。QC 的结构见 quorum_cert.rs。
三、Order Vote:3-hop 理论最小排序
这是 AptosBFT 相对经典 HotStuff 系协议的关键改进。形成 QC(r) 后,验证者立即向所有验证者广播一个针对该 QC 的排序投票(order vote);收齐 2f+1 个 order vote 即完成块 r 的排序。整个正常路径为 3 跳:
- Leader 提出 B(r)(乐观提案,不等父 QC);
- 验证者对 B(r) 投票;
- QC(r) 形成,验证者广播对 QC(r) 的 order vote;
- 收齐 2f+1 个 order vote → 块 r 排序完成。
2f+1 个 order vote 共同构成一个WrappedLedgerInfo——即提交证书(commit certificate)。从源码看,wrapped_ledger_info.rs 中WrappedLedgerInfo由vote_data与signed_ledger_info两部分组成,其中vote_data字段被明确标注为向后兼容的占位符:当 order votes 启用时,vote_data与consensus_data_hash不再参与校验逻辑,可设为 dummy 值。这个设计保证了启用 order vote 的升级对旧格式数据仍保持兼容。
Order Vote 本体定义在 order_vote.rs:每个OrderVote包含投票者author、被排序块的LedgerInfo及其 BLS 签名。其verify方法还强制要求consensus_data_hash为零值——因为 order vote 语义上只关心"该块将被排序"这一事实,不携带共识数据哈希。
Order Vote 的安全规则:safe_for_order_vote
safe_for_order_vote规则防止验证者在某轮已经超时之后再对该轮进行 order vote(通过持久化的highest_timeout_round追踪)。如果不加此约束,同一轮次可能在不同 fork 上产生互相冲突的排序决定。
2-chain commit:无 order vote 时的回退规则
如果 order votes 未启用(或尚未形成),则退回经典的2-chain commit 规则:当 B(r) 拥有 QC、且其直接子块 B(r+1) 也拥有 QC 时,B(r) 被提交。该规则实现于 safety_rules_2chain.rs。
四、超时、视图切换与活性保证
当某轮次在超时时限内未形成 QC 时,进入非正常路径(unhappy path):
- 验证者广播
RoundTimeout消息,其中携带自己当前看到的最高 QC 以及超时签名; - 收到f+1 个来自其他验证者的超时消息即可触发本地超时,加速轮次推进,无需等满整个超时时长;
- 2f+1 个超时签名构成
TwoChainTimeoutCertificate(TC,两链超时证书); - TC 允许下一轮 leader在没有上一轮 QC 的情况下继续提案,保证协议活性。
源码印证:timeout_2chain.rs 中TwoChainTimeout携带epoch、round与签名者持有的最高quorum_cert,验证时强制hqc_round < round(超时轮必须大于其 QC 的轮次);TwoChainTimeoutCertificate则聚合了带轮次的签名集合(AggregateSignatureWithRounds)。
轮次状态(RoundState)
RoundState是轮次推进的驱动器。NewRoundEvent由两种事件触发:收到 QC(正常路径)或收到 TC(非正常路径)。超时采用指数退避:base_ms * exponent_base^min(round_index, max_exponent)。从 round_state.rs 可以看到base_ms字段与超时时长按倍数递增的计算逻辑,与该公式一致。
领导选举
支持多种策略:轮转(round-robin)与基于信誉(reputation-based)——连续未能出块的验证者会被降权惩罚。相关代码见 proposer_election.rs(选举 trait)与 leader_reputation.rs(信誉机制)。
活性条件:为什么需要两个连续的诚实 leader
一个值得注意的活性细节:GST(全局稳定时间)之后,需要两个连续的诚实 leader 才能排定一个块——因为第一个 leader 发出乐观提案,第二个 leader 在其上构建块。若不使用乐观提案,一个诚实 leader 就足够了。这是乐观提案换取延迟降低所付出的活性代价,设计权衡非常清晰。
五、跨重启持久化的安全规则
共识运行在**纪元(epoch)**内:一个 epoch 定义验证者集合与配置;当链上 reconfiguration 交易被提交时,当前 epoch 结束、新 epoch 开始,所有共识状态(轮次、QC、块树)在 epoch 边界重置。
正因 epoch 会重置,且节点会重启,安全规则的状态必须持久化到本地存储。三个核心字段(定义于 safety_data.rs 的SafetyData结构):
pub struct SafetyData { pub epoch: u64, pub last_voted_round: u64, // 防止同轮重复投票(无双重投票) pub preferred_round: u64, // 最高 2-chain 头部轮次 pub one_chain_round: u64, // 最高 1-chain 轮次(新增,serde 默认值保证旧数据可反序列化) pub last_vote: Option<Vote>, pub highest_timeout_round: u64, // 防止超时后再 order vote }源码注释与 README 的表述精确对应:
last_voted_round—— 禁止双重投票(no equivocation):验证者在同一轮最多投一票;preferred_round—— 优先轮次约束:只允许对"父 QC 轮次 >= preferred_round"的块投票,其中 preferred_round 取自已见最高 2-chain 头部的轮次,防止对可能与已提交块冲突的 fork 投票;highest_timeout_round—— order vote 安全:防止验证者在已超时的轮次上再投 order vote。
从 safety_rules.rs 的observe_qc方法可以看到状态如何随 QC 更新:观察到一个 QC 时,用 QC 认证的块轮次(1-chain)更新one_chain_round,用 QC 父块轮次(2-chain)更新preferred_round。此外verify_proposal在执行任何投票前会依次做 epoch 检查、QC 验证、提案者 BLS 签名验证与格式良好性检查,把验证尽量前置。
SafetyData还内置了一个升级兼容性测试:旧的四个字段结构可以通过#[serde(default)]默认值平滑反序列化为新结构,印证了"安全状态必须跨版本、跨重启稳定"的工程要求。
六、组件架构
共识组件采用Actor 编程模型——子组件间通过消息传递通信,以 tokio 作为任务运行时。唯一的例外是被多个子组件并发访问的共享数据结构BlockStore。README 中的架构图如下:
Network Layer | +--------v---------+ | EpochManager | Lifecycle: epoch init, validator set, channels +--------+---------+ | +--------v---------+ | RoundManager | Core event loop: proposals, votes, timeouts +--------+---------+ | +------------------+------------------+ | | | +-------v------+ +-------v-------+ +-------v--------+ | BlockStore | | SafetyRules | | RoundState | | (block tree) | | (vote rules, | | (timeouts, | | | | persistence) | | round mgmt) | +--------------+ +---------------+ +----------------+ | +--------------+ +--------v--------+ | PendingVotes | | ProposalGen + | | + OrderVotes | | ProposerElect | | (aggregation)| | (leader duty) | +--------------+ +-----------------+各子组件职责:
| 子组件 | 职责 |
|---|---|
| EpochManager | 纪元生命周期管理、验证者集合初始化、子组件间通道(channel)接线。见 epoch_manager.rs |
| RoundManager | 核心事件处理器——处理所有共识消息(提案、投票、超时)并驱动协议。见 round_manager.rs |
| BlockStore | 维护提案块树、块执行状态、投票、QC 与持久化存储,并保证这些数据结构组合的一致性;可被其他子组件并发访问 |
| RoundState | 负责共识活性:因 TC 或 QC 切换轮次,并在自己是当前轮 leader 时提案 |
| SafetyRules | 负责共识安全:处理 QC 与 LedgerInfo 以学习新提交,并保证即使在重启后投票规则依然被遵守(安全数据全部持久化) |
| PendingVotes / PendingOrderVotes | 将投票聚合为 QC、TC 与提交证书 |
所有共识消息都由发送者签名、由接收者验证;消息验证尽量贴近网络层(见 network.rs)进行,避免无效或多余的数据进入共识协议主体。
共识消息类型
| 消息 | 用途 | 正常路径下的发送方 → 接收方 |
|---|---|---|
ProposalMsg | 携带父 QC 的块提案 | Leader → 全体验证者 |
OptProposalMsg | 乐观提案(父 QC 尚未存在) | Leader → 全体验证者 |
VoteMsg | 对提案的投票 | 验证者 → 全体验证者 |
OrderVoteMsg | 对 QC 的排序投票 | 验证者 → 全体验证者 |
RoundTimeoutMsg | 携带最高 QC 的超时投票 | 验证者 → 全体验证者 |
SyncInfo | 同步元数据(最高 QC、TC、提交点) | 搭载在其他消息上传输 |
七、五条安全不变量
README 以独立章节列出了整个共识组件必须维护的安全不变量,这是阅读consensus/代码时的检查清单:
- 禁止双重投票(No equivocation):每个轮次最多投一票,由持久化的
last_voted_round强制; - 优先轮次(Preferred round):只对父 QC 轮次 >=
preferred_round的块投票,防止对可能与已提交链冲突的 fork 投票; - Order vote 安全:不得对已超时的轮次投 order vote(
highest_timeout_round检查),防止跨 fork 的冲突排序决定; - 确定性执行:所有验证者对同一排序块序列必须产生相同的执行结果。推论:当迭代顺序影响序列化时,必须使用确定性数据结构(如
BTreeMap而非HashMap); - 滚动部署安全:滚动升级期间,所有节点无论代码版本新旧,都必须产生相同的
BlockMetadataTransaction;新行为应通过链上 feature flag 门控。
八、关键配置参数
共识的关键参数分布在ConsensusConfig(节点侧)与链上OnChainConsensusConfig(链上侧)中:
| 参数 | 作用 |
|---|---|
max_block_txns | 单个提案块允许的最大交易数 |
max_receiving_block_txns | 接收到的块中允许的最大交易数(防御性上限) |
round_initial_timeout_ms | 轮次基础超时(指数退避的base_ms) |
round_timeout_backoff_exponent_base | 超时指数退避的底数 |
round_timeout_backoff_max_exponent | 超时退避的最大指数(封顶,防止退避无限增长) |
enable_optimistic_proposal_rx | 是否接收乐观提案 |
enable_optimistic_proposal_tx | 是否发送乐观提案 |
order_vote_enabled | 是否启用 order vote 的 3-hop 排序 |
值得注意的是接收(rx)与发送(tx)两个开关被独立拆分——这使得运维可以对乐观提案进行渐进式、不对称的启用:先全网开启接收能力,再逐节点开启发送,从而在滚动部署中安全地引入新行为(与上文不变量第 5 条一脉相承)。
九、模块组织与源码导航
核心共识
| 文件 | 用途 |
|---|---|
| consensus/src/round_manager.rs | 核心事件处理器——处理所有共识消息 |
| consensus/src/epoch_manager.rs | 纪元生命周期、验证者集合初始化、通道接线 |
| consensus/src/network.rs | 网络消息发送/接收 |
| consensus/src/pending_votes.rs | 投票聚合 → QC/TC 形成 |
| consensus/src/pending_order_votes.rs | Order vote 聚合 |
| consensus/src/state_computer.rs | 执行接口 |
块存储
| 文件 | 用途 |
|---|---|
| consensus/src/block_storage/block_store.rs | 块树、QC 跟踪、执行状态 |
| consensus/src/block_storage/block_tree.rs | 带父块/QC 链接的树结构 |
| consensus/src/block_storage/sync_manager.rs | 缺失块的同步 |
活性(Liveness)
| 文件 | 用途 |
|---|---|
| consensus/src/liveness/round_state.rs | Pacemaker——轮次推进、超时 |
| consensus/src/liveness/proposal_generator.rs | 块提案生成、背压处理 |
| consensus/src/liveness/proposer_election.rs | Leader 选举 trait |
| consensus/src/liveness/leader_reputation.rs | 基于信誉的 leader 选择 |
安全(Safety)
| 文件 | 用途 |
|---|---|
| consensus/safety-rules/src/safety_rules.rs | 投票规则——防止双重投票 |
| consensus/safety-rules/src/safety_rules_2chain.rs | 2-chain 超时规则 |
| consensus/safety-rules/src/consensus_state.rs | 持久化安全状态 |
共识类型(consensus-types)
| 文件 | 用途 |
|---|---|
| consensus/consensus-types/src/block.rs | 块结构 |
| consensus/consensus-types/src/quorum_cert.rs | QuorumCert(2f+1 个投票签名) |
| consensus/consensus-types/src/vote.rs | 投票消息 |
| consensus/consensus-types/src/order_vote.rs | Order vote(3-hop 排序) |
| consensus/consensus-types/src/wrapped_ledger_info.rs | 由 order votes 构成的提交证书 |
| consensus/consensus-types/src/timeout_2chain.rs | 超时证书 |
| consensus/consensus-types/src/opt_proposal_msg.rs | 乐观提案消息 |
| consensus/consensus-types/src/safety_data.rs | 持久化安全状态 |
| consensus/consensus-types/src/payload.rs | 负载类型(DirectMempool、QuorumStore 等) |
相关子系统
两个与共识紧密协作但独立演进的方向,README 建议参阅其各自的说明:
- consensus/src/pipeline —— 解耦执行流水线(execute、sign、persist、broadcast 四段并行);
- consensus/src/quorum_store —— QuorumStore 数据分发通道。
目录结构
consensus ├── src │ ├── block_storage # 块及相关数据结构的内存存储 │ ├── consensusdb # 数据库交互,持久化共识安全与活性数据 │ ├── liveness # RoundState、proposer 等活性相关代码 │ ├── pipeline # 解耦执行流水线 │ ├── quorum_store # 用于数据分发的 QuorumStore │ └── test_utils # 仅供测试使用的 Mock 实现 ├── consensus-types # 共识数据类型(如 quorum certificate) └── safety-rules # 安全(投票)规则十、测试与验证方式
按 README 提供的命令,可以在本地对共识组件进行分层验证:
cargo test -p aptos-consensus # 共识单元测试 cargo test -p aptos-consensus-types # 类型测试 cargo test -p aptos-safety-rules # 安全规则测试 cargo test -p smoke-test # E2E 冒烟测试 # Forge 测试:见 testsuite/forge-cli/src/suites/其中 consensus/src/round_manager_tests 包含针对轮次管理器的集成测试(如consensus_test.rs覆盖超时与 order vote 场景),consensus/safety-rules/src/tests 则针对安全规则做定向验证,是理解各不变量行为边界的最直接入口。
小结
Aptos 共识组件的设计可以概括为三条主线:
- 延迟最优化:乐观提案(省一跳)+ order votes(3-hop 排序)将正常路径压缩到理论最小跳数,代价是活性需要两个连续诚实 leader;
- 安全可审计:投票规则集中在独立的 safety-rules 组件,
SafetyData三字段(last_voted_round、preferred_round、highest_timeout_round)全部持久化,重启与 epoch 切换不破坏安全性; - 工程可演进:rx/tx 独立开关、
WrappedLedgerInfo的向后兼容占位字段、SafetyData的 serde 默认值升级测试,都为滚动部署中的渐进式协议升级提供了明确的实现路径。
【免费下载链接】aptos-coreAptos is a layer 1 blockchain built to support the widespread use of blockchain through better technology and user experience.项目地址: https://gitcode.com/GitHub_Trending/ap/aptos-core
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考