共识机制
上一篇中,我们说到交易流程可以划分划分为三个阶段
-
交易背书
-
交易排序
-
交易校验(记账)
广义上说,整个交易流程都属于共识机制,通常情况下,我们说的共识机制仅是 **交易排序**阶段
交易排序主要在Orderer节点实现,orderer主要有三个功能:
1、交易排序
目的:保证系统交易顺序一致性(有限状态机)
如果一个系统从最初是的状态开始,每一个状态改变条件都一致的话,他一定会得到一个一致的结果。只有保证交易顺序,状态机改变条件一致,才能保证得到一致的结果
- solo:单点排序
- kafka:外部消息队列保证一致性
2、区块分发
- 中间状态区块(非落盘区块,中间状态区块,包含排序节点收到的所有交易)
- 有效交易&无效交易
3、多通道数据隔离
排序节点收到交易后,会按照通道进行拆分,拆分后进行排序,排序后发送至不同的通道,各节点通过订阅通道,获取交易区块。类似于kafuka的主题模式
账本存储
区块链
底层存储引擎是文件系统,
使用文件系统存储数据,fabric中,将多个区块,生成一个文件进行存储,查询的时候,需要指定偏移量
- 区块存储
- 区块以文件块的形式存储(blockfile_xxxx)
- 文件块大小:64M(硬编码,改变需要重新边缘)
- 账本最大容量:64 * 1000000
区块索引
将区块的属性与位置关联起来,使用levelDB存储通过区块区块索引来进行对区块的查询
- 快速定位区块
- 索引键:区块高度 区块哈希 交易哈希
- 索引值:区块文件编号 + 文件内偏移量 + 区块数据长度
状态数据库
可以理解为区块链上的最新数据,随着交易额增加不停的更新,如果丢失,可以从区块链上进行同步,二者不一致时候,则以区块链文件系统数据为准。
历史状态索引
-
某键在某区块的某条交易中被改变
-
只记录改变动作,不记录具体改变
-
历史读取 --> 历史数据索引 + 区块读取
-
LevelDB 组合键
某一数据的历史交易的索引,不存储任何状态值,这样如果用户需要对某一数变更历史进行查询的时候,可以通过历状态索引快速找到与改数据相关的交易的区块索引。
记账节点存储过程
- 保存区块文件 将区块追加或者另起一个文件块,然后更新区块索引(无效交易也会被存储)
- 更新世界状态 (无效交易不会更新)
- 更新历史状态
三者顺序执行
之前有说过,区块链的交易流程分为三步:
交易模拟 --->读写集(EWSet)
交易排序
交易验证 ----> 状态更新(更新写集)
读写集(EWSet)
读写集主要描述对区块链的操作:读取,写入,更新,删除
- 读集:读取已提交的状态键值对
- 写集:更新的,新增,删除标记键值对(多个更新,以最后一个更新为主)
- 版本号:二元组(区块高度+交易编号)
交易验证:
主要是对交易读写集的验证(还有签名,证书等)只跟读集有关
读集版本号 ==世界状态版本号(包括未提交的前序交易)
-
例子:
世界状态:(K1,1,v1.0)(K2,2,v2.0)(K3,3,v3.0)(K4,4,v4.0)
-
交易1:Write(k1,v1.1),Write(k2,v2.1)
交易1对k1,k2进行更新 有效。世界状态:(K1,1,v1.1)(K2,2,v2.1)(K3,3,v3.0)(K4,4,v4.0)
-
交易2:Read(k1),Write(k3,k3.1)
交易2对k1的读取和对k3的更新,由于k1已经被更新,此时交易2是无效的 交易与交易不知道彼此的存在。所以,读取的都是世界状态。世界状态:(K1,1,v1.1)(K2,2,v2.1)(K3,3,v3.0)(K4,4,v4.0)
-
交易3:Write(k2,v2.2)
交易3写集,有效世界状态:(K1,1,v1.1)(K2,2,v2.2)(K3,3,v3.0)(K4,4,v4.0)
-
交易4:Write(k2,v2.3),Read(k3)
交易4有效,因为交易2无效,没有对k3进行更新世界状态: (K1,1,v1.1)(K2,2,v2.3)(K3,3,v3.0)(K4,4,v4.0)
-
交易5:Write(k5,v5.0),Read(k4)
交易5有效世界状态: (K1,1,v1.1)(K2,2,v2.3)(K3,3,v3.0)(K4,4,v4.0)(K5,5,v5.0)
补充:
世界状态:
-
交易执行后的所有键的最新值
-
显著提升链码的执行效率
-
状态是所有交易日志的快照,可随时以区块链数据为准进行重构
理解:假如交易是一条条的sql语句,世界状态就是sql执行后的数据库表的最新信息