热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

Fabric源码阅读与编译

前言Hyperledgerfabric,什么是Hypeledger,什么是Fabric?Hypeledger从字面上的意思是超级账本,它是Linux基金会于2015年12月启动了名为“超级

前言

Hyperledger fabric,什么是Hypeledger,什么是Fabric?Hypeledger从字面上的意思是超级账本,它是Linux基金会于2015年12月启动了名为“超级账本”的开源项目,旨在推动各方协作,共同打造基于区块链的企业级分布式账本底层技术,用于构建支撑业务的行业应用和平台,以便支持各种各样的商业应用场景。Fabric是超级账本中的一个项目,为商业区块链应用提供底层支持.Fabric是由IBM、数字资产和Blockstream等三家公司的代码整合而成.

准备工作

  1. 环境准备(Ubuntu)

    a. 安装go的开发环境 
    b. 安装git工具及环境配置 
    c. 利用git下载Fabric源码. 
        git clone https://github.com/hyperledger/fabric.git (最好下载在go配置路径的src文件夹下)

  2. 技能准备

    2.1 Fabric项目主要是使用go语言进行编写,所有需要具备go语言的基础知识.

    a.基本的go语法知识. 
    b.go的并发知识. 
    c.一定的项目架构的设计模式思想

    2.2 通过Fabric项目部署的peer网络节点间的数据交互是属于不同的service(进程)间的通信,使用的是gRPC(谷歌的远程过程调用协议).所以需要掌握gRPC的基本用法和知识.而交互的数据格式使用的是 Protocol Buffers.

阅读方式-HOW

step 1 了解Fabric项目下的各个模块包的作用,Fabric源码项目是由不同的模块包组成的,了解各个模块包的作用有助于快速查找到你需要阅读的源码类.模块和包划分可参考http://qukuaiwang.com.cn/news/722.html. Fabric项目主要有三大模块peer和Order和fabric-ca,其中fabric-ca模块需要另外下源码.本文讨论的是Fabric的源码,只包括peer和Order两个模块.其他的Fabric源码中的不同的包都是为这两个模块服务.

step 2选定你要阅读和理解的模块部分. 
这里写图片描述
图中peer和o-service的属于Fabric源码中的模块内容.


step 3 模块的源码阅读(举例说明) 
注意:Docker部署Fabric网络需要的镜像是通过编译Fabric的源码的模块部分而来的,比如说,Fabric网络中的Peer镜像是通过make Peer模块的源码而来的. 
eg如果选定的是阅读Order模块的源码,需要对照利用Order模块的源码编译生成的Order Docker镜像来启动的Order容器.

3.1下图是fabric部署的网络节点启动的docker容器展示图.—–图中可以看到最后一个容器启动的信息启动的是Order容器,启动时候运行的命令是"orderer",容器服务开放的端口是7050端口,用于gRPC服务通信. 
这里写图片描述
3.2 进入到Fabric源码目录的文件夹,找到main.go入口文件. 
这里写图片描述

3.3 main.go入口文件的代码理解

说明main.go文件中的第三方包 
kingpin - 一个Go(golang)命令行和flag解析器支持子命令.

//命令变量的的初始化,appvar (    app = kingpin.New("orderer", "Hyperledger Fabric orderer node")    start   = app.Command("start", "Start the orderer node").Default()    version = app.Command("version", "Show version information"))//入口函数mainfunc main() { //开始解析命令kingpin    switch kingpin.MustParse(app.Parse(os.Args[1:])) {    // "start" command    case start.FullCommand():        logger.Infof("Starting %s", metadata.GetVersionInfo())        conf := config.Load()        initializeLoggingLevel(conf)        initializeProfilingService(conf)        grpcServer := initializeGrpcServer(conf)//初始化gPRC服务配置        initializeLocalMsp(conf)        signer := localmsp.NewSigner()        manager := initializeMultiChainManager(conf, signer)        server := NewServer(manager, signer)        ab.RegisterAtomicBroadcastServer(grpcServer.Server(), server)        logger.Info("Beginning to serve requests")        grpcServer.Start()//启动服务    // "version" command    case version.FullCommand():        fmt.Println(metadata.GetVersionInfo())    }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30

1.Order的Docker容器运行起来的时候初始化命令是”orderer”,而初始化命令参数flag默认的是”start”,start = app.Command("start", "Start the orderer node").Default() 
2.解析命令是switch的是”start” command,运行的是start.FullCommand()分支下的代码,执行的是一些初始化的操作,接下来就可以具体查看Order模块的源码初始化的细节.

参考链接

Protocol Buffers的学习笔记 

gRPC学习笔记

2.。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。

源码的编译-Why? 
Fabric源码的编译是建立在已经基本掌握了Fabric的部分模块或者很多模块的代码的基础上.但是为什么要编译Fabric的源码呢,大神们不是已经写好了Fabric这个项目框架并编译好了吗,拿来用不就好了吗?

1.部署Fabric网络的docker容器是通过编译Fabric里的peer/Order/fabric-ca/模块的代码形docker镜像创建的.固有的已编译好的镜像让我们要开发的系统也禁锢住了,每个要开发的应用系统都有自身的特点,我们需要通过编译Fabric的改写的模块代码生成应用系统所需要的镜像.比如说,阿里通过基于OpenJDK定制的TaobaoVM,也是自身编译的软件开发包. 
2.编译Fabric源码可以验证自己的想法,当阅读Fabric源码时候,代码如何的运行只是通过我们理论上的猜想,通过实际的编译代码可以验证我们的猜想. 
3.定位错误,修改bug.源码的编译是建立在Fabric的源码的阅读上的,当系统运行的日志里出现错误时,根据错误提示能定位到源码中的错误点,根据源码能修改bug.

准备工作

1.编译环境的安装,go的安装,Fabric的源码下载,在Fabric的源码的阅读一篇中讲述了. 
2.安装其他必要的组件.

假设GOPATH为/home/gopath该文件夹下有两个文件夹:src用于存放Fabric源码.bin用于存放go编译好的可执行文件. 
2.1安装go的包管理工具gopm
export GOPATH=/home/gopath 
go get -u github.com/gpmgo/gopm
 
/home/gopath/bin目录下将有gopm,go get是下载和编译的意思 
2.2通过 gopm安装 goimports.(go代码格式化工具,自动修正import的package) 
export GOPATH=/home/gopath 
gopm get -g -d golang.org/x/tools/cmd/goimports 
再使用 go install 安装 goimports 
go install golang.org/x/tools/cmd/goimports 
/home/gopath/bin目录下将有goimports
 
2.3安装 gocov(go的单元测试覆盖率检查工具) 
GOPATH=/home/gopath 
gopm get -g -d golang.org/x/tools/cover 
gopm get -g -d github.com/axw/gocov/gocov 
go install github.com/axw/gocov/gocov 
/home/gopath/bin目录下将有gocov
 
2.4安装 gocov-xml 
GOPATH=/home/gopath 
gopm get -g -d github.com/AlekSi/gocov-xml 
go install github.com/AlekSi/gocov-xml 
/home/gopath/bin目录下将有 gocov-xml
 
2.5安装其他组件 
yum install -y gcc libtool libltdl-dev libtool-ltdl-devel openssl

3.Makefile文件的语法理解. 
Fabric的源码镜像是通过make按照Makefile中文件的编译规则来编译镜像的.

简要介绍Makefile的语法规则. 
3.1 Makefile文件的一般形式. 
target ... : prerequisites ... 
command 
... 
...
 
其中表示多个. 
target是一个目标文件,可以是Object File,也可以是执行文件。也可以是一个标签(Label),make就不会自动去找lable后的文件的依赖性,也就不会自动执行其后所定义的命令。 需要明确使用make Label。才会执行命令。 
prerequisites是要生成target所需要的文件或是目标。 
command也就是make需要执行的命令。(任意的Shell命令) 
说明,上面的一般形式是一个文件的依赖关系.target这一个或多个的目标文件依赖于prerequisites中的文件,其生成规则定义在command中。特别的,prerequisites中如果有一个以上的文件比target文件要新的话,command所定义的命令就会被执行。这就是Makefile的规则。 
3.2依赖关系的实质上就是说明了目标文件是由哪些文件生成的,换言之,目标文件是哪些文件更新的。 
3.3伪目标使用方法的终端编译命令是make lable,避免当前文件夹下也有文件叫lable。 
伪目标eg: 
.PHONY lable.PHONY避免同名 
lable: 
rm *.o 

终端使用make labe,执行的操作是删除所有的.o文件. 
一般形式的eg : 
main.o : main.c defs.h 
cc -c main.c 
#make最后生成 main.o文件依赖于main.c defs.h两个文件,cc -c main.c执行可执行文件main.c进行编译. 

3.4 Makefile中的第一个目标会被作为其默认目标。

How

1.进入Fabric源码目录/home/gopath/src/hyperledger/fabric.并添加gopath的环境变量,一定要加. 
export GOPATH= /home/gopath 
sudo su 

2.编译生成 protoc-gen-go 
cd $GOPATH 
gopm get -g -d github.com/golang/protobuf/protoc-gen-go 
go install github.com/golang/protobuf/protoc-gen-go 
# /home/gopath/bin出现protoc-gen-go执行文件
 
3.根据Fabric源码目录下的Makefile文件中的说明.在源码目录下打开终端,根据下图1中方框的targets伪目标,选择你要编译的target,执行命令make peer/all/orderer... 
这里写图片描述 
执行make命令后会在当前文件夹下生成一个build文件夹.编译后的镜像或者可运行工具都是在这个文件夹里找.

编译peer模块的代码示例

说明:peer网络节点启动时运行的命令是peer node start,实际上Fabric网络节点的peer docker容器中执行的便是通过Fabric源码编译的peer可执行文件来操作peer下的命令.本例中在peer节点下通过修改代码并编译来添加test命令. 
1.在/home/gopath/src/hyperledger/fabric/peer下添加test包.并在test包下创建test.go文件.

package testimport (    "github.com/hyperledger/fabric/common/flogging"    "github.com/spf13/cobra")var logger = flogging.MustGetLogger("testCommand")func Cmd() *cobra.Command {    return testCommond}var testCommOnd= &cobra.Command{    Use:   "test",    Short: "test the node.",    Long:  `test a node that interacts with the network.`,    Run: func(cmd *cobra.Command, args []string) {        logger.Info("Build test by JinaWenJun----------------------")    },}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

2.在/home/gopath/src/hyperledger/fabric/peer下的main.go文件中添加

    mainCmd.AddCommand(version.Cmd())    mainCmd.AddCommand(node.Cmd())    mainCmd.AddCommand(chaincode.Cmd(nil))    mainCmd.AddCommand(clilogging.Cmd(nil))    mainCmd.AddCommand(channel.Cmd(nil))    //添加的另外一个test命令,并在前面导入包"github.com/hyperledger/fabric/peer/test"    mainCmd.AddCommand(test.Cmd())
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

3.在源码目录下打开终端进行编译 make peer,在/home/gopath/src/hyperledger/fabric/build/bin下将会生成可执行文件peer.将该文件拷贝到/home/gopath/bin下测试新添加的test 命令.(模拟在peer docker的容器下peer命令的执行). 
4.打开终端,执行peer test 
这里写图片描述

遇到的问题解决方案

1.终端执行make 命令时,出现没有那个文件或目录如图, 
这里写图片描述
方法:需要在终端下添加环境变量,执行export GOPATH= /home/gopath

2.当因为网速终端卡住时,需要将Makefile文件中的curl部分删除.手动下载相应的文件chaintool目录/build/bin下面. 
chaintool 
3.当出现文件找不到或者命令找不到,如图 
这里写图片描述
方法:终端执行下面两条命令,将命令复制进去 
cp $GOPATH/bin/protoc-gen-go $GOPATH/src/github.com/hyperledger/fabric/build/docker/gotools/bin/ 

cp $GOPATH/bin/gocov $GOPATH/src/github.com/hyperledger/fabric/build/docker/gotools/bin/

4.当终端make peer出现下图错误时候. 
这里写图片描述
方法:根据错误提示core/chaincode/ccproviderimpl.go:20:2:不能找到context.进入到相应的文件ccproviderimpl.go修改. 
这里写图片描述 
如果在出现提示哪里不能找到”context”到指定的文件下按照上述形式修改即可. 
编译成功: 
这里写图片描述相应的 build/bin/文件夹下有peer可执行文件



推荐阅读
  • Go Cobra命令行工具入门教程
    本文介绍了Go语言实现的命令行工具Cobra的基本概念、安装方法和入门实践。Cobra被广泛应用于各种项目中,如Kubernetes、Hugo和Github CLI等。通过使用Cobra,我们可以快速创建命令行工具,适用于写测试脚本和各种服务的Admin CLI。文章还通过一个简单的demo演示了Cobra的使用方法。 ... [详细]
  • Python已成为全球最受欢迎的编程语言之一,然而Python程序的安全运行存在一定的风险。本文介绍了Python程序安全运行需要满足的三个条件,即系统路径上的每个条目都处于安全的位置、"主脚本"所在的目录始终位于系统路径中、若python命令使用-c和-m选项,调用程序的目录也必须是安全的。同时,文章还提出了一些预防措施,如避免将下载文件夹作为当前工作目录、使用pip所在路径而不是直接使用python命令等。对于初学Python的读者来说,这些内容将有所帮助。 ... [详细]
  • 本文介绍了在go语言中利用(*interface{})(nil)传递参数类型的原理及应用。通过分析Martini框架中的injector类型的声明,解释了values映射表的作用以及parent Injector的含义。同时,讨论了该技术在实际开发中的应用场景。 ... [详细]
  • 基于.NET Core框架nacos的简单应用
    什么是Nacos?服务(Service)是Nacos世界的一等公民。Nacos支持 ... [详细]
  • 微软头条实习生分享深度学习自学指南
    本文介绍了一位微软头条实习生自学深度学习的经验分享,包括学习资源推荐、重要基础知识的学习要点等。作者强调了学好Python和数学基础的重要性,并提供了一些建议。 ... [详细]
  • Java太阳系小游戏分析和源码详解
    本文介绍了一个基于Java的太阳系小游戏的分析和源码详解。通过对面向对象的知识的学习和实践,作者实现了太阳系各行星绕太阳转的效果。文章详细介绍了游戏的设计思路和源码结构,包括工具类、常量、图片加载、面板等。通过这个小游戏的制作,读者可以巩固和应用所学的知识,如类的继承、方法的重载与重写、多态和封装等。 ... [详细]
  • Centos7.6安装Gitlab教程及注意事项
    本文介绍了在Centos7.6系统下安装Gitlab的详细教程,并提供了一些注意事项。教程包括查看系统版本、安装必要的软件包、配置防火墙等步骤。同时,还强调了使用阿里云服务器时的特殊配置需求,以及建议至少4GB的可用RAM来运行GitLab。 ... [详细]
  • 本文介绍了Android 7的学习笔记总结,包括最新的移动架构视频、大厂安卓面试真题和项目实战源码讲义。同时还分享了开源的完整内容,并提醒读者在使用FileProvider适配时要注意不同模块的AndroidManfiest.xml中配置的xml文件名必须不同,否则会出现问题。 ... [详细]
  • 本文介绍了iOS数据库Sqlite的SQL语句分类和常见约束关键字。SQL语句分为DDL、DML和DQL三种类型,其中DDL语句用于定义、删除和修改数据表,关键字包括create、drop和alter。常见约束关键字包括if not exists、if exists、primary key、autoincrement、not null和default。此外,还介绍了常见的数据库数据类型,包括integer、text和real。 ... [详细]
  • Spring学习(4):Spring管理对象之间的关联关系
    本文是关于Spring学习的第四篇文章,讲述了Spring框架中管理对象之间的关联关系。文章介绍了MessageService类和MessagePrinter类的实现,并解释了它们之间的关联关系。通过学习本文,读者可以了解Spring框架中对象之间的关联关系的概念和实现方式。 ... [详细]
  • 本文介绍了在wepy中运用小顺序页面受权的计划,包含了用户点击作废后的从新受权计划。 ... [详细]
  • 本文介绍了如何使用vue-awesome-swiper组件,包括在main.js中引入和使用swiper和swiperSlide组件,以及设置options和ref属性。同时还介绍了如何在模板中使用swiper和swiperSlide组件,并展示了如何通过循环渲染swipes数组中的数据,并使用picUrl属性显示图片。最后还介绍了如何添加分页器。 ... [详细]
  • 本文介绍了MVP架构模式及其在国庆技术博客中的应用。MVP架构模式是一种演变自MVC架构的新模式,其中View和Model之间的通信通过Presenter进行。相比MVC架构,MVP架构将交互逻辑放在Presenter内部,而View直接从Model中读取数据而不是通过Controller。本文还探讨了MVP架构在国庆技术博客中的具体应用。 ... [详细]
  • 阿里云监控URL的配置笔记
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了阿里云监控URL的配置笔记相关的知识,希望对你有一定的参考价值。有很多细节需要记录 ... [详细]
  • k8s入坑之路(14)scheduler调度 kubelet管理及健康检查
    kubelet主要功能Pod管理在kubernetes的设计中,最基本的管理单位是pod,而不是container。pod是kubernetes在容器上的一层封装,由一组运行在同一 ... [详细]
author-avatar
Mr丶X8063_789
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有