news 2026/10/7 2:09:49

Polkadot 候选者待可用性查询:`candidate_pending_availability` 运行时 API 全解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Polkadot 候选者待可用性查询:`candidate_pending_availability` 运行时 API 全解析
  • 区块链

【免费下载链接】polkadot

Polkadot Node Implementation

项目地址:https://gitcode.com/gh_mirrors/po/polkadot
点击查看免费下载

导读

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 returnsSomefor 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(&para) .map(|p| p.descriptor) .and_then(|d| <PendingAvailabilityCommitments<T>>::get(&para).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(&para) // → descriptor └─> PendingAvailabilityCommitments::<T>::get(&para) // → 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 模块的例程 可以梳理出它对应的完整生命周期:

  1. 写入阶段:process_candidates通过全部检查后,将每个已背书候选者写入PendingAvailability与PendingAvailabilityCommitments,此时对应核心在availability_cores中呈现为 occupied;
  2. 可用性收集阶段:验证者通过process_bitfields提交可用性比特,每比特对应写入候选者的availability_votes;当超过 2/3 验证者投票后,候选者进入enact_candidate阶段,存储被清理、核心被释放;
  3. 查询阶段:在这两阶段之间,任何需要“读取当前待可用候选者收据”的组件(例如追踪候选者进度、准备后续 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

项目地址:https://gitcode.com/gh_mirrors/po/polkadot
点击查看免费下载
上一篇:Habitat-Sim 传感器配置详解:RGB-D相机与运动感知的终极指南
下一篇:Atom Flight Manual:查找替换与多光标编辑的12个进阶技巧,从新手到高手的捷径

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/7 2:08:03

C# OPC UA客户端开发实战:连接、订阅与SQL Server数据存储

简介&#xff1a;这是一份面向工业自动化、物联网及企业级数据集成方向开发者的C#实战项目源码&#xff0c;核心是用C#构建OPC UA客户端&#xff0c;连接OPC UA服务器完成数据读写&#xff0c;并将采集数据存入SQL Server数据库。项目借助OpcUaHelper开源库简化协议实现&#x…

作者头像 李华
网站建设 2026/10/7 2:07:59

2026 Android Studio 保姆级安装配置指南:从下载到跑通全流程

2026 年了&#xff0c;还有人在 Android Studio 安装配置这一步卡住&#xff0c;而且卡住的原因往往不是技术难题&#xff0c;而是信息太散、教程太旧、版本对不上。你搜“Android Studio 安装教程”能搜出几百篇&#xff0c;但一半是 2019 年的截图&#xff0c;一半讲的是过时…

作者头像 李华
网站建设 2026/10/7 2:05:13

WorkBuddy完整实战教程:10个模块掌握AI工作流自动化

这次我们来看 WorkBuddy。它不是某个模型&#xff0c;也不是单纯的聊天框工具&#xff0c;而是一个偏向 AI 工作流编排与自动化落地的轻量级平台。简单说&#xff0c;就是把 AI 能力、数据处理、业务步骤、人工确认串成一条可重复执行的流水线&#xff1a;输入一份材料&#xf…

作者头像 李华