学习记录:fabric(6)- 系统设计(3)
新开一节,继续项目把mysql打包进peer的镜像里给peer添加深入检查peer的广播和通信,将对数据库同步机制放进去密钥先写到core.yaml中,或者包括一些自定义配置也可以加进去。考虑如何将结果返回到客户端。也许可以直接共识成功即发送给链码,这里就需要假设保存到数据库一定成功了。记录不知道为啥docker非常慢。生成docker很慢,似乎是因为下载东西,但是这也不好弄,现在没有v2ray的
新开一节,继续项目
- 把mysql打包进peer的镜像里
- 给peer添加
- 深入检查peer的广播和通信,将对数据库同步机制放进去
- 密钥先写到core.yaml中,或者包括一些自定义配置也可以加进去。
- 考虑如何将结果返回到客户端。也许可以直接共识成功即发送给链码,这里就需要假设保存到数据库一定成功了。
记录
不知道为啥docker非常慢。生成docker很慢,似乎是因为下载东西,但是这也不好弄,现在没有v2ray的链接可以用了。手贱,就不该删除docker的缓存。不过也是没办法,电脑上的空间太小了,光虚拟机就占用了160+G,又不能删,因为还有用。
不管怎么说,现在编译成功了,试一下把之前链码开发的镜像换成这个。
现在有个问题,那就是docker建议每个容器只有一个进程,那么就改成这样实现。
peer和mysql还是两个容器,peer通过环境变量的方式来设置连接地点,默认是本机的ip,端口也得弄成环境变量的方式。
所以现在这样:1看一下peer的环境变量怎么读取进来的(config)2给mysql添加连接管理逻辑,主要是看一下释放连接3看一下peer的启动位置,给mysql添加连接逻辑
成功修改了peer node start的说明。
通过 viper.GetString(“mysql.syncTableName”) 这样的方式来获取core.yaml中的配置,第一条搞定。
看看能不能通过让链码也读取core.yaml,这样很多东西就能共享。
是不是因为go的并发特性,所以不需要消息队列???
明天接着弄,今天先休息了。
这里需要看一下能不能连接mysql,因为要写入数据,至少可以确定的是增删改都要放进共识之后的后处理。
跑了一天回来,接着弄。
过程中有看代码的记录,可以看这里:《学习记录:fabric(10)- fabric本身编译(2)》
现在已经添加了mysql的启动逻辑。
那么接下来的问题:1区块上链后的数据操作2数据加密逻辑
先要找到区块入账本的地方,然后读取账本内容。执行写入账本的SQL语句。
peer的5个服务,op监听,gossip服务,发送服务,链码支持服务,背书服务
链码支持服务有这么一句话:ChaincodeSupportServer is the server API for ChaincodeSupport service
看来还是得从这里入手看一下。
似乎链码是单独容器,那么有个问题,那就是链码和peer是通过网络通信交互的。那这还是得看到底是哪里。
突然发现日志很有用,格式是这样的:
首先是容器名(peer0.org1.example.com),时间(UTC),方括号里是注册日志器的名称(endorser),然后是日志的方法名(callChaincode),然后是信息等级(INFO),最后才是日志内容。通过这些名称可以在goland中很容易找到相关地方。
调用了一下链码,看一下这个地方有没有打包。分析一下这个日志(蓝色和紫红色部分是链码里我自己的日志):
可以只看一个节点
[endorser] callChaincode 是调用链码背书的地方。
很多地方都是抽象定义,而且很多最基础的定义都放在fabric-proto-go里面,搞得很难找整个调用逻辑,比C++还费劲。
ProcessProposal,这是proto定义的EndorerServer。里面的ProcessProposal接口,在auth里被拦截器包装了一次,然后实现是在start.go里面最下面,但是,调用的时候,这里我没搞清楚,
这样的写法,感觉像是递归了。不知道怎么调用过去的。可能还有其他地方的代码我没看到吧。
总之进入到fabric/core/endorser/endorser.go里面,也有这个方法,然后就是真正的处理逻辑了。
这个里面类Endorser的实例化在start.go里面
实例化之后用权限包了一次,
然后放到了服务上面。从peerServer上启动了。实际上peerServer上总共注册了3个服务,背书,快照,deliver。
那大概就是peerServer接收到grpc的请求之后,发现是背书,转给了endorser来做。
因为proto-go里面看不到原本的proto文件,所以生成的pb文件看起来就会有点难受。
这里启动服务后,通过peer.pb.go里的RegisterEndorserServer给peerServer上注册了服务,这属于grpc的常规操作了。
接下来肯定是有某个请求,某个响应在这个服务上运作。真正执行任务的是_Endorser_ProcessProposal_Handler这个接口,在这里面调用了ProcessProposal,这应该是真正的地方了,然后实现是在endorser.go里面。
换句话说,实例化是Endorser,实现了ProcessProposal接口,然后整体大层面都是面向接口编程的,所以,这里运行的时候,直接调用的就是Endorser这个类的内容。
所以很大程度上,应该是整体的结构是在fabric-proto-go里面定义的。这外面很多都仅仅是实现而已。
proposal.pb.go里面是客户端提案的结构。数据大都是byte数组,应该都是可序列化的json和字符串
再回到日志,两个节点背书完后,到orderer运行。
2021-9-17
还是得找到block整个流程
分析一下完整的debug日志(只启动了一个peer的debug):
分析的结果,还是要找一下位置,或者可以先尝试把数据库操作放到kvledger里面。
go语言中的接口都是大写字母开头,是对外的,仅在struct上实现的是小写,是内部用的,内聚。
fabric喜欢用provider,对应一个Initializer用来封装初始化过程。
有时候就仅仅是为了调用其他模块的资源,搞一个provider的接口,不过从逻辑上来说也说得通,而且似乎也有点感觉到go语言的特点了,这就是完全的接口定义和实现的拆分,二者几乎毫不相关。
2021-9-24
找到区块中,交易中SQL类型定义字段,然后取出,现在是payload中的transaction不知道怎么解析。
go语言中区块读写集的读取:
Block->BlockData->[]Envelope->Payload->Transaction->[]TransactionAction->ChaincodeActionPayload->ChaincodeEndorsedAction->ProposalResponsePayload->Extension
注释中说,extension应当被反序列化为特定类型的消息。
相关的proto文件定义在fabric-proto项目中
很奇怪,找到的地方,不知道怎么回事,解析不出来相应信息,就是找不到读写集。rwset。这个不知道用什么层级解析出来的.
看了fabric-proto的定义,知道了,全都是byte数组,定义的时候就不是完全结构化的,所以必须强转。
通过借用已有的代码,果然,这样可以解析出来txrwset,这样就可以看到SQL语句
表名是直接查同步表,这样快很多。
那么双向加密。。表名似乎也不需要,表名传过来的肯定都是hex过的。那么对于字段,只需要检查string类型的,然后进行hex转换即可。
但是如果查询是放在链码里,双向则有个问题。
有个问题,怎么把key保存到文件里,然后还得让链码读取到?
现在先跳过双向加密,看看如何进行同步。
换句话说,分两部分:校验和拉取数据。我认为,重启则直接从orderer拉取,先看看orderer有没有账本,如果有,则最好也存数据库。
显然是有的。在/var/hyperledger/produciton/orderer/chains下面。有一个blockfile文件。
那看来还要看一下orderer里面打包区块和写入区块的调用地方,应该是复用了代码的,查一下日志。
orderer的账本和peer的不一样,orderer的是在fabric/common/ledger中的相关接口,而且似乎仅仅是一个leveldb文件数据库。
peer的kvledger,其中的存储用的也是fabric/common/ledger/blkstorage中的blockStore,看来orderer的账本要比peer简单多了,先看看这里如何处理区块吧。还有就是看看peer在丢失账本之后,在哪里拉取数据。
peer应该有一个上线时候的账本检测,
idStore,BlockStore,VersionedDB,HistoryDB四种不同的DB,只有blockstore存在blockfile中,blockfile就是文件存储,其它都是数据库,一般用leveldb。
peer node reset命令是这么说的: 将所有通道重置为genesis块。执行命令时,对等方必须脱机。当对等方在重置后启动时,它将从orderer或另一个peer接收以块编号1开始的块,以重建块存储和状态数据库。如果对等方包含从快照引导的任何通道,则不支持该命令
所以还是的和找一下start命令中的检查在哪里,是不是还是idstore。。。
看ledger_interface.go这里,发现好像应该把数据库操作放在StateListener.HandleStateUpdates中。
go语言的接口定义,可以保证需求者和提供者完全分开。至少在fabric中看到的是这样完成了模块化,当然,造成的结果是,不得不在注释里写上是哪个模块会提供相应的功能,而在实现的对应函数上,也往往要写上是实现了哪个接口,换句话说,struct和interface的多对多使得查看会比较乱。有利有弊,在修改或者在对项目很熟悉的时候,改动会变得及其容易,但是当不熟悉的时候,就会变得很繁琐,需要一个很陡峭的学习曲线。
在项目中,有两类测试,mock和test,mock看这里https://www.jianshu.com/p/5582ff72170a。
可能还是在账本存储部分的某个地方,有高度检测。
令人头大,2.3之后引入了快照系统,这才是尴尬的存在。https://cloud.tencent.com/developer/article/1841712
让同步变得更加复杂了.
还是要找到如何进行同步,不然这个很难收尾。
其实还是主要在传输上,就是,节点之间到底如何传输数据的。
现在写一下专利。
零散知识记录
- docker的哲学是每一个容器只有一个指令运行
- 感悟:比特币是通过激励机制让网络大部分节点能够同步。不然会出现大量的掉节点。
参考
- https://www.cnblogs.com/cbkj-xd/p/11072761.html
更多推荐
所有评论(0)