在Ubuntu中部署并测试HyperLedger Fabric 0.6
最近开始研究区块链,对这个新兴的技术有了基本概念上的了解,所以打算基于一个开源项目做做实验。如果是做数字货币,那么比特币的源代码是最好的了,不过这算是区块链1.0吧,已经有很多改进的竞争币和山寨币出来了,所以打算对区块链2.0,也就是智能合约入手。
智能合约比较成功的就是以太坊了。以太坊主要是公有链,其实对企业应用来说并不是特别合适,而且本身并没有权限控制功能,面向企业的,主要还是超级账本HyperLedger的Fabric和刚刚开源出来的R3的Corda。关于这些项目的应用场景和区别,我觉得这篇文章写的比较好:http://geek.csdn.net/news/detail/134967
经过比较,觉得Fabric目前比较合适,所以就以这个项目为基础,学习智能合约。
一、环境准备
1.1 安装VirtualBox并在其中安装好Ubuntu
这一步其实没啥好说的,下载好最新版的VirtualBox,下载Ubuntu Server,我用的是16.10 X64。在安装完Ubuntu后,需要保证apt source是国内的,不然如果是国外的话会很慢很慢的。具体做法是
sudo vi /etc/apt/sources.list
打开这个apt源列表,如果其中看到是http://us.xxxxxx之类的,那么就是外国的,如果看到是http://cn.xxxxx之类的,那么就不用换的。我的是美国的源,所以需要做一下批量的替换。在命令模式下,输入:
:%s/us./cn./g
就可以把所有的us.改为cn.了。然后输入:wq即可保存退出。
sudo apt-get update
更新一下源。
然后安装ssh,这样接下来就可以用putty或者SecureCRT之类的客户端远程连接Ubuntu了。
sudo apt-get install ssh
1.2 安装Docker
安装Docker也会遇到外国网络慢的问题,幸好国内有很好的镜像,推荐DaoClound,安装Docker的命令是:
curl -sSL https://get.daocloud.io/docker | sh
安装完成后,运行以下脚本将当前用户添加到Docker的组中
sudo usermod -aG docker studyzy
重新登录当前用户,接下来修改 Docker 服务配置(/etc/default/docker
文件)。
sudo vi /etc/default/docker
添加以下内容:
DOCKER_OPTS="$DOCKER_OPTS -H tcp://0.0.0.0:2375 -H unix:///var/run/docker.sock --api-cors-header='*'"
接下来就需要设置国内的Docker镜像地址,需要注册一个账号,然后在加速器页面提供了设置Docker镜像的脚本,加速器页面是:
https://www.daocloud.io/mirror 我提供的脚本是:
curl -sSL https://get.daocloud.io/daotools/set_mirror.sh | sh -s http://d4cc5789.m.daocloud.io
运行完脚本后,重启Docker服务
sudo service docker restart
1.3 安装docker-compose
Docker-compose是支持通过模板脚本批量创建Docker容器的一个组件。在安装Docker-Compose之前,需要安装Python-pip,运行脚本:
sudo apt-get install python-pip
安装完成后,接下来从DaoClound安装Docker-compose,运行脚本:
curl -L https://get.daocloud.io/docker/compose/releases/download/1.10.1/docker-compose-`uname -s`-`uname -m` > ~/docker-compose
sudo mv ~/docker-compose /usr/local/bin/docker-compose
chmod +x /usr/local/bin/docker-compose
二、Fabric部署
2.1 下载Fabric镜像
Fabric的Docker镜像是在https://hub.docker.com/r/hyperledger/ 我们要做实验主要用到peer,baseimage,membersrvc,先现在Peer和membersrvc,这两个镜像提供了latest版本,所以直接pull下来即可。
docker pull hyperledger/fabric-peer
docker pull hyperledger/fabric-membersrvc
但是baseimage是没有latest版本,所以我们可以下载一个新一点的版本,然后rename成latest。
docker pull hyperledger/fabric-baseimage:x86_64-0.3.
docker tag hyperledger/fabric-baseimage:x86_64-0.3. hyperledger/fabric-baseimage:latest
现在我们运行docker images命令,可以看到我们准备好的镜像:
REPOSITORY TAG IMAGE ID CREATED SIZE
hyperledger/fabric-baseimage latest f4751a503f02 7 days ago 1.27 GB
hyperledger/fabric-baseimage x86_64-0.3.0 f4751a503f02 7 days ago 1.27 GB
hyperledger/fabric-membersrvc latest b3654d32e4f9 3 months ago 1.42 GB
hyperledger/fabric-peer latest 21cb00fb27f4 3 months ago 1.42 GB
2.2 使用Git下载Docker-compose模板
如果没有安装Git,那么需要先安装Git,安装Git很简单:
sudo apt-get install git
感谢yeasy提供的很好的HyperLedger的模板,我们先克隆到本地:
git clone https://github.com/yeasy/docker-compose-files
2.3 以PBFT模式启动Fabric
先进入Git下载下来的Docker-compose目录:
cd docker-compose-files/hyperledger/0.6/pbft/
这里提供了多种模式的启动方案,一种是启动4个节点的Peer,没有权限认证:4-peers.yml 另一种是在4节点Peer的基础上,再加上MembershipService节点,也就是需要权限认证的:4-peers-with-membersrvc.yml 另外还有再进一步,提供了web的Explorer的:4-peers-with-membersrvc-explorer.yml
这里我们就简单点,直接忽略掉MembershipService和Explorer,只启用4个节点的PBFT:
docker-compose -f -peers.yml up
系统会打印出启动的日志:
Creating network "pbft_default" with the default driver
Creating pbft_vp0_1
Creating pbft_vp3_1
Creating pbft_vp2_1
Creating pbft_vp1_1
……
至此,我们的环境搭建完毕,接下来我们就可以在上面跑链上代码了。
三、测试Fabric
3.1 在CLI中测试Example02
我们前面创建了4个容器,开启另外一个命令行窗口,输入docker ps命令,可以看到当前容器的状态:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
2131cede4ade hyperledger/fabric-peer:latest "peer node start" 3 minutes ago Up 3 minutes 7050-7059/tcp pbft_vp1_1
5acea88f21bc hyperledger/fabric-peer:latest "peer node start" 3 minutes ago Up 3 minutes 7050-7059/tcp pbft_vp2_1
546b103d904d hyperledger/fabric-peer:latest "peer node start" 3 minutes ago Up 3 minutes 7050-7059/tcp pbft_vp3_1
327ab874b2e3 hyperledger/fabric-peer:latest "peer node start" 3 minutes ago Up 3 minutes 0.0.0.0:7050->7050/tcp, 7051-7059/tcp pbft_vp0_1
这里我们可以看到,最后一个容器pbft_vp0_1其启用了端口映射的,容器上面的7050端口会映射到Ubuntu的7050端口上。我们要执行命令行代码,需要先连接到这个容器内部:
docker exec -it pbft_vp0_1 bash
进入容器后,命令行会变为:root@vp0:/opt/gopath/src/github.com/hyperledger/fabric#
这里的容器已经帮我们把测试代码都放在了容器里面,所以我们不需要再下载测试代码。
3.1.1部署Go语言的ChainCode并初始化
下面我们部署Example02到Fabric上:
peer chaincode deploy -p github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example02 -c '{"Function":"init", "Args": ["a","100", "b", "200"]}'
这个示例是初始化两个账户a和b,a有余额100元,b有余额200元,这是运行结果:
root@vp0:/opt/gopath/src/github.com/hyperledger/fabric# peer chaincode deploy -p github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example02 -c '{"Function":"init", "Args": ["a","100", "b", "200"]}'
::12.187 [chaincodeCmd] chaincodeDeploy -> INFO Deploy result: type:GOLANG chaincodeID:<path:"github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example02" name:"ee5b24a1f17c356dd5f6e37307922e39ddba12e5d2e203ed93401d7d05eb0dd194fb9070549c5dc31eb63f4e654dbd5a1d86cbb30c48e3ab1812590cd0f78539" > ctorMsg:<args:"init" args:"a" args:"" args:"b" args:"" >
Deploy chaincode: ee5b24a1f17c356dd5f6e37307922e39ddba12e5d2e203ed93401d7d05eb0dd194fb9070549c5dc31eb63f4e654dbd5a1d86cbb30c48e3ab1812590cd0f78539
::12.188 [main] main -> INFO Exiting.....
这里我们可以看到已经部署成功,并返回了ChainCode的ID:ee5b24a1f17c356dd5f6e37307922e39ddba12e5d2e203ed93401d7d05eb0dd194fb9070549c5dc31eb63f4e654dbd5a1d86cbb30c48e3ab1812590cd0f78539
3.1.2查询ChainCode
下面我们把这个ID放入一个变量中:
CC_ID="ee5b24a1f17c356dd5f6e37307922e39ddba12e5d2e203ed93401d7d05eb0dd194fb9070549c5dc31eb63f4e654dbd5a1d86cbb30c48e3ab1812590cd0f78539"
下面我们来查询一下a账户的余额:
peer chaincode query -n ${CC_ID} -c '{"Function": "query", "Args": ["a"]}'
这是运行结果:
root@vp0:/opt/gopath/src/github.com/hyperledger/fabric# peer chaincode query -n ${CC_ID} -c '{"Function": "query", "Args": ["a"]}'
::17.780 [chaincodeCmd] chaincodeInvokeOrQuery -> INFO Successfully queried transaction: chaincodeSpec:<type:GOLANG chaincodeID:<name:"ee5b24a1f17c356dd5f6e37307922e39ddba12e5d2e203ed93401d7d05eb0dd194fb9070549c5dc31eb63f4e654dbd5a1d86cbb30c48e3ab1812590cd0f78539" > ctorMsg:<args:"query" args:"a" > >
Query Result:
::17.781 [main] main -> INFO Exiting.....
可以看到查询结果是100元。
注意:这里如果遇到了抛出异常:
LedgerError - ResourceNotFound: ledger: resource not found
那么就得看log,到底是什么地方错了,我们可以切换回docker-compose的那个窗口,那个窗口会打印错误日志,或者我们再打开一个窗口,运行命令:
docker logs -f pbft_vp0_1
查看peer日志,找到原因。我之前一直遇到这个异常,后来发现是baseimage没有latest版的造成的,所以2.1步骤不能出错。
3.1.3调用ChainCode
接下来,我们让a给b转账10元,运行命令:
peer chaincode invoke -n ${CC_ID} -c '{"Function": "invoke", "Args": ["a", "b", "10"]}'
这是调用后的结果:
root@vp0:/opt/gopath/src/github.com/hyperledger/fabric# peer chaincode invoke -n ${CC_ID} -c '{"Function": "invoke", "Args": ["a", "b", "10"]}'
::19.903 [chaincodeCmd] chaincodeInvokeOrQuery -> INFO Successfully invoked transaction: chaincodeSpec:<type:GOLANG chaincodeID:<name:"ee5b24a1f17c356dd5f6e37307922e39ddba12e5d2e203ed93401d7d05eb0dd194fb9070549c5dc31eb63f4e654dbd5a1d86cbb30c48e3ab1812590cd0f78539" > ctorMsg:<args:"invoke" args:"a" args:"b" args:"" > > (94c9cbd9-ea04-436f-9cf8-3436303554d2)
::19.904 [main] main -> INFO Exiting.....
3.1.4检查调用ChainCode后的结果
现在已经转账完毕,我们再来查询一下a账户的余额:
peer chaincode query -n ${CC_ID} -c '{"Function": "query", "Args": ["a"]}'
查询结果:
root@vp0:/opt/gopath/src/github.com/hyperledger/fabric# peer chaincode query -n ${CC_ID} -c '{"Function": "query", "Args": ["a"]}'
::33.937 [chaincodeCmd] chaincodeInvokeOrQuery -> INFO Successfully queried transaction: chaincodeSpec:<type:GOLANG chaincodeID:<name:"ee5b24a1f17c356dd5f6e37307922e39ddba12e5d2e203ed93401d7d05eb0dd194fb9070549c5dc31eb63f4e654dbd5a1d86cbb30c48e3ab1812590cd0f78539" > ctorMsg:<args:"query" args:"a" > >
Query Result:
::33.937 [main] main -> INFO Exiting.....
可以看到,a账户变成90元了。
3.2 在REST API中测试Example02
前面我们已经说到,容器的7050端口会映射成Ubuntu的7050端口,我们在Ubuntu下,运行ifconfig,可以看到Ubuntu的IP,然后我们回到Windows,就可以通过REST的Client来测试,这里我喜欢用Chrome的插件DHC,很好用,强烈推荐!不过要翻墙才能装。
这里我Ubuntu的IP是192.168.100.129,下面就用DHC进行REST API的Example02部署。
3.2.1通过REST API部署GO语言的ChainCode
POST 192.168.100.129:7050/chaincode
Body是:
{
"jsonrpc": "2.0",
"method": "deploy",
"params": {
"type": 1,
"chaincodeID":{
"path":"github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example02"
},
"ctorMsg": {
"function":"init",
"args":["a", "1000", "b", "2000"]
}
},
"id": 1
}
这里为了区别,我们把a账户初始化1000元,b账户初始化2000元。返回的结果是:
{
"jsonrpc": "2.0",
"result":{
"status": "OK",
"message": "04233c6dd8364b9f0749882eb6d1b50992b942aa0a664182946f411ab46802a88574932ccd75f8c75e780036e363d52dd56ccadc2bfde95709fc39148d76f050"
},
"id": 1
}
这里04233c6dd8364b9f0749882eb6d1b50992b942aa0a664182946f411ab46802a88574932ccd75f8c75e780036e363d52dd56ccadc2bfde95709fc39148d76f050就是部署后的ChainCodeID。
3.2.2通过REST API查询ChainCode
POST 192.168.100.129:7050/chaincode
Body内容是:
{
"jsonrpc": "2.0",
"method": "query",
"params": {
"type": 1,
"chaincodeID":{
"name":"04233c6dd8364b9f0749882eb6d1b50992b942aa0a664182946f411ab46802a88574932ccd75f8c75e780036e363d52dd56ccadc2bfde95709fc39148d76f050"
},
"ctorMsg": {
"function":"query",
"args":["a"]
}
},
"id": 2
}
系统返回的结果是:
{
"jsonrpc": "2.0",
"result":{
"status": "OK",
"message": "1000"
},
"id": 2
}
一切正常,返回a账户的1000元。
3.2.3通过REST API调用ChainCode
我们试着从a向b转账100元:
POST 192.168.100.129:7050/chaincode
Body内容是:
{
"jsonrpc": "2.0",
"method": "invoke",
"params": {
"type": 1,
"chaincodeID":{
"name":"04233c6dd8364b9f0749882eb6d1b50992b942aa0a664182946f411ab46802a88574932ccd75f8c75e780036e363d52dd56ccadc2bfde95709fc39148d76f050"
},
"ctorMsg": {
"function":"invoke",
"args":["a", "b", "100"]
}
},
"id": 3
}
返回的结果:
{
"jsonrpc": "2.0",
"result":{
"status": "OK",
"message": "2ac78b5f-6d35-400d-b7c4-75ef81e14d3e"
},
"id": 3
}
3.2.4通过REST API检查调用ChainCode后的结果
这里我们来查询一下b账户。
POST 192.168.100.129:7050/chaincode
Body内容改为:
{
"jsonrpc": "2.0",
"method": "query",
"params": {
"type": 1,
"chaincodeID":{
"name":"04233c6dd8364b9f0749882eb6d1b50992b942aa0a664182946f411ab46802a88574932ccd75f8c75e780036e363d52dd56ccadc2bfde95709fc39148d76f050"
},
"ctorMsg": {
"function":"query",
"args":["b"]
}
},
"id": 4
}
返回结果:
{
"jsonrpc": "2.0",
"result":{
"status": "OK",
"message": "2100"
},
"id": 4
}
一切正常,b账户果然真假了100元。
关于更多的REST API,我们可以参考这里:https://github.com/hyperledger-archives/fabric/blob/master/docs/API/CoreAPI.md#rest-api
3.3测试Java版Chain Code
Fabric除了支持本身的Go语言的ChainCode,也可以支持其他语言,比如最常用的Java语言。Fabric的源代码中也提供了Java示例,这里我们就用SimpleSample这个示例:
https://github.com/hyperledger/fabric/tree/master/examples/chaincode/java/SimpleSample
3.3.1在CLI中部署该Java代码的ChainCode到Fabric
命令是:
peer chaincode deploy -l java -p /opt/gopath/src/github.com/hyperledger/fabric/examples/chaincode/java/SimpleSample -c '{"Function":"init", "Args": ["a","100", "b", "200"]}'
运行结果为:
root@vp0:/opt/gopath/src/github.com/hyperledger/fabric# peer chaincode deploy -l java -p /opt/gopath/src/github.com/hyperledger/fabric/examples/chaincode/java/SimpleSample -c '{"Function":"init", "Args": ["a","100", "b", "200"]}'
09:20:16.857 [chaincodeCmd] chaincodeDeploy -> INFO 001 Deploy result: type:JAVA chaincodeID:<path:"/opt/gopath/src/github.com/hyperledger/fabric/examples/chaincode/java/SimpleSample" name:"0f5b1d65041bc6d500bd0f1cab50eb6154c291ef0f4596d64b6797e8ef8f7c34a179b5a2cea82253ff3d74e768512fe0481503eadcf13d18f9761bbb8133efd0" > ctorMsg:<args:"init" args:"a" args:"100" args:"b" args:"200" >
Deploy chaincode: 0f5b1d65041bc6d500bd0f1cab50eb6154c291ef0f4596d64b6797e8ef8f7c34a179b5a2cea82253ff3d74e768512fe0481503eadcf13d18f9761bbb8133efd0
09:20:16.857 [main] main -> INFO 002 Exiting.....
接下来的各种查询,调用都是差不多的,我就不再累述了。
3.3.2通过REST API部署Java ChainCode到Fabric
POST 192.168.100.129:7050/chaincode
Body为
{
"jsonrpc": "2.0",
"method": "deploy",
"params": {
"type": 4,
"chaincodeID":{
"path":"/opt/gopath/src/github.com/hyperledger/fabric/examples/chaincode/java/SimpleSample"
},
"ctorMsg": {
"function":"init",
"args":["a", "1000", "b", "2000"]
}
},
"id": 1
}
系统返回的结果为:
{
"jsonrpc": "2.0",
"result":{
"status": "OK",
"message": "27cb2925013a5e8f27b41be748e6767c3fbc7bfdfe2453c2640f9069e75c4db38735fa3b6b8cac78e212a1c97193f3bfb2f9b810ce0a11f437a96b330d508fbd"
},
"id": 1
}
这里需要注意的是type:4,不再是1。1是Go语言的,而Java语言是4.接下来的操作也是类似的了,我就不累述了。
总的来说,Fabric基于Docker容器技术,部署的ChainCode在运行时会基于baseimage重新创建Docker容器,运行的链上代码越多,容器就会越多。运行docker ps会看到很多容器被创建。docker images也可以看到多了很多镜像。需要注意清理。
在Ubuntu中部署并测试HyperLedger Fabric 0.6的更多相关文章
- 在Ubuntu中部署并测试Fabric 1.0 Beta
[更新:1.0Beta已经是过去式了,现在出了1.0.0的正式版,请大家参照 http://www.cnblogs.com/studyzy/p/7437157.html 安装Fabric 1.0.0 ...
- ubuntu中编译安装gcc 9.2.0
一切都和其他源码安装软件是一样的: 一.下载源代码: http://ftp.gnu.org/gnu/gcc/gcc-9.2.0/gcc-9.2.0.tar.xz 二.解压文件 tar xvf gcc- ...
- Ubuntu中部署Django项目的配置与链接MySQL
Django的简介 MVT模式的介绍创建项目的虚拟环境 本次使用的是pip安装 一.更新 sudo apt update 二.安装pip sudo apt install python3-pip 三. ...
- Centos 7 中 部署 asp.net core 3.0 + nginx + mongodb 的一些新手简单入门,非docker
目录 零.准备工作 一.部署Mongodb 1.安装Mongodb 2.创建mongodb的数据目录 3.设置目录权限 4.设置mongodb启动 5.修改mongodb的配置文件 6.启动Mongo ...
- rails创建项目,部署,测试流程(rails5.0+ruby2.3.1)
rails new test_app --skip-test-unit 不生成默认的test,稍后用rspeccd test_app 修改Gemfile(大部分为自动生成) source 'https ...
- 记一次Docker中部署Asp.Net Core 3.0的踩坑过程
最近公司打算重构目前直销报单系统到微信小程序中,目前的系统只能在PC上面使用,这两年也搞过App端,但是由于人员流动和公司架构调整最后都不了了之,只留下一堆写了一半的接口.以前的接口依然是使用Asp. ...
- Hyperledger Fabric Chaincode for Operators——实操智能合约
什么是Chaincode(智能合约)? chaincode是一个程序,它是使用Go语言编写的,最终在Java等其他编程语言中实现了指定的接口.chaincode运行在一个被背书peer进程独立出来的安 ...
- Hyperledger Fabric 1.0 从零开始(一)
在HyperLedger/Fabric发布0.6的时候,公司就已经安排了一个团队研究这一块,后来也请IBM的专家组过来培训了一批人,不幸的是,这批人后来全走了,然后1.0就发布了.自从2017年7月H ...
- 不使用pvc的方式在K8S中部署apisix-gateway
不使用pvc的方式在K8S中部署apisix-gateway 简介 我的apisix使用etcd作为数据存储服务器,官方的使用pvc方式或者docker-compose的方式,对于新手不太友好,本篇是 ...
随机推荐
- django(python manage.py imgrate)同步数据库出错后的解决办法
问题 很多情况下,因为app的models.py的文件内容有误,但是通过python manage.py check检查不出来时,当执行python manage.py migra ...
- web-worker 的使用
JavaScript采用的是单线程模式,它每次也只能执行一个事件,所以它在加载大量的事件的时候会比较慢. 而web-worker的作用就是给JavaScript提供一个多线程的模式. 注意的是 web ...
- Java面试题总结(不定期更新)
1.HashMap和Hashtable的区别? HashMap:key.value都可以为空,线程不安全.初始容量16,扩容方式每次为2倍 Hashtable:不支持null key 和null va ...
- 使用混淆ProGuard压缩代码和资源/减少方法数量
ProGuard介绍 ProGuard是一个Java类文件压缩器,优化器,混淆器和预先文件验证器. 压缩步骤检测和删除未使用的类,字段,方法和属性. 优化步骤分析和优化方法的字节码. 混淆步骤使用短无 ...
- python--文件流读写
在讲述fileinput模块之前,首先说一下python内置的文件API—open()函数以及与其相关的函数. 我这里主要讲讲其中四个比较重要和常用的方法,更多的方法,可以参考:菜鸟教程http:// ...
- recovery 界面汉化过程详解
一. 主要是针对recovery汉化,主要汉化对象是界面显示为中文. 二. 基于中文的汉化,有两种方式,一种是基于GB2312的编码格式汉化,另外一种是基于unicode编码格式汉化.下面介绍unic ...
- Microsoft SQL Server 17导出xlsx文件时报错:The 'Microsoft.ACE.OLEDB.12.0' provider is not registered on the local machine. (System.Data)
导出数据时报错: 如果你是导出office 2007格式 TITLE: SQL Server Import and Export Wizard ---------------------------- ...
- sql语句中的join用法(可视化解释)
一.innerjoin innerjoin总结来说就是 ,如A知道通往B如何走:B知道通往C如何走:但是A不知道通往C如何走,但是A可以通过B获得去往C的通往方式.. 首先,假设有A,B两张表,结构及 ...
- Oracle EBS R12 GL_IMPORT_REFERENCES 映射
非原创. 转自出处: http://alloracleapps.com/oracle_apps/gl_import_references-columns-mapping-11i-vs-r12/
- c/c++ 标准库 智能指针( smart pointer ) 是啥玩意儿
标准库 智能指针( smart pointer ) 是啥玩意儿 一,为什么有智能指针??? c++程序员需要自己善后自己动态开辟的内存,一旦忘了释放,内存就泄露. 智能指针可以帮助程序员"自 ...