- 区块链
【免费下载链接】polkadot
Polkadot Node Implementation
导读
candidate_pending_availability是 Polkadot 中继链ParachainHost运行时 API 家族中的一员,用于按ParaId查询正处于“等待可用性(pending availability)”状态的候选区块收据(CommittedCandidateReceipt)。本文以其在 implementers-guide 中的定义为主线,结合本仓库的运行时实现、inclusion 模块存储结构与节点子系统调用链,说明该 API 的语义、数据来源、节点侧消费方式及典型应用场景,帮助读者理解中继链上候选区块从“被背书”到“可用性确认”这一关键状态的数据面。
一、API 签名与语义:从文档定义出发
implementers-guide 中对该 API 的定义非常简洁,只有一条函数签名:
fn candidate_pending_availability(at: Block, ParaId) -> Option<CommittedCandidateReceipt>;其文档语义为:
Get the receipt of a candidate pending availability. This returns
Somefor any paras assigned to occupied cores inavailability_coresandNoneotherwise.
即:返回指定平行链(Para)当前正处于“等待可用性”阶段的候选区块收据。判定规则与核心(core)状态直接挂钩——只有当该 Para 被分配到了availability_cores中某个“被占用(occupied)”的核心时,才返回Some;否则返回None。
这一语义在中继链运行时原语库 primitives/src/runtime_api.rs 的 trait 声明中得到了完全一致的复刻:
/// Get the receipt of a candidate pending availability. This returns `Some` for any paras /// assigned to occupied cores in `availability_cores` and `None` otherwise. fn candidate_pending_availability(para_id: ppp::Id) -> Option<CommittedCandidateReceipt<H>>;注意这里的参数形态:文档中写作(at: Block, ParaId),其中at表示查询所针对的中继链区块(运行时 API 的通用查询上下文,用于确定状态版本);而在 trait 声明与实现中,仅保留业务参数para_id: ppp::Id(即polkadot_primitives::parachain::Id)。这与availability_cores、persisted_validation_data等同族 API 的模式一致——at是框架层(RuntimeApi)注入的查询目标块,业务层只关心ParaId。
二、返回值:CommittedCandidateReceipt是什么
Option<CommittedCandidateReceipt>中的CommittedCandidateReceipt(提交候选收据)是候选区块的“正式化”表示,由两部分组成,在中继链运行时 inclusion 模块的 runtime/parachains/src/inclusion/mod.rs 中可以清晰地看到它的拼装方式:
<PendingAvailability<T>>::get(¶) .map(|p| p.descriptor) .and_then(|d| <PendingAvailabilityCommitments<T>>::get(¶).map(move |c| (d, c))) .map(|(d, c)| CommittedCandidateReceipt { descriptor: d, commitments: c })即:
descriptor(候选描述符):来自PendingAvailability存储项,包含候选者的中继父区块哈希、平行链 ID、验证数据哈希、上行消息数、时隙占位等背书时锁定的信息;commitments(候选承诺):来自PendingAvailabilityCommitments存储项,包含候选者承诺的头部数据(HeadData)、上行消息(UpwardMessage)、HRMP 水平消息、处理后的下行消息水位等执行结果。
二者一旦组合,CommittedCandidateReceipt便完整描述了“这个候选者提议了什么、承诺产出什么”,这也是后续enact_candidate(候选者生效)流程所消费的输入格式——参见 implementers-guide 中 inclusion 模块的enact_candidate例程。
三、数据从哪来:inclusion 模块的两张存储表
要理解candidate_pending_availability的语义,必须理解它背后读取的两张存储映射。implementers-guide 的 Inclusion Pallet 存储布局 给出了权威定义:
/// The latest bitfield for each validator, referred to by index. bitfields: map ValidatorIndex => AvailabilityBitfield; /// Candidates pending availability. PendingAvailability: map ParaId => CandidatePendingAvailability; /// The commitments of candidates pending availability, by ParaId. PendingAvailabilityCommitments: map ParaId => CandidateCommitments;其中CandidatePendingAvailability辅助结构体记录了候选者在等待可用性期间的完整元数据:
struct CandidatePendingAvailability { core: CoreIndex, // availability core hash: CandidateHash, descriptor: CandidateDescriptor, availability_votes: Bitfield, // one bit per validator. relay_parent_number: BlockNumber, // number of the relay-parent. backers: Bitfield, // one bit per validator, set for those who backed the candidate. backed_in_number: BlockNumber, backing_group: GroupIndex, }关键字段的含义:
core:候选者当前占用的可用性核心索引,正是它决定了availability_cores中该 core 处于occupied状态;availability_votes:每个验证者一比特,记录哪些验证者已经为这个候选者提交了可用性比特(availability bitfield),当设置比特数超过 2/3 阈值时候选者即可被enact_candidate生效;backers:每个验证者一比特,记录哪些验证者(所在的验证组)在process_candidates阶段为这个候选者提供了背书签名。
这两张表在同一笔交易中成对写入:当process_candidates例程通过全部校验后,“create an entry in thePendingAvailabilitymap for each backed candidate with a blankavailability_votesbitfield”并“create a corresponding entry in thePendingAvailabilityCommitmentswith the commitments”(见 inclusion.md 的 process_candidates 步骤)。因此,两张表要么同时存在、要么同时不存在,candidate_pending_availability用双重get串起两张表,天然保证返回的收据是完整的。
四、运行时实现:从 API 层到 Pallet 层的调用链
中继链运行时通过 runtime/parachains/src/runtime_api_impl/v5.rs 将上述 trait 方法映射到 inclusion pallet 的实现:
/// Implementation for the `candidate_pending_availability` function of the runtime API. pub fn candidate_pending_availability<T: initializer::Config>( para_id: ParaId, ) -> Option<CommittedCandidateReceipt<T::Hash>> { <inclusion::Pallet<T>>::candidate_pending_availability(para_id) }而 inclusion pallet 中的 candidate_pending_availability 例程(pub(crate)可见性)正是前面展示的“双表拼装”逻辑。整条调用链可以概括为:
ParachainHost::candidate_pending_availability(para_id) └─> runtime_api_impl::v5::candidate_pending_availability::<T>(para_id) └─> inclusion::Pallet::<T>::candidate_pending_availability(para_id) ├─> PendingAvailability::<T>::get(¶) // → descriptor └─> PendingAvailabilityCommitments::<T>::get(¶) // → commitments从源码结构看,这条链是纯读路径(无状态变更),因此该 API 适合在查询类场景中高频调用,且与 implementers-guide 中该模块“All failed checks should lead to an unrecoverable error”的写入路径(process_candidates、process_bitfields)严格分离。此外,inclusion pallet 还提供配套例程pending_availability(ParaId) -> Option<CandidatePendingAvailability>用于返回未拼装 commitments 的候选者元数据,以及force_enact(ParaId)用于在运行时 API 执行等“状态变更将被丢弃”的场景下强制生效候选者(inclusion.md 的 Routines 小节)。
五、各链运行时的导出与测试桩
该 API 属于ParachainHost运行时 API(即平行链宿主 API)的一部分,各中继链运行时均将其纳入实现并对外导出。从仓库搜索结果看,runtime/polkadot/src/lib.rs、runtime/kusama/src/lib.rs、runtime/rococo/src/lib.rs、runtime/westend/src/lib.rs以及runtime/test-runtime/src/lib.rs中都引用了candidate_pending_availability,表明 Polkadot、Kusama、Rococo、Westend 与测试运行时均导出了该接口。
在测试与开发环境中,node/service/src/fake_runtime_api.rs 提供了一个恒定返回None的模拟实现:
fn candidate_pending_availability(_: ParaId) -> Option<CommittedCandidateReceipt<Hash>> { None }这保证了在没有真实运行时(或运行时不包含完整 state)的情况下,依赖该 API 的节点流程也能以“无候选者待可用”的基线状态启动。
六、节点侧消费路径:Runtime API 子系统与缓存
在节点侧,candidate_pending_availability由runtime-api子系统封装为面向其他子系统的请求-响应服务。其核心链路位于 node/core/runtime-api/src/lib.rs:
- 子系统收到
RuntimeApiRequest::CandidatePendingAvailability(para_id, tx)请求后,通过RuntimeApiSubsystem的查询逻辑调用运行时 API,并将结果回传给请求方; - 查询结果会被写入缓存:第 132 行附近通过
cache_candidate_pending_availability((relay_parent, para_id), candidate)将“中继父区块 + ParaId”二元组映射到候选者收据(缓存实现见 node/core/runtime-api/src/cache.rs)。由于同一 relay-parent 下候选者状态短期内稳定,这种缓存能显著降低对运行时的重复调用开销。
子系统对客户端的抽象定义在 node/subsystem-types/src/runtime_client.rs:
async fn candidate_pending_availability( at: Hash, para_id: ParaId, ) -> Result<Option<CommittedCandidateReceipt>, ApiError> { self.client.runtime_api().candidate_pending_availability(at, para_id) }与此同时,node/subsystem-util/src/lib.rs 通过specialize_requests!宏为各子系统生成类型安全的请求辅助函数:
fn request_candidate_pending_availability(para_id: ParaId) -> Option<CommittedCandidateReceipt>; CandidatePendingAvailability;任何子系统只需持有RuntimeApiSender与 relay-parent 上下文,即可通过request_candidate_pending_availability(para_id).await发起查询,无需关心底层如何路由到运行时。
节点侧测试验证
node/core/runtime-api/src/tests.rs 中的requests_candidate_pending_availability测试演示了完整用法:构造MockSubsystemClient,向candidate_pending_availability映射预置一条CommittedCandidateReceipt,然后启动子系统、发送请求并断言返回结果。该测试同时覆盖了“para 无待可用候选者时返回None”的边界情况(第 650 行附近assert_eq!(rx.await.unwrap().unwrap(), None)),与 API 文档语义(occupied core 之外的 para 返回None)形成对照验证。
七、典型应用场景:结合availability_cores与可用性流程
candidate_pending_availability的语义与availability_cores()API 强耦合:availability_cores返回每个核心的CoreState(Occupied/Free等),而本 API 进一步揭示“被占用核心上的那个候选者具体长什么样”。从 implementers-guide 中 inclusion 模块的例程 可以梳理出它对应的完整生命周期:
- 写入阶段:
process_candidates通过全部检查后,将每个已背书候选者写入PendingAvailability与PendingAvailabilityCommitments,此时对应核心在availability_cores中呈现为 occupied; - 可用性收集阶段:验证者通过
process_bitfields提交可用性比特,每比特对应写入候选者的availability_votes;当超过 2/3 验证者投票后,候选者进入enact_candidate阶段,存储被清理、核心被释放; - 查询阶段:在这两阶段之间,任何需要“读取当前待可用候选者收据”的组件(例如追踪候选者进度、准备后续 dispute 证据或做账本数据采集的子系统)都可以调用
candidate_pending_availability获取该 Para 的当前候选者收据;候选者被生效或 session 变更清空存储后(inclusion 模块在 Session Change 时会“Clear out all candidates pending availability”),查询即返回None。
从代码结构可以推断,该 API 的典型消费者是那些需要与availability_cores配合、做只读状态审计的节点组件(如 node/subsystem-util 中基于specialize_requests!的通用请求层),它避免了直接读取 pallet 内部存储的私有结构,为子系统提供了稳定、原子的数据视图。
八、小结
candidate_pending_availability虽然只有一行签名,但其背后串联起了 Polkadot 中继链三条关键事实:核心占用语义(仅 occupied core 上的 para 有返回值)、inclusion pallet 的双表存储(PendingAvailability+PendingAvailabilityCommitments)以及节点子系统统一的运行时 API 请求通道(runtime-api 子系统 + 缓存 + 请求宏)。理解这条 API,也就理解了中继链上“候选者被背书后、可用性确认前”这一关键状态窗口的数据表示与访问方式,是深入阅读 implementers-guide 的 inclusion 章节 与 ParachainHost API 定义 时非常合适的切入点。
- 区块链
【免费下载链接】polkadot
Polkadot Node Implementation
相关推荐
Polkadot Candidates Included 运行时 API 详解:本地查询候选人是否已被纳入链上
Polkadot Candidates Included 运行时 API 详解:本地查询候选人是否已被纳入链上 导读 CandidatesIncluded (c
区块链gws Google Workspace CLI 实战:用 recipe-log-deal-update 将交易状态更新追加进 Google Sheets 销售追踪表
gws Google Workspace CLI 实战:用 recipe log deal update 将交易状态更新追加进 Google Sheets 销售
区块链Vibe-Trading screen_market 完整指南:免费一次调用拉出全市场行情排行榜
Vibe Trading screen_market 完整指南:免费一次调用拉出全市场行情排行榜 "今天全市场谁涨得最猛?哪些标的成交最活跃?"传统做法是循环候
区块链
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考