fabric源码解析1——线头

来源:互联网 发布:windows 删除文件夹 编辑:程序博客网 时间:2024/04/29 12:04

fabric源码解析1——线头

Getting Started

简单提一下Fabric说明文档中的Getting Started部分。说明文档下载地址在 http://hyperledger-fabric.readthedocs.io/en/latest/ 。其中网址中有en的,就说明各种语言版本的说明文档可能在开发中,希望能尽快出中文版的,毕竟在有些概念上,个人在英语上的理解还是有一点困难。Getting Started主要引导你做的以下事情:

  • 根据Prerequisites的要求部署环境,安装docker,go等。
  • 下载要操作体验的单独的一个小例子及所需的镜像,解压后是一个release目录,以下的步骤都是操作这个小例子中的文件,脚本或程序。
  • 用configtxgen和cryptogen生成用于区域链的配置文件,gensis块文件,交易配置文件。这两个工具也可手工生成。
  • 用shell脚本运行docker镜像。
  • 执行peer命令,部署区域链,执行一个实际交易,把a的10块钱转给b,然后查询一下。

找到线头

入手一个陌生的项目,我这水平的只能从main函数开始了。关于这点也想了很久,也咨询过一些人,从main函数入手算是最快也最容易的方法了。幸而go语言传承了C的不少特点,而我们还有grep这样搜索的利器。在Fabric根目录执行如下命令——递归搜索所有go文件中的main函数,并将结果导入func_main.txt文件:

grep "func main" * -r -n --include=*.go > func_main.txt

打开func_main.txt文件,会发现大约七八十条记录,但是很有规律,如下:

这里写图片描述

可以看到,结果只集中在bddtests,common,core,examples,orderer,peer,vendor这几个目录。

秉承学习的姿态,可以将结果分为三类:可以直接排除掉的结果,可辅助研究源码的结果,源码本身的结果。

首先可以直接排除掉vendor中的所有结果,因为vendor目录下都是go语言使用的第三方库的代码。其次目录中有test,example,sample字眼的,都属于测试和示例范畴的代码,可以参考辅助我们研究源码,因为有时候看不懂源码时,看看例子是怎么用的,可能就知道这个函数是要干什么或者要怎么使用了。最后是源码本身,也是我们要研究的线头,经过以上两步的排除,剩下的,也就是源码:

  • 2 common/configtx/tool/configtxgen/main.go:310:func mainc(){
  • 3 common/tools/cryptogen/main.go:203:func main() {
  • 26 orderer/main.go:50:func main() {
  • 31 peer/main.go:77:func main() {

操作过Fabric文档中Getting Started的话,很容易就能推测出2,3行这两个main是用于生成configtxgen和cryptogen这两个工具。31行的main函数是用于生成peer程序,因为操作交易时在命令行使用到了peer …。Getting Started中虽然没有明显使用到关于orderer的操作,但既然被单独赋予了main函数,就说明其是自成一体,自成一个服务,最终生成会一个orderer程序。

这样看来,研究整个项目源码所要扯出的线头是不是一目了然了?

验证线头

Getting Started 入手,因为能作为一个项目的Getting Started,肯定是属于麻雀虽小五脏俱全的。

  1. 我们知道,Getting Started用脚本启动了一些容器,并将这些容器作为分布的客户端进行区域链的部署,传递消息和交易等操作。启动容器操作的是 ./network_setup.sh up 命令,也就是使用的network_setup.sh脚本,查看该文件,可以知道该命令最终执行的是该脚本中的networkUp函数。理解这一步,需要你知道基本的脚本知识。

  2. networkUp函数主要运行了generateCfgTrx.sh脚本(进行了两个工具的生成进而使用两个工具生成区域链的必要的配置文件)和 docker-compose -f $COMPOSE_FILE up -d命令,其中docker-compose就是根据指定yaml配置文件启动相应容器的命令。该配置文件为docker-compose-no-tls.yaml($COMPOSE_FILE的值),这又将我们的目光转移到了docker-compose-no-tls.yaml配置文件。理解这一步,需要你知道基本的docker容器操作和docker-compose命令。

  3. 从yaml配置文件中我们可以看出,docker-compose命令启动了orderer0,peer0,peer1,peer2,peer3,cli六个容器服务。也就是说,这六个容器中所运行的服务覆盖了我们所要研究的源码中所会生成的主要服务,也都是最重要的核心服务。理解这一步,以及下面的每一步,需要你理解yaml配置文件的基本配置项。

  4. orderer0容器的command选项为orderer,即启动orderer容器之时默认就启动了orderer程序,与我们牵扯出的orderer目录下的main函数所生成的orderer程序就对应上了。这也说明,启动容器的时候,orderer程序已经存在与该容器之中。

  5. 每个peer容器没有command选项,但有extends选项,其加载的是peer-base目录下的peer-base-no-tls.yaml 配置文件。打开该文件,我们看到其加载的peer-base服务时所默认执行的commandpeer node start –peer-defaultchain=false ,即执行的是peer命令,这就和我们牵扯出的peer的main函数所生成的peer程序对应上了。这也说明,启动容器的时候,peer程序已经存在与该容器之中。

  6. cli容器服务的command选项是 /bin/bash -c ‘./scripts/script.sh ${CHANNEL_NAME}; ‘ ,即启动容器时默认执行scripts目录下的script.sh脚本。打开script.sh脚本,我们发现最终所执行的命令都是peer channel…peer chaincode…, 即执行的是peer命令,这也和我们牵扯出的peer的main函数所生成的peer程序对应上了。

  7. 根据每个容器的depends_on选项(依赖关系),我们甚至可以推测出在区域链中,哪些命令和服务是必须先于一些命令服务运行起来的。orderer容器先起,各个peer之间其实可以没有先后顺序但是都必须后与orderer容器,最后是cli容器。这说明,orderer服务必须先于peer服务,peer node start命令必须先于peer channel或peer chaincode命令。

>
最终,以上的这些指向将我们引向了 orderer和peer的main函数 ,也就是研究整个项目源码的线头。接下来的源码分析也是先将从peer的main函数这个线头开始。

源码中的简拼

能被Linux Foundation支持的项目,自然差不了。代码瞄上几眼就知道是很优秀的代码。代码中很多地方都是英语的全拼,有时候不需要看ReadMe.md或注释都能知道这个目录或函数是干嘛用的。但有些目录,文件名也有用首字母的,知道这些简拼对于顺利阅读代码也是很有帮助的。以下是我在阅读代码中收集的简拼,各位可以看一下,翻译不到之处还请指正。

MSP:Membership service provider 会员服务提供者
BCCSP:blockchain(前两个字母BC) cryptographic service provider 区域链加密服务提供者
ab:atomic broadcast原子(操作)广播
lscc:lifecycle(L) system(S) chaincode(CC)生命周期系统链码
Spec:Specification,规格标准,详细说明
KV:key-value 键-值
CDS:ChaincodeDeploymentSpec
CIS:ChaincodeInvocationSpec
mgmt:management
SW:software-based
AB:AtomicBroadcast
GB:genesis block,创世纪的block,也就是区域链中的第一个块
CC或cc:chaincode
SCC或scc:system chaincode
cscc:configer system chaincode
lscc:lifecycle system chaincode
escc:endorser system chaincode
vscc:validator system chaincode
qscc:querier system chaincode
alg:algorithm 算法
mcs:mspMessageCryptoService
mock:假装,学样子,模仿的意思,基本上是服务于xxx_test.go的,即用于测试的
Gossip:一种使分布结点达到状态最终一致的算法
attr:attribute
FsBlockStore:file system block store
vdb:versioned database 也就是状态数据库
RTEnv:runtime environment运行环境
pkcs11:pcks#11,一种公匙加密标准,有一套叫做Cryptoki的接口,是一组平台设备无关的API
MCS:mspMessageCryptoService,消息加密服务
sa:SecurityAdvisor
impl:implement,好多处XXX.go和XXXimpl.go是对应的,前者是用于接口或者定义的,后者是实现该接口或定义的
FSM:finite state machine 有限状态机
FS:filesystem 文件系统
blk:block
cli:command line interface 命令行界面
CFG:FABRIC_CFG_PATH中的,应该是config的意思
mgr:manager
cpinfo:checkpoint information,检查点信息
DevMode:development mode,开发模式
Reg:register,注册,登记
hdr:header
impl:implement
oid:ObjectIdentifier,对象标识符
ou或OU:organizational unit
CRL:certificate revocation list,废除证书列表
prop:proposal,申请,交易所发送的申请
ACL:Access Control List,访问控制列表
rwset:read/write set,读写集
tx,Tx:transaction,交易
CSP:cryptographic service provider,BCCSP的后三个字母,加密服务提供者
opt:option,选项
opts:options,多个选项
SKI:当前证书标识,所谓标识,一般是对公匙进行一下hash
AKI:签署方的SKI,也就是签署方的公匙标识
HSM:Hardware Security Modules
ks:KeyStore,Key存储,这个key指的是用于签名的公匙私匙
oid:OBJECT IDENTIFIER,对象身份标识

源码中的惯例

源码中有很多惯例,也是大型项目(这就跟语言无关了)中需要有的很优秀的习惯。这一点也是值得学习的。目前个人发现的惯例有以下几点,对于阅读源码也是很有帮助的:

  • common目录是其所在的层级中的公用的代码。A/common,则说明该common中的代码在A范围中公用,A/B/C/common,则说明该common中的代码在C目录中公用。
  • mock目录是用于方便go测试文件(即众多的XXX_test.go)中进行测试所需要的模拟数据/环境等。研究源码的初始阶段可忽略该类目录。
  • XXX.go与XXXimpl.go是定义与实现的配套代码。
  • 同一事务分别存在与不同主题下。如protos目录下的peer与core目录下的peer都是peer相关的代码,但是相关主题的代码却分开放置。
  • no-tls标有no-tls的与说明相关代码未使用安全传输协议(TLS)。
  • util文件夹,一般都是该层级或该主题源码中具有辅助性,工具性的代码。

源码目录的基本结构

其实关于源码目录的基本结构应该是自己在探索源码的过程中自己自然而然的明白的。在此只做记录使用,不建议各位看这部分,而是建议各位在自己阅读源码过程中自己不断的翻目录,自己慢慢弄懂。最开始研究源码,需要关注的也就是如下这些目录了。

  • bcssp 加密服务代码目录
  • common 全局公用代码目录
  • core 核心功能代码目录
  • docs 以.rst文件为核心,可编译生成文档。说明文档的目录
  • events 事件代码目录,用于生产和消费信息
  • examples 示例目录
  • gossip 本意是绯闻的意思,是一种可达到去中心化,有一定容错能力且可达到最终一致的传播算法
  • msp 会员服务代码目录
  • orderer 就理解成orderer目录就好,orderer也算是区域链中的专用名词,用于消息的订阅与分发处理
  • protos 原型目录,定义个各种原型和生成的对应的XXX.pb.go源码
  • vendor 原意是商贩,在此就是存放go中使用的全部的各种第三方包