5.4 KiB
title
title |
---|
Blockstore(区块存储) |
当一个区块到达最终状态时,从那个区块到创世区块之间所有区块形成了一条链,就是大家都熟悉区块链。 然而,在此之前,验证节点必须维护所有可能有效的链,称为_分叉(forks)_。 领导节点从验证节点中通过算法轮换选举,这个过程会自然的产生分叉。 本节描述了验证节点的 区块存储(blockstore) 数据结构是如何复制并处理这些分叉,直到确定最终的区块。
验证节点记录它在网络上观察到的每一个区块分片(无论任何顺序,只要区块分片是由给定插槽的领导者签名的)。
碎片被移动到一个可分叉的区间领导者插槽
+ 碎片索引
(在一个 slot 区间) 。 这允许Solana中的跳表数据结构完整的存储碎片,而无需事先选择跟随哪个分叉或者等待区块已经达到最终状态。
可以从内存中或者最近的文件中重组最新的区块碎片,较晚的区块碎片可以从磁盘的旧文件中重组,这取决于BlockStore的实现。
Blockstore 功能
-
持久性:Blockstore和节点的验证流水线打交道
接收输入流和签名验证。 如果
收到的区块碎片和领导节点的签名是一致的(
例如领导节点的分配插槽内接收的区块),它需要立即存储。
-
重组:重组和上面提到的一样
但是它能够为任何接收的区块碎片进行重组。 Blockstore存储带有签名的区块碎片,
保留区块链的历史记录。
-
分叉:Blockstore支持区块碎片的随机访问,
因此可以支持验证节点回滚并且重放记录点后的交易。
-
重启:通过适当的修剪/剔除,
区块储藏可以通过少数交易条目回放到 slot 0。 回放的逻辑就是
()通过最新的Blockstore状态
来处理的,例如处理分叉。
Blockstore 设计
-
每条记录都是通过键值对来存储的,键就是插槽索引加上区块碎片索引,值就是条目数据。 值得注意的是每个碎片索引都是重新从零开始的(按照每个插槽)。
-
Blockstore 中每个插槽中的元组
SlotMeta
数据结构包含:-
slot_index
- 插槽索引 -
num_blocks
- 插槽的区块数量 (用于区块链中前一个插槽) -
consumed
- 碎片索引的连续最高值n
,对于所有的m < n
,,总会有一个碎片索引的值等于n
(例如连续最高的碎片索引)。 -
received
- 碎片索引的最高值 -
next slots
- 下一个插槽的列表 可以用于重建到一个记录点的回放
-
last _index
- 插槽的最后一个碎片标识 当领导节点在传输插槽的最后一个碎片索引时会带上这个标识。 -
is_root
- 如果为True那么当前插槽所有区块碎片都是收集完整的。 我们可以按照以下的规则进行。 假设slot(n)是索引为n
的插槽,并且slot(n).is_full()为真,如果索引为n
的插槽都收集到了所有的碎片。 假设 is_rooted(n) 表示“slot(n).is_root 为真”。 那么:is_rooted(0) is_rooted(n+1) iff(is_rooted(n) and slot(n).is_full()
-
-
Chaining - 当
x
插槽的碎片到达时,我们检查新插槽中的(num_blocks
)(这个信息在碎片中会有编码)。 我们就知道这个新插槽链是x - num_blocks
插槽。 -
Subscriptions - Blockstore记录一组已“订阅”到的插槽。 这意味着这些插槽的条目将被发送到Blockstore通道,供ReplayStage使用。 详情请查看
Blockstore APIs
。 -
Update notifications - 对于任意一个
n
,Blockstore 更新 slot(n).is_rooted 这个值从false 变成true。
Blockstore 接口
Blockstore提供了一个基于订阅的API,ReplayStage使用它来请求所需要的条目。 Blockstore有暴露相关的接口让请求方获取这些条目。 这些订阅API如下所示: 1. fn get_slots_slots_slouts(slot_indexes: &[u64]) -> Vec<SlotMeta>
:返回slot_indexes
中对应的区块碎片数据。
fn get_slot_entries(slot_index: u64, entry_start_index: usize, max_entries: Option<u64>) -> Vec<Entry>
:返回以entry_start_index
开头的插槽入口向量,如果max_entries == Some(max)
,则将结果限制在max
,对返回向量的长度施加限制。
请注意:这意味着重播阶段现在必须知道一个slot何时结束,并订阅它感兴趣的下一个slot以获得下一组条目。 较旧的slot将会存储到Blockstore当中。
与Bank交互
Bank 暴露以下字段用于交易重放:
-
prev_hash
:PoH链上的最后一个区块哈希它处理过的条目
-
tick_head
:PoH链中的滴答,由 Bank进行验证
-
votes
:包含以下内容的一堆记录: 1.prev_hashes
: 上一次PoH的哈希值 2.tick_high
:此投票的高度 3.lockout period
:这个投票的最大截止时间能够在这次投票中被引用
在这个voteReplay阶段会建立分叉点,用Blockstore API找到它可以挂起的最长链。 如果当前链没有最新的投票,那么重放阶段将回滚到投票的分叉点,并从那里重新同步。
Blockstore 剪枝
一旦Blockstore中记录太旧了,表示所有可能的分叉就变得不那么有用了,甚至可能在重启时重放出现问题。 一旦验证节点的投票达到最大截止时间限制,任何不在PoH链上的区块都可以被剪枝、删除。