这一步其实没啥好说的,下载好最新版的VirtualBox,下载Ubuntu Server,我用的是16.10 X64。在安装完Ubuntu后,须要保证apt source是国内的,否则若是是国外的话会很慢很慢的。具体作法是java
sudo vi /etc/apt/sources.list
打开这个apt源列表,若是其中看到是http://us.xxxxxx之类的,那么就是外国的,若是看到是http://cn.xxxxx之类的,那么就不用换的。个人是美国的源,因此须要作一下批量的替换。在命令模式下,输入:node
:%s/us./cn./g
就能够把全部的us.改成cn.了。而后输入:wq便可保存退出。python
sudo apt-get update
更新一下源。git
而后安装ssh,这样接下来就能够用putty或者SecureCRT之类的客户端远程链接Ubuntu了。github
sudo apt-get install ssh
安装Docker也会遇到外国网络慢的问题,幸亏国内有很好的镜像,推荐DaoClound,安装Docker的命令是:web
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
Docker-compose是支持经过模板脚本批量建立Docker容器的一个组件。在安装Docker-Compose以前,须要安装Python-pip,运行脚本:docker
sudo apt-get install python-pip
安装完成后,接下来从DaoClound安装Docker-compose,运行脚本:json
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的Docker镜像是在https://hub.docker.com/r/hyperledger/ 咱们要作实验主要用到peer,baseimage,membersrvc,先如今Peer和membersrvc,这两个镜像提供了latest版本,因此直接pull下来便可。c#
docker pull hyperledger/fabric-peer docker pull hyperledger/fabric-membersrvc
可是baseimage是没有latest版本,因此咱们能够下载一个新一点的版本,而后rename成latest。api
docker pull hyperledger/fabric-baseimage:x86_64-0.3.0 docker tag hyperledger/fabric-baseimage:x86_64-0.3.0 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
若是没有安装Git,那么须要先安装Git,安装Git很简单:
sudo apt-get install git
感谢yeasy提供的很好的HyperLedger的模板,咱们先克隆到本地:
git clone https://github.com/yeasy/docker-compose-files
先进入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 4-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 ……
至此,咱们的环境搭建完毕,接下来咱们就能够在上面跑链上代码了。
咱们前面建立了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#
这里的容器已经帮咱们把测试代码都放在了容器里面,因此咱们不须要再下载测试代码。
下面咱们部署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"]}' 08:37:12.187 [chaincodeCmd] chaincodeDeploy -> INFO 001 Deploy result: type:GOLANG chaincodeID:<path:"github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example02" name:"ee5b24a1f17c356dd5f6e37307922e39ddba12e5d2e203ed93401d7d05eb0dd194fb9070549c5dc31eb63f4e654dbd5a1d86cbb30c48e3ab1812590cd0f78539" > ctorMsg:<args:"init" args:"a" args:"100" args:"b" args:"200" > Deploy chaincode: ee5b24a1f17c356dd5f6e37307922e39ddba12e5d2e203ed93401d7d05eb0dd194fb9070549c5dc31eb63f4e654dbd5a1d86cbb30c48e3ab1812590cd0f78539 08:37:12.188 [main] main -> INFO 002 Exiting.....
这里咱们能够看到已经部署成功,并返回了ChainCode的ID:ee5b24a1f17c356dd5f6e37307922e39ddba12e5d2e203ed93401d7d05eb0dd194fb9070549c5dc31eb63f4e654dbd5a1d86cbb30c48e3ab1812590cd0f78539
下面咱们把这个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"]}' 08:41:17.780 [chaincodeCmd] chaincodeInvokeOrQuery -> INFO 001 Successfully queried transaction: chaincodeSpec:<type:GOLANG chaincodeID:<name:"ee5b24a1f17c356dd5f6e37307922e39ddba12e5d2e203ed93401d7d05eb0dd194fb9070549c5dc31eb63f4e654dbd5a1d86cbb30c48e3ab1812590cd0f78539" > ctorMsg:<args:"query" args:"a" > > Query Result: 100 08:41:17.781 [main] main -> INFO 002 Exiting.....
能够看到查询结果是100元。
注意:这里若是遇到了抛出异常:
LedgerError - ResourceNotFound: ledger: resource not found
那么就得看log,究竟是什么地方错了,咱们能够切换回docker-compose的那个窗口,那个窗口会打印错误日志,或者咱们再打开一个窗口,运行命令:
docker logs -f pbft_vp0_1
查看peer日志,找到缘由。我以前一直遇到这个异常,后来发现是baseimage没有latest版的形成的,因此2.1步骤不能出错。
接下来,咱们让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"]}' 08:44:19.903 [chaincodeCmd] chaincodeInvokeOrQuery -> INFO 001 Successfully invoked transaction: chaincodeSpec:<type:GOLANG chaincodeID:<name:"ee5b24a1f17c356dd5f6e37307922e39ddba12e5d2e203ed93401d7d05eb0dd194fb9070549c5dc31eb63f4e654dbd5a1d86cbb30c48e3ab1812590cd0f78539" > ctorMsg:<args:"invoke" args:"a" args:"b" args:"10" > > (94c9cbd9-ea04-436f-9cf8-3436303554d2) 08:44:19.904 [main] main -> INFO 002 Exiting.....
如今已经转帐完毕,咱们再来查询一下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"]}' 08:45:33.937 [chaincodeCmd] chaincodeInvokeOrQuery -> INFO 001 Successfully queried transaction: chaincodeSpec:<type:GOLANG chaincodeID:<name:"ee5b24a1f17c356dd5f6e37307922e39ddba12e5d2e203ed93401d7d05eb0dd194fb9070549c5dc31eb63f4e654dbd5a1d86cbb30c48e3ab1812590cd0f78539" > ctorMsg:<args:"query" args:"a" > > Query Result: 90 08:45:33.937 [main] main -> INFO 002 Exiting.....
能够看到,a帐户变成90元了。
前面咱们已经说到,容器的7050端口会映射成Ubuntu的7050端口,咱们在Ubuntu下,运行ifconfig,能够看到Ubuntu的IP,而后咱们回到Windows,就能够经过REST的Client来测试,这里我喜欢用Chrome的插件DHC,很好用,强烈推荐!不过要FQ才能装。
这里我Ubuntu的IP是192.168.100.129,下面就用DHC进行REST API的Example02部署。
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。
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元。
咱们试着从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 }
这里咱们来查询一下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
Fabric除了支持自己的Go语言的ChainCode,也能够支持其余语言,好比最经常使用的Java语言。Fabric的源代码中也提供了Java示例,这里咱们就用SimpleSample这个示例:
https://github.com/hyperledger/fabric/tree/master/examples/chaincode/java/SimpleSample
命令是:
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.....
接下来的各类查询,调用都是差很少的,我就再也不累述了。
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 }