forked from Fankouzu/solana-basic-ui
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
完成blockstore的翻译
- Loading branch information
Showing
1 changed file
with
64 additions
and
0 deletions.
There are no files selected for viewing
64 changes: 64 additions & 0 deletions
64
docs/SolanaValidatorDocumentation/Validators/Blockstore.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
# Solana 验证者节点中的区块存储(Blockstore) | ||
|
||
在一个区块达到最终确定性后,从该区块到起源区块的所有区块将形成一个线性链,也就是我们熟悉的区块链。然而,在此之前,验证者节点必须维护所有潜在有效的链条,称为分叉。分叉的自然形成过程是领导者轮换的结果,相关描述可见于[分叉生成](https://docs.solanalabs.com/consensus/fork-generation)。本文描述的区块存储数据结构是验证节点在区块最终确定之前应对这些分叉的方式。 | ||
|
||
区块存储允许验证者节点记录它在网络上观察到的所有分片(shred),无论顺序如何,只要分片是由预期领导者在给定槽位(slot)上签名的。 | ||
|
||
分片被移动到一个可分叉的键空间,该键是`领导者槽位`和`分片索引`(在槽位内)的元组。这允许Solana协议的跳表结构被完全存储,而无需预先选择遵循哪个分叉、持久化哪些条目或何时持久化它们。 | ||
|
||
对于最近的分片,修复请求会从RAM或最近的文件中服务;对于不太近的分片则将服务于更深层存储,作为区块存储以支持存储实现。 | ||
|
||
## 区块存储的功能 | ||
|
||
1. 持久性:区块存储位于节点验证流水线(Pipeline)的前端,紧跟在网络接收和签名验证之后。如果收到的分片与领导者时间表一致(即由该槽位的领导者签名),它将立即被存储。 | ||
2. 修复:修复与上述窗口修复相同,但可以服务于任何已收到的分片。区块存储留存带有签名的分片,保留了其起源链。 | ||
3. 分叉:区块存储支持分片的随机访问,因此可以支持验证者节点在银行检查点从头开始回滚和重播。 | ||
4. 重启:在适当的修剪/清理下,可以通过从槽位0开始有序地枚举条目来重播区块存储。重播阶段的逻辑(例如处理分叉)将用于区块存储中最新的条目。 | ||
|
||
## 区块存储设计 | ||
1. 区块存储中的条目以键值对的形式存储,其中键是条目的槽位索引和分片索引的连接,值是条目的数据。注意,每个槽位的分片索引是从零开始的(即它们是相对于槽位的)。 | ||
2. 区块存储为每个槽位维护元数据,在`槽位元`结构中包含: | ||
|
||
- `slot_index` - 该槽位的索引 | ||
- `num_blocks` - 槽位中的区块数(用于链接到前一个槽位) | ||
- `consumed` - 最高的分片索引`n`,对于所有`m < n`,在该槽位中存在分片索引等于`n`的分片(即最高的连续分片索引)。 | ||
- `received` - 槽位中收到的最高分片索引 | ||
- `next_slots` - 该槽位可能链接到的未来槽位列表。用于重建分类账时查找可能的分叉点。 | ||
- `last_index` - 该槽位被标记为最后一个分片的分片索引。该标记将在槽位的领导者发送该槽位的最后一个分片时设置在分片上。 | ||
- `is_connected` - 当且仅当从0到槽位的每个区块形成没有任何漏洞的完整序列时为真。我们可以使用以下规则为每个槽位推导出is_connected。设slot(n)为索引为`n`的槽位,slot(n).is_full()如果索引为n的槽位具有该槽位所期望的所有ticks则为真。设is_connected(n)为"slot(n).is_connected为真"的陈述。则: | ||
|
||
当且仅当(is_connected(n)并且slot(n).is_full()),is_connected(0)is_connected(n+1)成立 | ||
|
||
3. 链接- 当新槽位x的分片到达时,我们检查该新槽位的`区块数`(num_blocks,该信息被编码在分片中)。然后我们知道该新槽位链接到槽位`x-num_blocks`。 | ||
4. 订阅 - 区块存储记录已“被订阅”的一组槽位。这意味着链接到这些槽位的条目将被发送到区块存储渠道以供重播阶段应用。详情见`区块存储API`。 | ||
5. 更新通知 - 对于任意`n`,当slot(n).is_connected从假变为真时,区块存储通知监听器。 | ||
6. | ||
## 区块存储API | ||
|
||
区块存储提供了基于订阅的API,重播阶段用来请求它感兴趣的条目。这些订阅API如下: | ||
|
||
1. `fn get_slots_since(slots: &[u64]) -> Result<HashMap<u64, Vec<u64>>>`:返回与`槽位`的任何元素相连接的槽位。这种方法使发现新子槽位成为可能。 | ||
2. `fn get_slot_条目(slot: Slot, shred_start_index: u64) -> Result<Vec<Entry>>`:对于指定的`槽位`,返回从`shred_start_index`开始的可用、连续的条目向量。分片是序列化条目的片段,因此从条目索引到分片索引的转换不是一对一的。然而,存在类似的函数`get_slot_entries_with_shred_info()`,它返回组成返回的条目向量的分片数量。这使调用者能够跟踪通过槽位的进度。 | ||
|
||
注意:总体而言,这意味着重播阶段现在必须知道何时完成一个槽位,并订阅它感兴趣的下一个槽位以获取下一组条目。以前,链接槽位的负担在于区块存储。 | ||
|
||
## 与银行的接口 | ||
|
||
银行向重播阶段暴露了: | ||
1. `prev_hash`:它正在处理的PoH链,如由它处理的最后一个条目的哈希所指示。 | ||
2. `tick_height`:当前由该银行验证的PoH链中的tick高度。 | ||
3. `votes`:包含以下内容的记录堆栈: | ||
- `prev_hashes`:此投票之后的任何内容都必须链接到PoH。 | ||
- `tick_height`:此投票投出的tick高度。 | ||
- `lockout period`:必须在分类账中观察多长时间链条才能在此投票下方链接。 | ||
|
||
重播阶段使用区块存储API查找可以从之前的投票中挂靠的最长条目链。如果该条目链未挂靠在最新投票上,重播阶段会将银行回滚到该投票并从那里重播该链。 | ||
## 区块存储修剪 | ||
一旦区块存储条目足够旧,表示所有可能的分叉变得不太有用,甚至可能在重启时导致重播问题。然而,一旦验证者的投票达到最大锁定期,任何不在该投票PoH链上的区块存储内容都可以被修剪和删除。 | ||
|