分享 | Hyperledger fabric1.0整体架构与记账逻辑架构的分析

关于Hyperledger fabric1.0整体架构与记账逻辑架构的分析

作者:深蓝居

本文转载自开源中国

原文链接:https://my.oschina.net/u/568367/blog/1589730

关于逻辑架构的一些问题

1)CLI客户端和peer节点之间是如何沟通的?

2)Peer节点之间如何数据传输处理,与cli和peer之间的方式有何不同?

3)数据何时进入orderer节点,orderer节点是如何处理的?(0.6里面就是共识这块怎么处理)

4)链码(CC)是如何与节点或cli或rest api交互的,怎么实现的?

新旧架构的比较

旧版本(0.6)的运行时架构:

640?wx_fmt=jpeg&wxfrom=5&wx_lazy=1

新版本(1.0)的运行时架构:

640?wx_fmt=jpeg&wxfrom=5&wx_lazy=1

fabric1.0记账的逻辑分析

Fabric账本逻辑架构

640?wx_fmt=jpeg&wxfrom=5&wx_lazy=1

Fabric 1.0中的账本分为3种:

区块链数据,这是用文件系统存储在Committer节点上的。区块链中存储了Transaction的读写集。

为了检索区块链的方便,所以用LevelDB对其中的Transaction进行了索引。

ChainCode操作的实际数据存储在State Database中,这是一个Key Value的数据库,默认采用的LevelDB,现在1.0也支持使用CouchDB作为State Database。

当执行a向b转账10元,我们在cli中执行的命令为:

peer chaincode invoke -o orderer.example.com:7050  --tls $CORE_PEER_TLS_ENABLED --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/cacerts/ca.example.com-cert.pem -C mychannel -n devincc -c '{"Args":["invoke","a","b","10"]}'

这个过程是这样的:


640?wx_fmt=jpeg&wxfrom=5&wx_lazy=1

其中peer chaincode invoke表明这是一个Transaction调用。-c '{"Args":["invoke","a","b","10"]}'中的”invoke”说明调用的是example02.go中的invoke函数,具体函数我们可以看看到底实现了什么功能:

640?wx_fmt=jpeg&wxfrom=5&wx_lazy=1

其中主要的4个关于StateDatabase调用是:

640?wx_fmt=png&wxfrom=5&wx_lazy=1

  1. 客户端SDK把'{"Args":["invoke","a","b","10"]}'这些参数发送到endorser peer节点,

  2. endorser peer会与ChainCode的docker实例通信,并为其提供模拟的State Database的读写集,也就是说ChainCode会执行完逻辑,但是并不会在stub.PutState的时候写数据库。

  3. endorser把这些读写集连同签名返回给Client SDK。

  4. SDK再把读写集发送给Orderer节点,Orderer节点是进行共识的排序节点,在测试的情况下,只启动一个orderer节点,没有容错。在生产环境,要进行Crash容错,需要启用Zookeeper和Kafka。在1.0中移除了拜占庭容错,没有0.6的PBFT,也没有传说中的SBFT,不得不说是一个遗憾。

  5. Orderer节点只是负责排序和打包工作,处理的结果是一个Batch的Transactions,也就是一个Block,这个Block的产生有两种情况,一种情况是Transaction很多,Block的大小达到了设定的大小,而另一种情况是Transaction很少,没有达到设定的大小,那么Orderer就会等,等到大小足够大或者超时时间。这些设置是在configtx.yaml中设定的。

  6. 打包好的一堆Transactions会发送给Committer Peer提交节点,

  7. 提交节点收到Orderer节点的数据后,会先进行VSCC校验,检查Block的数据是否正确。接下来是对每个Transaction的验证,主要是验证Transaction中的读写数据集是否与State Database的数据版本一致。验证完Block中的所有Transactions后,提交节点会把吧Block写入区块链。然后把所有验证通过的Transaction的读写集中的写的部分写入State Database。另外对于区块链,本身是文件系统,不是数据库,所有也会有把区块中的数据在LevelDB中建立索引。

查询a账户的cli命令是:

640?wx_fmt=png&wxfrom=5&wx_lazy=1

这样系统会调用ChainCode中的invoke函数,但是传入的function name是query。也就是会执行如下代码:

640?wx_fmt=jpeg&wxfrom=5&wx_lazy=1

我们可以看到,我们只是调用了stub.GetState(A),并没有写操作,那么会像前面说的Transaction一样那么复杂吗?答案是不会。因为调用调用的是peer query,在代码中,只有invoke的时候才会执行Transaction步骤中的4、5、6、7.但是如果我们使用peer invoke,那么会怎么样呢?比如如下的命令:

peer chaincode invoke -o orderer.example.com:7050  --tls $CORE_PEER_TLS_ENABLED --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/cacerts/ca.example.com-cert.pem  -C mychannel -n mycc -c '{"Args":["query","a"]}'

那么从代码上来看,虽然我们是一个查询,却会以Transaction的生命周期来处理。

Fabric不支持对同一个数据的并发事务处理,也就是说,如果我们同时运行了a->b 10元,b->a 10元,那么只会第一条Transaction成功,而第二条失败。因为在Committer节点进行读写集版本验证的时候,第二条Transaction会验证失败。这是我完全无法接受的一点!

Fabric是异步的系统,在Endorser的时候a->b 10元,b->a 10元都会返回给SDK成功,而第二条Transaction在Committer验证失败后不进行State Database的写入,但是并不会通知Client SDK,所以必须使用EventHub通知Client或者Client重新查询才能知道是否写入成功。

不管在提交节点对事务的读写数据版本验证是否通过,因为Block已经在Orderer节点生成了,所以Block是被整块写入区块链的,而在State Database不会写入,所以会在Transaction之外的地方标识该Transaction是无效的。

著作权作者所有,转载请注明出处。

区块链技术交流qq群:634713958

区块链兄弟微信公众号请扫码关注

attachments-2017-12-Aefi38c55a39c050af12a.

  • 发表于 2018-01-08 11:07
  • 阅读 ( 1828 )
  • 分类:hyperledger

0 条评论

请先 登录 后评论
不写代码的码农
社区运营-小链

区块链兄弟社区运营管理

244 篇文章

作家榜 »

  1. 社区运营-小以 430 文章
  2. 社区运营-小链 244 文章
  3. 于中阳Mercina-zy 78 文章
  4. 涂晶 71 文章
  5. 李晓琼 45 文章
  6. 兄弟连区块链培训 41 文章
  7. 吴寿鹤 36 文章
  8. John-smith 26 文章