4.3 KiB
title
title |
---|
维修服务 |
维修服务
修复服务负责检索未能通过Turbine等主要通信协议传送的遗失碎片。 它负责管理下面维修协议
部分中描述的协议。
挑战。
1) 验证节点可能会因为网络故障而无法接收特定的碎片。
2) 考虑一个场景,blockstore包含一组插槽{1, 3, 5}。 那么Blockstore接收到一些插槽7的碎片,其中对于每一个碎片b,b.parent == 6,那么父子关系6 -> 7就存储在blockstore中。 但是,没有办法将这些插槽链到Blockstore中任何一个现有的库中,因此,碎片修复
协议不会修复这些插槽。 如果这些插槽恰好是主链的一部分,这将停止该节点上的重放进度。
修复相关基元
纪元插槽: 每个验证节点都在Gossip上分别广播纪元插槽
的各个部分。
储藏
:一个以纪元为单位的所有已完成插槽的压缩集。缓存
:最新的N
个已完成的插槽的运行长度编码(RLE),从某个插槽M
开始,其中N
是一个MTU大小的数据包所能容纳的插槽数。
gossip中的Epoch Slots
每当验证节点收到一个在epoch内的完整插槽时,就会更新。 已完成的插槽由blockstore检测,并通过通道发送到维修服务。 需要注意的是,我们知道当一个插槽X
完成的时候,包含插槽X
的纪元必须存在纪元时间表,因为WindowService会拒绝未确认的纪元的碎片。
每完成一个N/2
插槽,最老的N/2
插槽就会从缓存
移到stash
中。 RLE的基值M
也要更新。
修复请求协议
修复协议为进步Blockstore的分叉结构做了最好的尝试。
不同的协议策略来解决上述难题。
-
Shred Repair(解决挑战#1):这是最基本的修复协议,目的是检测和填补账本中的 "漏洞"。 Blockstore会跟踪最新的根插槽。 然后,RepairService会从根插槽开始定期迭代blockstore中的每一个分叉,向验证节点发送修复请求,以获取任何缺失的碎片。 它每次迭代最多会发送一些
N
修复请求。 碎片修复应该根据领导者的分叉重量来优先修复分叉。 验证节点应该只向在其EpochSlots中标记该插槽已完成的验证节点发送修复请求。 验证节点应该优先修复他们负责通过涡轮重传的每个插槽中的碎片。 验证节点可以计算出他们负责重传的碎片,因为turbine的种子是基于leader id、slot和碎片 index的。注意:验证节点只接受当前可验证的epoch (验证节点有领袖时间表的epoch) 内的碎纸片。
-
Preemptive Slot Repair(解决挑战 #2):这个协议的目标是发现 "孤儿 "插槽的链路关系,这些插槽目前没有链到任何已知的分叉。 碎片修复应该根据领导者的分叉权重来优先修复孤儿插槽。
-
Blockstore将在一个单独的列族中跟踪 "孤儿 "插槽的集合。
-
修复服务将定期为blockstore中的每个孤儿提出
Orphan
请求。Orphan(orphan)
请求--orphan
是请求者想知道的孤儿插槽的父母Orphan(orphan)
响应--请求的orphan
的前N
个父母的最高分叉量。在收到响应
p
时,其中p
是父插槽中的一些碎片,验证节点将:- 如果它还不存在,那么就在区块存储中为
p.slot
插入一个空的SlotMeta
。 - 如果
p.slot
确实存在,根据父辈
更新p
的父插槽。
注意:一旦这些空插槽被添加到区块存储中,
Shred Repair
协议应该尝试填补这些插槽。注意:验证节点只会接受包含当前可验证的epoch (验证节点有领导时间表的epoch) 内的碎片的响应。
- 如果它还不存在,那么就在区块存储中为
-
验证节点应该尝试将孤儿请求发送给在其EpochSlots中已将该孤儿标记为已完成的验证节点。 如果不存在这样的验证节点,那么就以利害关系加权的方式随机选择一个验证节点。
修复响应协议
当验证节点收到一个碎片S
的请求时,如果他们有碎片,他们就会响应。
当验证节点通过修复响应收到碎纸片时,他们会检查EpochSlots
,看看是否有 <= 1/3
的网络已经将这个插槽标记为完成。 如果是这样,他们就会通过其相关的涡轮路径重新提交这个碎片,但前提是这个验证节点之前没有重传过这个碎片。