
Aptos Quorum Store 深度解析基于 Narwhal 的交易分发层、乐观 Quorum Store 与批量生命周期【免费下载链接】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本文围绕 consensus/src/quorum_store/README.md 展开系统讲解 Aptos 共识模块中的 Quorum StoreQS子系统的协议设计、组件职责与核心数据结构并结合 consensus/src/quorum_store/ 下的源码实现与 config/src/config/quorum_store_config.rs 中的配置参数还原批量batch从生成、签名、聚合证明到进入共识提案的完整链路。读完后你将理解 Aptos 如何将交易分发从领导者单点瓶颈转变为全体验证者并行广播并能读懂 BatchProofQueue、BatchStore、BatchRequester 等关键组件的源码逻辑与默认配置。一、Quorum Store 要解决的问题Quorum StoreQS是 Aptos 基于 Narwhal 论文思想实现的数据分发层其核心目标是把交易分发与共识排序解耦没有 QS 时共识领导者leader是瓶颈——它必须从 mempool 拉取交易再在自己的提案proposal中把完整交易广播给所有验证者有了 QS 后每个验证者持续创建交易**批量batch**并广播给所有对端当某个 batch 获得 2f1 个验证者签名后就形成一个Proof of StorePoS证明该 batch 的数据已可用领导者随后在提案中只引用 batch 的摘要PoS而不再携带原始交易。这样做的好处是充分利用所有验证者的网络带宽并显著压缩提案体积。设计背景可参考 AIP-26原始设计与 AIP-106Optimistic Quorum Store。在代码层面QS 是aptos-consensuscrate 的一个子模块其模块声明见 mod.rspub mod counters; /// Equivalent to directly fetching blocks from mempool without a quorum store. pub mod direct_mempool_quorum_store; pub(crate) mod batch_coordinator; pub(crate) mod batch_generator; pub(crate) mod batch_proof_queue; pub(crate) mod batch_requester; pub(crate) mod batch_store; pub(crate) mod network_listener; pub(crate) mod proof_coordinator; pub(crate) mod proof_manager; pub(crate) mod quorum_store_builder; pub(crate) mod quorum_store_coordinator; pub mod quorum_store_db; pub(crate) mod tracing; pub mod types; pub(crate) mod utils;值得注意的是direct_mempool_quorum_store它提供了不走 Quorum Store、直接从 mempool 取交易的等价实现路径说明 QS 在架构上被抽象为一种可替换的交易来源后端。二、Optimistic Quorum Store乐观 Quorum Store标准 QS 流程中领导者必须等到 2f1 个签名凑齐 PoS 之后才能把 batch 放进提案。AIP-106 引入的 Optimistic QS 去掉了这个等待领导者直接提案不带证明的 batch 摘要batch summaries without proofs由于 batch 作者已把 batch 数据广播给所有验证者从网络三角不等式的角度看batch 数据大概率会先于或同时于领导者提案到达各验证者若某验证者本地没有该 batch则通过BatchRequester从 batch 作者或 PoS 签名者处拉取始终凑不齐证明的 batch 会在过期后被垃圾回收。提案负载类型OptQuorumStorePayload因此分为三层层级内容特点Proof batches带完整 PoS 的 batch数据可用性由签名者保证Optimistic batches不带证明的 batch 摘要延迟更低缺失时按需拉取Inline batches直接内联的完整交易用于证明队列被占满时的兜底对应配置开关在 config/src/config/quorum_store_config.rs 中pub allow_batches_without_pos_in_proposal: bool, // 默认 true pub enable_opt_quorum_store: bool, // 默认 true pub opt_qs_minimum_batch_age_usecs: u64, // 默认 50ms pub enable_payload_v2: bool, // 默认 false pub enable_batch_v2_tx: bool, // 默认 true pub enable_batch_v2_rx: bool, // 默认 true pub enable_opt_qs_v2_payload_tx: bool, // 默认 true pub enable_opt_qs_v2_payload_rx: bool, // 默认 true其中opt_qs_minimum_batch_age_usecs默认 50ms控制batch 至少要存活多久才允许以乐观方式被引用给数据到达留出窗口。三、协议批量生命周期Batch LifecycleREADME 将批量生命周期拆为四个阶段下面逐阶段结合源码印证。3.1 批量创建BatchGenerator职责见 batch_generator.rs以可配置间隔从 mempool 拉取交易handle_scheduled_pull通过MempoolProxy发送QuorumStoreRequest按 gas price 降序排序并分桶到batch_buckets各气价区间同时遵守单批大小限制sender_max_batch_txns、sender_max_batch_bytes分配单调递增的BatchId——首次启动时BatchId初始化为当前时间戳微秒值并持久化到本地 DBdb.save_batch_id重启时从 DB 恢复并 1保证唯一性把 batch 持久化到本地 DBbatch_writer.persist向所有验证者广播BatchMsgV1 走broadcast_batch_msg开启 Batch V2 时走broadcast_batch_msg_v2。几个从源码可见的实现细节去重txns_in_progress_sortedBTreeMapTransactionSummary, TransactionInProgress记录已在进行中的交易摘要避免同一交易被重复打进多个 batchmempool 拉取时会传入该集合做排除BATCH_PULL_EXCLUDED_TXNS指标记录排除数量分桶process_transaction_group从高到低遍历batch_buckets用二分查找定位每个桶中的交易最终零桶兜底超限保护单个交易超过sender_max_batch_bytes时会被跳过并打 warn 日志BATCH_GENERATOR_SKIPPED_OVERSIZED_TXN计数批处理上限单轮拉取最多生成sender_max_num_batches个 batch。3.2 批量接收BatchCoordinator收到远端BatchMsg后batch_coordinator.rs校验大小限制与交易过滤条件持久化到BatchStore用本节点验证者私钥对 batch 元数据签名生成SignedBatchInfo把SignedBatchInfo回送给 batch 作者不是广播给所有人——签名聚合只发生在作者侧。BatchMsg的合法性校验在 types.rs 中实现核心检查包括消息非空、batch 数不超过receiver_max_num_batches、作者必须是当前 epoch 的合法验证者、作者必须等于发送者防止转发他人 batch、以及逐 batch 校验 payload 作者/摘要/交易数/字节数/气价一致。3.3 证明聚合ProofCoordinator见 proof_coordinator.rs收集各验证者回传的SignedBatchInfo使用SignatureAggregator聚合签名凑齐 2f1 个签名后形成ProofOfStore对 batch 元数据的聚合 BLS 签名向所有验证者广播ProofOfStore。3.4 证明入队ProofManagerProofManagerproof_manager.rs负责把ProofOfStore插入BatchProofQueue队列按作者author和气价桶gas bucket组织实现公平的优先拉取用TxnSummary出现次数occurrence count跨 batch 去重交易收到 proof 时会估算 batch 年龄超过 500ms 未收到证明就打SlowProofReceipt告警日志用于发现慢证明的离群点。四、共识集成Proposal 如何拿到交易当领导者要创建提案时调用链如下ProposalGenerator向ProofManager发送GetPayloadCommandProofManager从BatchProofQueue依次拉取三层内容Proof batches带完整ProofOfStore的 batch可用性有保证Optimistic batches仅 batch 摘要OptQS延迟更低Inline batches队列有余量时直接内联完整交易返回包含全部三类内容的OptQuorumStorePayload验证者执行阶段若发现本地缺 batch则用 PoS 上的签名者列表作为应答源从对端拉取。源码中这一过程被组织为PullSessionbatch_proof_queue.rs它跨三次顺序拉取proofs → optimistic → inline累积已选 batch 集合与已选交易摘要避免重复计算和重复选取并支持按BatchKind分别统计拉取数量PerBatchKindTxnLimits。五、反压机制BackpressureProofManager跟踪两个水位remaining_total_txn_num与remaining_total_proof_num。当任一水位超过阈值backlog_txn_limit_count/backlog_per_validator_batch_limit_count就向BatchGenerator发送反压信号。源码中该水位采样每 200ms 执行一次sample!(SampleRate::Duration(Duration::from_millis(200)), ...)见 proof_manager.rs避免每收一个 proof 都更新。BatchGenerator收到信号后batch_generator.rs按 AIMD 思路调节拉取速率dynamic_pull_txn_per_s拥塞时乘法减每decrease_duration_ms默认 1000ms执行一次×decrease_fraction默认 0.5下限dynamic_min_txn_per_s默认 160无拥塞时加法增每increase_duration_ms增加additive_increase_when_no_backpressure默认 2000上限dynamic_max_txn_per_s默认 12000。每轮 tick 的实际拉取上限还受距上次非空拉取的时间约束batch_generation_min_non_empty_interval_ms/batch_generation_max_interval_ms避免无谓高频拉取。六、Batch V2 与交易分类Batch V2 为 batch 引入交易分类字段BatchKindNormal或Encrypted由enable_batch_v2_tx/enable_batch_v2_rx分别控制创建与接收路径。从 batch_generator.rs 可以看到分类逻辑集中在categorize_transaction/// Categorize a transaction to determine its batch kind. /// This is the central place to add new categorization logic. fn categorize_transaction(txn: SignedTransaction) - BatchKind { if txn.is_encrypted_txn() { BatchKind::Encrypted } else { BatchKind::Normal } }开启 V2 后拉取到的交易先按 kind 分组、各组内按 gas 降序排序再按Normal → Encrypted的顺序处理保证向后兼容并优先普通交易加密批次的单笔上限独立为sender_max_encrypted_batch_txns默认 64小于普通批次的 50 上限独立配置以保护解密管道。V1 路径则会过滤掉加密交易并打 error 日志。V1/V2 消息互斥性由测试保护types.rs 的verify_v2_rejects_v1_batch_in_batch_msg_v2验证BatchMsgV2中混入 V1 batch 会被拒绝Non-V2 batch in BatchMsgV2。七、核心数据结构详解7.1 QuorumStoreCoordinator顶层编排quorum_store_coordinator.rs 运行主循环处理CoordinatorCommandCommitNotification(block_timestamp, batches)—— 扇出到ProofCoordinator、ProofManager和BatchGenerator各自对已提交 batch 做垃圾回收并更新时间戳。BatchGenerator侧batch_generator.rs还会处理两种回收已提交 batch 从batches_in_progress移除以及按时间戳过期回收若同一 batch 存在更高过期时间则重新入堆。Shutdown(ack_tx)—— 按逆管道顺序优雅关停网络监听器 → proof manager → proof coordinator → batch coordinator → batch generator确保发送者先于接收者关闭。7.2 BatchProofQueue公平、去重、可过期batch_proof_queue.rs 是 QS 的核心队列源码结构印证了 README 的四点描述pub struct BatchProofQueue { my_peer_id: PeerId, // Queue per peer for batches WITH proofs author_to_proof_batches: HashMapPeerId, BTreeMapBatchSortKey, BatchInfoExt, // Queue per peer for batches WITHOUT proofs author_to_non_proof_batches: HashMapPeerId, BTreeMapBatchSortKey, BatchInfoExt, // Map of Batch key to QueueItem containing Batch data and proofs items: HashMapBatchKey, QueueItem, // Number of unexpired and uncommitted proofs in which the txn_summary // (sender, replay protector, hash, expiration) has been included. txn_summary_num_occurrences: HashMapTxnSummaryWithExpiration, u64, // Expiration index expirations: TimeExpirationsBatchSortKey, batch_store: ArcBatchStore, ... }排序BatchSortKey按(gas_bucket_start ASC, batch_id DESC)组织——高 gas 桶先被拉取桶内新 batch 优先按对端公平每个作者有独立BTreeMap防止单个验证者垄断队列去重txn_summary_num_occurrences以(sender, replay_protector, hash, expiration)为 key 统计跨 batch 出现次数拉取时已见交易按重复计算并从有效批量中扣除过期TimeExpirations二叉堆跟踪 batch 生命周期handle_updated_block_timestamp时批量移除过期项并递减交易计数防御性校验insert_proof会拒绝已过期的 PoSPOS_EXPIRED_LABEL、与队列中已有BatchInfo不一致的碰撞POS_COLLISION_LABEL、以及重复/已提交的插入POS_DUPLICATE_LABEL防止同一(author, batch_id)被不同摘要污染。7.3 BatchStore配额制持久化batch_store.rs 提供内存缓存 DB 的持久化存储并对每个对端设配额防止资源垄断配额体系每个 peer 有QuotaManager跟踪db_balance、memory_balance、batch_balance两种存储模式见 types.rsMemoryAndPersisted—— 内存缓存 DB首选PersistedOnly—— 内存配额耗尽时仅写 DB元数据留缓存两种配额都耗尽则拒绝并发使用DashMap做无锁并发访问锁定顺序为先缓存条目、后对端配额以避免死锁订阅机制batch 尚未到达时调用方通过subscribe()注册batch 到达后经 oneshot 通道通知所有订阅者——这解决了拉取 batch与接收 batch两条路径之间的竞态BatchRequester正是依赖该通道启动引导bootstrap启动时从 DB 加载上一 epoch 遗留 batchGC 掉已过期的再回填内存缓存。7.4 BatchRequester缺失批量的按需拉取batch_requester.rs 在验证者需要本地没有的 batch 时介入源码完整印证了 README 描述的策略请求策略BatchRequesterState::next_request_peers首次随机选一个起始签名者确保不同节点请求自不同集合之后重试时循环遍历 PoS 签名者最多retry_limit次每轮并发向request_num_peers个验证者发送BatchRequest完成条件request_batch的tokio::select!收到合法BatchResponse::Batch/BatchV2收到BatchResponse::NotFound(ledger_info)且其中ledger_info的提交时间戳已超过 batch 过期时间并通过了签名验证——即链已走远batch 逻辑过期短路返回CouldNotGetDatasubscriber_rx收到订阅通知另一条代码路径已把 batch 取到超过retry_limit后超时失败。相关的核心类型Batch、BatchRequest、BatchResponse、BatchMsg定义在 types.rs其中BatchResponse有三态pub enum BatchResponse { Batch(BatchBatchInfo), NotFound(LedgerInfoWithSignatures), BatchV2(BatchBatchInfoExt), }Batch.verify()还会强校验 payload 作者与元数据一致、payload 哈希等于摘要、交易数/字节数一致、每笔交易 gas 价不低于gas_bucket_start并校验交易种类与BatchKind匹配。八、配置参数全解QuorumStoreConfigQS 的全部可调参数集中在 config/src/config/quorum_store_config.rs。默认值如下表对应源码中的Default实现8.1 基础参数参数默认值含义channel_size1000组件间消息通道容量proof_timeout_ms10000证明聚合超时超时后 batch 放弃并允许交易被重新拉取batch_generation_poll_interval_ms25批量生成轮询间隔batch_generation_min_non_empty_interval_ms50无 proof 反压时的最小非空拉取间隔batch_generation_max_interval_ms250强制拉取间隔上限8.2 发送侧限制BatchGenerator参数默认值含义sender_max_batch_txns50单 batch 最大交易数sender_max_encrypted_batch_txns64单加密 batch 最大交易数sender_max_batch_bytes1MB - 160B单 batch 最大字节数扣除BATCH_PADDING_BYTESsender_max_num_batches10单轮拉取最多生成的 batch 数sender_max_total_txns1500单轮从 mempool 拉取的最大交易数sender_max_total_bytes4MB - 10×160B单轮拉取的最大字节数8.3 接收侧限制BatchCoordinator参数默认值含义receiver_max_batch_txns100收到的单 batch 最大交易数receiver_max_encrypted_batch_txns64收到的单加密 batch 最大交易数receiver_max_batch_bytes1MB 160B收到的单 batch 最大字节数receiver_max_num_batches20单条BatchMsg最多含 batch 数receiver_max_total_txns2000单条BatchMsg最大交易数receiver_max_total_bytes4MB 10 160B单条BatchMsg最大字节数remote_batch_coordinator_channel_size10每作者远程 batch 入口队列容量num_workers_for_remote_batches10处理远程 batch 消息的 worker 数接收上限刻意大于发送上限为 ULEB128 编码等留出余量且ConfigSanitizer会强制校验发送限制 ≤ 接收限制、单批限制 ≤ 总量限制违规配置直接拒绝启动见 sanitize 实现 及同文件的测试模块。8.4 请求与过期参数默认值含义batch_request_num_peers5每次并发请求的对端数batch_request_retry_limit10请求重试上限batch_request_retry_interval_ms500重试间隔batch_request_rpc_timeout_ms5000单次 RPC 超时batch_expiry_gap_when_init_usecs60s本地创建 batch 的过期窗口remote_batch_expiry_gap_when_init_usecs500ms远程 batch 的过期窗口交易已被过滤防重memory_quota/db_quota/batch_quota1.2e8 / 3.0e8 / 3.0e5每 peer 的内存/DB/batch 配额8.5 反压参数QuorumStoreBackPressureConfig参数默认值含义backlog_txn_limit_count36000剩余总交易数超过此值触发反压约等于目标 TPS × 出块延迟秒数backlog_per_validator_batch_limit_count20单验证者剩余 batch 数超过此值触发反压decrease_fraction0.5乘法减系数dynamic_min_txn_per_s/dynamic_max_txn_per_s160 / 12000动态拉取速率下限/上限additive_increase_when_no_backpressure2000无反压时每秒加法增量源码中还提供了面向 DAG 场景的独立默认集default_for_dag()单批 300 笔、单批 4MB、反压速率区间 100~200 txn/s 等其注释解释了原因DAG 中每个验证者可向每一轮贡献batch 需小到能塞进一个 DAG 节点且只需为自提案生成足够 batch。九、网络消息类型与架构图9.1 消息类型消息用途发送方 → 接收方BatchMsg一批交易创建者 → 所有验证者SignedBatchInfo验证者对 batch 的签名接收方 → batch 作者ProofOfStoreMsg聚合证明2f1 签名作者 → 所有验证者BatchRequest按摘要请求缺失 batch任意验证者 → PoS 签名者BatchResponsebatch 负载或 NotFound带LedgerInfoWithSignatures签名者 → 请求方网络路由由 network_listener.rs 负责把上述消息分发到对应 handler持久化层由 quorum_store_db.rs 实现QuorumStoreStoragetrait负责 batch 存取、batch_id 维护与清理。9.2 组件架构┌──────────────────────────────────────────┐ │ QuorumStoreCoordinator │ │ (dispatches commands to all components) │ └──────┬──────┬──────┬──────┬──────────────┘ │ │ │ │ ┌────────────▼┐ ┌──▼──────▼──┐ ┌▼──────────────┐ │ Batch │ │ Proof │ │ Proof │ Mempool ──► │ Generator │ │ Coordinator│ │ Manager │◄── GetPayloadCommand │ (create │ │ (aggregate │ │ (queue │ (from consensus) │ broadcast)│ │ signatures│ │ pull proofs)│ └─────────────┘ │ → PoS) │ └───────────────┘ └────────────┘ ┌─────────────┐ Network ──► │ Batch │ ┌────────────┐ │ Coordinator │ │ Batch │ │ (receive │ │ Store │ │ sign ├─►│ (persist │ │ persist) │ │ cache) │ └─────────────┘ └────────────┘ ┌─────────────┐ Network ──► │ Network │ Routes: BatchMsg → BatchCoordinator │ Listener │ SignedBatchInfo → ProofCoordinator └─────────────┘ ProofOfStoreMsg → ProofManager数据流可概括为Mempool → BatchGenerator造批广播→ BatchCoordinator收批签名→ ProofCoordinator聚合 PoS→ ProofManager入队供提案反压BatchStore承担持久化底座BatchRequester兜底缺失数据NetworkListener负责消息路由QuorumStoreCoordinator统一分发CommitNotification/Shutdown。十、验证方式运行 QS 测试QS 的全部单元测试位于 consensus/src/quorum_store/tests/覆盖每个核心组件tests/ ├── batch_coordinator_test.rs ├── batch_generator_test.rs ├── batch_proof_queue_test.rs ├── batch_requester_test.rs ├── batch_store_test.rs ├── direct_mempool_quorum_store_test.rs ├── mod.rs ├── network_listener_test.rs ├── proof_coordinator_test.rs ├── proof_manager_test.rs ├── quorum_store_db_test.rs └── types_test.rs运行方式与 README 一致cargo test -p aptos-consensus -- quorum_store例如batch_proof_queue_test.rs验证排序、去重与过期行为batch_requester_test.rs验证重试与订阅竞态batch_generator_test.rs验证分桶与反压调整——这些测试是理解各组件契约的最直接入口。十一、小结Aptos 的 Quorum Store 用全员并行分发 BLS 聚合证明 按需拉取兜底替代了领导者串行广播交易BatchGenerator把 mempool 交易按 gas 分桶打包并广播配合 AIMD 反压自适应调节吞吐BatchCoordinator ProofCoordinator完成签名回送—聚合 2f1的可用性证明闭环ProofManager BatchProofQueue以气价优先、按作者公平、跨批去重的方式向共识供给交易并通过乐观 batch 省去等待证明的时间BatchStore BatchRequester用配额持久化 订阅通知 签名者轮询拉取保证数据最终可取。整套设计让提案体积从全量交易降为摘要 证明同时以过期回收batch_expiry_gap_when_init_usecs和配额memory/db/batch quota约束了资源边界是 Aptos 高吞吐低延迟网络层的支柱性组件之一。【免费下载链接】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),仅供参考