这篇文章基于Polkadot的6be14014提交(2020/12),目的是介绍Polkadot在平行链角度上的系统架构。
角色
链
- Relay chain:中继链,负责平台安全性。
- Parachain:平行链,拥有自己独立的状态与业务逻辑,共享中继链提供的安全性。
节点
- validator:验证人,负责中继链的出块,同时验证来自收集者的证明,与其他验证人进行共识投票。中继链全节点,需要抵押DOT。
- collator:收集者,为验证人收集平行链的交易和状态转移证明(collation)。平行链全节点,同时内嵌中继链全节点服务,不一定需要抵押DOT,可以由平行链自行激励。注意,平行线程的 collator 需要持有DOT,以便参与出块资格的拍卖。
- fishermen:渔民,监控验证人和收集者,检查无效的候选收据。collator 或者 validator 都可以作为 fishermen,需要抵押DOT。
平行链节点结构
平行链节点主要有以下两点变动。
共识
collator 在平行链上的角色类似于以往的独立链上的 validator。
但是 collator 只提供候选区块,然后交由中继链上的 validator 进行共识。所以,平行链不再需要自己的共识机制。当然,可以保留对 collator 的选择机制。
双服务
平行链节点与以往单链节点的不同在于:需要启动一个中继链全节点服务。
内嵌的中继链全节点服务中,包含了 overseer (关于 overseer 在“中继链节点结构”部分介绍)与子系统服务,并且将 overseer_handle 共享给 collator,在collator_protocol
上注册为 collator_side
。因此,collator 能与 validator 通过 overseer 进行消息交互,例如传递候选区块相关消息。
另外,平行链全节点还需要通过内嵌的中继链节点来“跟随”中继链的出块。所谓“跟随”,指的是平行链全节点的最佳区块为中继链上最佳区块包含的相应平行链区块,终结区块亦如此。
中继链节点结构
中继链上除了必须的基础组件外,比较重要的就是overseer
与子系统。
overseer
Overseer 主要有以下功能:
- 启动和关闭一系列子系统;
- 作为子系统之间的消息总线,避免消息争用;
- 监听外部事件,触发子系统相应任务。
消息协议
overseer 向子系统发送两种类型的消息:Communication
, Signal
。
Communication
:子系统之间交互的消息被封装在Communication
类型中,根据被封装的消息类型传递到指定的子系统。例如子系统A向子系统B发送一个消息M:1. A向overseer发送AllMessages::B{M}
;2. overseer收到后,向B发送FromOverseer::Communication{M}
。Signal
:系统消息,例如块导入、块终结、关闭子系统,被封装在Signal
中。系统消息会被广播到所有子系统。
子系统
目前设计上共有18个子系统。
Collator相关
- collation_generation_subsystem:collator在块更新时生成collation
- collator_protocol_subsystem:collation的请求与回应,根据validator/collator的角色执行对应的任务
候选区块共识
- candidate_selection_subsystem:触发对collation的请求,收到collation后请求投票
- candidate_backing_subsystem:对collation投票,签署
statement
- statement_distribution_subsystem:广播
statement
- pov_distribution_subsystem:广播
PoV
- apporoval_subsystems:在finalize前对候选区块的再次检查
可用性相关
- availability_distribution_subsystem
- bitfield_signing_subsystem
- bitfield_distribution_subsystem
- availability_recovery
工具类子系统
- candidate_validation_subsystem:验证候选区块
- provisioner_subsystem:提供平行链相关的出块打包数据
- runtime_api_subsystem:调用runtime api
- availability_store_subsystem:存储可用性数据
- network_bridge_subsystem:与collation相关数据在节点间传递的网桥协议
- chain_api_subsystem
- misbehavior_arbitration
Collator
以平行链上的Collator为例,介绍节点如何与子系统协作。
启动
- 平行链启动时,
build_polkadot_full_node
启动一个中继链全节点,包含overseer和子系统,并且在 collator_protocol_subsystem 注册为collator_side
。如果要以collator的身份启动节点,启动时需要设定--collator
,类似于以往独立链设定--validator
启动验证人节点。中继链全节点持有平行链的client
,即平行链嵌套在中继链全节点中运行。start_collator
:polkadot_full_node.client.execute_with(StartCollator}
,collator和polkadot_full_node共享一个overseer_handler
。cumulus_consensus::run_parachain_consensus
:根据中继链的出块来更新平行链follow_new_best
:1. 中继链监听到中继链的best区块包含新的平行链区块后,handle_new_best_parachain_head
:如果collator已经导入了该区块,就把它当做best并且广播给平行链节点。如果还没有导入,存到unset_best_header
中;2. collator导入区块时,优先导入unset_best_header
。follow_finalized_head
:中继链监听到中继链的finalize区块包含新的平行链区块后,collator进行finalize_block
。
- 初始化collation_generation_subsystem,在此时注册
collator.produce_candidate
方法,用来生成collation
,同时注册para_id,collatorId(公钥)。 - 在 collator_protocol_subsystem 上注册 Collator 所在的para_id,在
advertise_collation
需要用到该id。
准备候选区块
- collation_generation_subsystem 启动后会循环
handle_incoming
。接受到Signal(ActiveLeaves(ActiveLeavesUpdate{..})
后触发handle_new_activations
。- 获取availability_cores:core的数量为max(n_parachains + config.parathread_cores, validators.len() / config.max_validators_per_core),第i个parachain分配第i个core。调用
request_availability_cores_ctx
->runtime_api_impl/v1::availability_cores
得到CoreState。 - 仅匹配CoreState::Scheduled;
- 检查scheduled_core.para_id;
request_full_validation_data_ctx
会触发中继链调用runtime api获取ValidationData
,实际调用make_persisted_validation_data
构造辅助验证的数据,最终被打包进平行链的SystemInherentData
。这时的ValidationData
是平行链父区块所对应的;task_config.collator
->produce_candidate
- 500ms内
propose
一个候选区块; build_collation
:构建候选区块的Collation
;- 开启
wait_to_announce
任务,注册成为StatementListener
。当收到validator发来的Statement::Seconded
就广播当前候选区块。
- 500ms内
collator_signature_payload
签名,payload包括:relay_parent,para_id,persisted_validation_data_hash,pov_hash;erasure_root
:将available_data
分成chunks,组合成 merkle trie,erasure_root为树根哈希。- 生成
CandidateReceipt
,发送CollatorProtocolMessage::DistributeCollation(CandidateReceipt, PoV)
给 collator_protocol_subsystem。
- 获取availability_cores:core的数量为max(n_parachains + config.parathread_cores, validators.len() / config.max_validators_per_core),第i个parachain分配第i个core。调用
schedule_core
1 | // AvailabilityCores |
request_availability_cores
1 | pub struct OccupiedCore<H = Hash, N = BlockNumber> { |
PersistedValidationData
1 | pub struct PersistedValidationData<N = BlockNumber> { |
平行链的SystemInherentData
1 | /// The payload that system inherent carries. |
对SystemInherentData创建的Inherent交易为set_validation_data
:可更新parachain的runtime wasm,更新[存储中的PersistedValidationData,RelevantMessagingState,HostConfiguration,processed_downward_messages,hrmp_watermark],处理数据[on_validation_data
,DownwardMessageHandlers::handle_downward_message
,HrmpMessageHandlers::handle_hrmp_message
]
Collation
1 | pub struct Collation<BlockNumber = polkadot_primitives::v1::BlockNumber> { |
Ensure Code的available_data
1 | pub struct AvailableData { |
连接并通知validator
- collator_protocol_subsystem 监听Communication(CollatorProtocolMessage),
process_msg
处理消息。收到DistributeCollation
后,检查para_id,然后distribute_collation
向validator广播。distribute_collation
:要求collation在active-leaves上,collation未被发送determine_core
:计算当前平行链分配到的coredetermine_our_validators
:计算分配到该平行链的validator集合,包括当前集合和下一次分配的集合。每个session会依据n_cores
和validators.len()
重新排列ValidatorGroups,但是不一定是一个session才更换分配给平行链的group。connect_to_validators
:同时连接当前validators和下一组validators。
- 连接上新的validator后,在collator protocol子系统中
handle_validator_connected
- 发送一个
CollatorProtocolMessage::Declare(CollatorId)
给validator,注册collator - 如果validator是属于该平行链的验证人集合,那么
add_peer_id_for_validator
记录validators的peer_id,advertise_collation
,向validator 发送CollatorProtocolMessage::AdvertiseCollation(relay_parent, collating_on)
,通知validator准备发送collation了。
- 发送一个
Candidate
1 | pub struct CandidateReceipt<H = Hash> { |
回应validator的请求
- 收到validator消息
CollatorProtocolMessage::RequestCollation
send_collation
:回应validtor,发送CollatorProtocolMessage::Collation(request_id,receipt,pov)
给validator。对PoV进行compress
再发送,减少通信压力。CandidateReceipt中只存储commitments_hash,validator在验证时从PoV中重新组装出commitments,最后验证hash是否一致。
由于这是节点间通信,overseer的中继只能作用于节点内的子系统之间,所以这个消息是被封装在NetworkBridgeMessage::SendCollationMessage
中的,通过 network_bridge_subsystem 向validator转发消息(一对一,非广播)。
出块
- 当中继链上statement被checked后(状态为seconded),collator在平行链上
announce_block
,此时为暂时同步。 - 最佳区块和终结区块跟随中继链的出块。
More
实际上,以上所描述的Collator与子系统的交互也可以说是以Collator角度的平行链出块流程。关于以Validator角度的平行链出块流程将在《平行链节点的出块流程》中介绍。