ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Polkadot 实现者指南:`persisted_validation_data` Runtime API 与持久化验证数据详解

Polkadot 实现者指南:`persisted_validation_data` Runtime API 与持久化验证数据详解 区块链【免费下载链接】polkadotPolkadot Node Implementation项目地址https://gitcode.com/gh_mirrors/po/polkadot点击查看免费下载本篇指南聚焦 Polkadot 中继链运行时relay-chain runtime提供的persisted_validation_dataRuntime API逐层讲解PersistedValidationData的类型结构、OccupiedCoreAssumption三种占核假设的语义以及该 API 在运行时实现与候选验证candidate-validation子系统中的真实调用链。读完本文你将能准确理解验证数据为何需要持久化、每个字段如何从链上状态组装而来以及验证者与收集人collator如何利用该数据完成候选的输入构建与校验。一、API 定义与返回语义该 Runtime API 位于ParachainHosttrait 之中其公开声明见 primitives/src/runtime_api.rs/// Yields the persisted validation data for the given ParaId along with an assumption that /// should be used if the para currently occupies a core. /// /// Returns None if either the para is not registered or the assumption is Freed /// and the para already occupies a core. fn persisted_validation_data(para_id: ppp::Id, assumption: OccupiedCoreAssumption) - OptionPersistedValidationDataH, N;其核心语义可以概括为入参目标平行链的ParaId以及一个OccupiedCoreAssumption占核假设。出参OptionPersistedValidationData——当且仅当平行链已注册、且假设与核的当前占用状态相容时返回Some否则返回None。返回None的具体触发条件para 未注册或假设为Free但该 para 已经占用了某个核。在实现者指南的抽象描述中该 API 写作fn persisted_validation_data(at: Block, ParaId, OccupiedCoreAssumption) - OptionPersistedValidationData其中at表示在哪个中继链区块的状态下执行查询详见 roadmap/implementers-guide/src/runtime-api/persisted-validation-data.md。二、PersistedValidationData的类型结构2.1 字段定义在运行时原语primitivescrate 的 v5 模块中PersistedValidationData被定义为四个字段的轻量结构体见 primitives/src/v5/mod.rspub struct PersistedValidationDataH Hash, N BlockNumber { /// The parent head-data. pub parent_head: HeadData, /// The relay-chain block number this is in the context of. pub relay_parent_number: N, /// The relay-chain block storage root this is in the context of. pub relay_parent_storage_root: H, /// The maximum legal size of a POV block, in bytes. pub max_pov_size: u32, }各字段的作用如下字段类型含义parent_headHeadData平行链当前父块头数据即该 para 在 relay-parent 状态下最新被纳入的块头relay_parent_numberBlockNumber该验证数据所处上下文的中继链区块号用于告知收集人当前高度relay_parent_storage_rootHash该验证数据所处上下文的中继链区块存储根max_pov_sizeu32一个 PoVProof-of-Validity块的最大合法字节数实现者指南在 roadmap/implementers-guide/src/types/candidate.md 中对PersistedValidationData的设计动机给出了详细说明其要点包括轻量设计该数据在 inclusion纳入流程中为每个候选构造位于纳入的关键路径critical path上因此必须尽量轻量避免拖慢区块生产。持久化原因该数据被用作验证函数的输入可用性系统availability system必须持久化它以避免验证者对中继链状态的依赖——即验证者不应当需要重新访问中继链存储才能重建验证输入。授权额外数据验证数据扮演着授权收集人传递给验证函数的附加数据的角色。例如验证函数可以利用验证数据中携带的 MQC heads消息队列链头来检查收集人传入的入站消息如下行消息 DMP是否确实由中继链发送。2.2 关于HeadData与ParaIdHeadData是围绕字节的强类型包装struct HeadData(Vecu8)用于表示平行链的头ParaId是 32 位唯一标识符中继链运行时保证任意会话期间ParaId唯一但允许在更长的时间跨度内回收复用见 roadmap/implementers-guide/src/types/candidate.md。2.3 哈希与相等性判断PersistedValidationData还提供了hash()方法使用 blake2-256BlakeTwo256::hash_of计算整个结构体的哈希见 primitives/src/v5/mod.rs。这个哈希正是候选描述符CandidateDescriptor中persisted_validation_data_hash字段的取值来源是后续验证流程中判断收集人声明的验证数据是否与链上状态一致的关键依据。三、OccupiedCoreAssumption三种占核假设3.1 为什么要引入假设某些面向 para 状态的 Runtime API 需要调用方提供OccupiedCoreAssumption它指示如果该 para 的一个候选正占用了某个可用性核availability core结果应当如何计算。这一设计源于 roadmap/implementers-guide/src/runtime-api/README.md假设的选择包括该核上的候选被假定已完成可用性并被纳入included、被假定超时并被丢弃timed out以及第三种断言——该核原本就没有被占用。该假设会影响从父头数据、验证代码到消息队列状态在内的一切派生结果。在实现者指南的抽象类型定义中该枚举有三个变体primitives/src/v5/mod.rs 中的运行时原语与指南中 roadmap/implementers-guide/src/runtime-api/README.md 的描述一致enum OccupiedCoreAssumption { /// The candidate occupying the core was made available and included to free the core. Included, /// The candidate occupying the core timed out and freed the core without advancing the para. TimedOut, /// The core was not occupied to begin with. Free, }三个变体的含义与适用场景变体语义典型使用场景Included假设占用核的候选已被判定可用并被纳入核被释放para 状态向前推进大多数正常流程候选描述符中的验证数据哈希通常对应此假设TimedOut假设占用核的候选超时核被释放但 para 状态未推进对抗性场景或验证者集合轮换后少数块中的边缘情况Free断言该核原本未被占用查询未被调度的 para或 para 未注册时直接返回None在实际使用中调用方通常采用核空闲或占用候选已被纳入两种假设因为超时只在对抗性场景中才被预期且即使发生也只影响紧随验证者集合轮换后的极少数块。3.2 假设在运行时中的具体处理在runtime_api_impl/v5.rs中假设被翻译成对 inclusion pallet 状态的实际操作。with_assumption辅助函数按假设分支处理见 runtime/parachains/src/runtime_api_impl/v5.rsIncluded调用inclusion::Pallet::force_enact(para_id)将该 para 待可用性pending availability的候选强行纳入如同已收到足够的可用性位域投票一般然后构建验证数据。TimedOut直接构建验证数据不推进状态相当于核被释放且候选被丢弃。Free先检查pending_availability(para_id)是否存在待纳候选——若存在则返回None因为核事实上被占用与Free假设矛盾否则才构建验证数据。其中force_enact是 inclusion pallet 的内部方法其实现见 runtime/parachains/src/inclusion/mod.rs。它的注释明确说明该方法在正常路径上一般不应使用但在 Runtime API 执行期间很有用——此时对状态的修改预期会在 API 调用结束后立即被丢弃因此可以作为推测性执行的工具让调用方以Included假设模拟候选纳入后的链上状态。四、运行时实现验证数据如何从链上状态组装4.1 实现入口persisted_validation_data的运行时实现位于 runtime/parachains/src/runtime_api_impl/v5.rspub fn persisted_validation_dataT: initializer::Config( para_id: ParaId, assumption: OccupiedCoreAssumption, ) - OptionPersistedValidationDataT::Hash, BlockNumberForT { let (relay_parent_number, relay_parent_storage_root) current_relay_parent::T(); with_assumption::T, _, _(para_id, assumption, || { crate::util::make_persisted_validation_data::T( para_id, relay_parent_number, relay_parent_storage_root, ) }) }实现分两步通过current_relay_parent::T()获取当前正在处理的区块号与对应存储根见 runtime/parachains/src/runtime_api_impl/v5.rs——即该验证数据所处上下文的中继链高度与状态根。将para_id、高度、存储根交给make_persisted_validation_data并按假设包裹执行。4.2 组装逻辑串联多个 pallet 的存储make_persisted_validation_data位于 runtime/parachains/src/util.rs是理解本 API 的枢纽。它串联了多个模块的存储源码注释原文实际引用了三个 palletpub fn make_persisted_validation_dataT: paras::Config hrmp::Config( para_id: ParaId, relay_parent_number: BlockNumberForT, relay_parent_storage_root: T::Hash, ) - OptionPersistedValidationDataT::Hash, BlockNumberForT { let config configuration::PalletT::config(); Some(PersistedValidationData { parent_head: paras::PalletT::para_head(para_id)?, relay_parent_number, relay_parent_storage_root, max_pov_size: config.max_pov_size, }) }字段来源与模块对应关系parent_head来自paras pallet的para_head存储。注意这里使用了?运算符——若该 para 未注册或尚无头数据para_head返回None整个函数立即返回None这与 API 文档中para 未注册则返回None的语义严格一致。relay_parent_number/relay_parent_storage_root来自frame_system的当前区块上下文。max_pov_size来自configuration pallet的运行时配置项max_pov_size是一个全局统一的最大 PoV 字节数限制。由此可以看出尽管PersistedValidationData在指南的类型定义中还包含hrmp_mqc_heads字段见 roadmap/implementers-guide/src/types/candidate.md描述为按 para id 升序排列、无重复发送方的入站 HRMP 通道 MQC 头列表但当前运行时实现make_persisted_validation_data组装出的结构体实际只填充了四个字段hrmp_mqc_heads并未由该函数填充。从源码结构看这是 v5 原语演进过程中的一个差异点PersistedValidationData结构体中仍保留了该字段位hrmp_mqc_heads: Vec(ParaId, Hash)验证函数对入站消息的授权检查仍可借助其他途径的 MQC 信息完成。撰写对验证数据做二次推断时应以当前仓库源码为准。五、配套 APIassumed_validation_data的哈希匹配变体除persisted_validation_data外ParachainHost还提供了它的哈希匹配变体assumed_validation_data声明见 primitives/src/runtime_api.rs/// Returns the persisted validation data for the given ParaId along with the corresponding /// validation code hash. Instead of accepting assumption about the para, matches the validation /// data hash against an expected one and yields None if theyre not equal. fn assumed_validation_data( para_id: ppp::Id, expected_persisted_validation_data_hash: pcp::v2::Hash, ) - Option(PersistedValidationDataH, N, ppp::ValidationCodeHash);它不接受假设而是将组装出的验证数据哈希与调用方预期的哈希比对一致才返回且返回结果额外附带当前验证代码哈希。实现见 runtime/parachains/src/runtime_api_impl/v5.rs其关键步骤先按make_persisted_validation_data组装数据用.filter(|data| data.hash() expected_hash)做哈希比对。若不一致再尝试一次force_enact仅当该 para 存在 pending availability 候选时才有意义重新组装并比对。成功后将验证数据与paras::Pallet::current_code_hash(para_id)打包成元组返回。这一变体的典型动机是候选描述符中只携带persisted_validation_data_hash一个哈希值验证者并不预先知道收集人采用了哪种占核假设因此需要通过哈希匹配来确定与描述符一致的那份验证数据。六、在候选验证子系统中的实际使用6.1 从描述符哈希反推验证数据验证者子系统在验证候选时候选描述符CandidateDescriptor中带有persisted_validation_data_hash。candidate-validation子系统的check_assumption_validation_data会通过 runtime API 请求PersistedValidationData(descriptor.para_id, assumption, tx)然后计算其哈希并与描述符中的哈希比对见 node/core/candidate-validation/src/lib.rslet persisted_validation_data_hash validation_data.hash(); if descriptor.persisted_validation_data_hash persisted_validation_data_hash { // 哈希一致 → 继续请求 ValidationCode返回 AssumptionCheckOutcome::Matches } else { // 不一致 → AssumptionCheckOutcome::DoesNotMatch }由于描述符的哈希可能对应两种可能的假设Included或TimedOut/Freefind_assumed_validation_data会依次尝试假设集合[Included, TimedOut]并注释指出TimedOut与Free都不做推测性执行因此二者结果等价只需尝试其一见 node/core/candidate-validation/src/lib.rs。6.2 验证数据字段直接驱动候选检查拿到验证数据后validate_candidate_exhaustive会先执行perform_basic_checks其中max_pov_size被用来对候选的 PoV 编码大小做硬性上限检查见 node/core/candidate-validation/src/lib.rslet encoded_pov_size pov.encoded_size(); if encoded_pov_size max_pov_size as usize { return Err(InvalidCandidate::ParamsTooLarge(encoded_pov_size as u64)) }随后parent_head、relay_parent_number、relay_parent_storage_root会被转交给验证函数见 node/core/candidate-validation/src/lib.rs 与 node/core/candidate-validation/src/lib.rs作为构造验证输入的一部分。这印证了指南中的论述验证数据由中继链状态派生、经可用性系统持久化从而保证任何验证者都能在不依赖中继链状态可用性的前提下重建验证输入。七、总结persisted_validation_dataRuntime API 是平行链验证流程的基石之一它把中继链当前状态压缩成一个轻量的、可持久化、可哈希的验证数据对象结构上PersistedValidationData由parent_head、relay_parent_number、relay_parent_storage_root、max_pov_size四个字段组成其组装串联了 paras、configuration 与 frame_system 的存储runtime/parachains/src/util.rs。语义上OccupiedCoreAssumption的三种变体决定了查询时如何对待核被占用这一事实运行时通过force_enact等机制在 Runtime API 的推测性执行中模拟候选纳入。使用上验证者通过描述符中的persisted_validation_data_hash反查验证数据并用其中的max_pov_size等字段完成基本检查与验证输入构造node/core/candidate-validation/src/lib.rs。对于深入阅读者建议继续查阅 primitives/src/runtime_api.rs 的完整ParachainHost声明、runtime/parachains/src/runtime_api_impl/v5.rs 的 v5 实现以及实现者指南中的 PersistedValidationData 类型文档 与 OccupiedCoreAssumption 说明。赞分享区块链【免费下载链接】polkadotPolkadot Node Implementation项目地址https://gitcode.com/gh_mirrors/po/polkadot点击查看免费下载相关推荐gws Google Workspace CLI 实战用 recipe-log-deal-update 将交易状态更新追加进 Google Sheets 销售追踪表gws Google Workspace CLI 实战用 recipe log deal update 将交易状态更新追加进 Google Sheets 销售区块链Kotatsu数据库设计终极指南Room ORM与数据持久化实现详解Kotatsu数据库设计终极指南Room ORM与数据持久化实现详解 Kotatsu作为一款功能强大的Android漫画阅读器其 数据库设计 和 数据持久化移动开发前端Draft.js 数据转换 API 详解如何在富文本编辑器中实现数据持久化Draft.js 数据转换 API 详解如何在富文本编辑器中实现数据持久化 前言 在现代 Web 应用中富文本编辑器是常见的交互组件。Draft.js 作为前端UI组件上一篇Processing3完全指南从零开始的创意编程之旅下一篇Vosk-api核心架构解析深入理解离线语音识别的实现原理创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表