Fabric 部署与管理

使用 1.0 版本

Hyperledger Fabric 1.0 版本整体 重新设计了架构,新的设计可以实现更好的扩展性和安全性。

下载 Compose 模板文件

$ git clone https://github.com/yeasy/docker-compose-files

进入 hyperledger/1.0 目录,查看包括若干模板文件,功能如下。

文件 功能
orderer-base.yaml orderer 节点的基础服务模板
peer-base.yaml peer 节点的基础服务模板
docker-compose-base.yaml 包含 orderer 和 peers 组织结构的基础服务模板
docker-compose-1peer.yaml 使用自定义的 channel 启动一个最小化的环境,包括 1 个 peer 节点、1 个 orderer 节点、1 个 CA 节点、1 个 cli 节点
docker-compose-2orgs-4peers.yaml 使用自定义的 channel 启动一个环境,包括 4 个 peer 节点、1 个 orderer 节点、1 个 CA 节点、1 个 cli 节点
docker-compose-2orgs-4peers-couchdb.yaml 启动一个带有 couchdb 服务的网络环境
docker-compose-2orgs-4peers-event.yaml 启动一个带有 event 事件服务的网络环境
e2e_cli/channel-artifacts 存放创建 orderer, channel, anchor peer 操作时的配置文件
e2e_cli/crypto-config 存放 orderer 和 peer 相关证书
e2e_cli/example 用来测试的 chaincode
scripts/setup_Docker.sh 安装并配置 dokcer 和 docker-compose
scripts/download_images.sh 下载依赖镜像
scripts/start_fabric.sh 快速启动一个fabric 网络
scripts/initialize.sh 自动化测试脚本,用来初始化 channel 和 chaincode
scripts/test_4peers.sh 自动化测试脚本,用来执行 chaincode 操作
scripts/cleanup_env.sh 容器,镜像自动清除脚本
scripts/test_1peer.sh 测试1个peer网络的自动化脚本
kafka/ 基于kafka 的 ordering 服务

安装 Docker 和 docker-compose

docker 及 docker-compose 可以自行手动安装。也可以通过 hyperledger/1.0/scripts 提供的 setup_Docker.sh 脚本自动安装。

$ bash scripts/setup_Docker.sh

获取 Docker 镜像

Docker 镜像可以自行从源码编译(make docker),或从 DockerHub 仓库下载。

执行脚本获取

直接执行 hyperledger/1.0/scripts 提供的 download_images.sh 脚本获取。

$ bash scripts/download_images.sh

从官方仓库获取

从社区 DockerHub 仓库下载。

# pull fabric images
ARCH=x86_64
BASEIMAGE_RELEASE=0.3.1
BASE_VERSION=1.0.0
PROJECT_VERSION=1.0.0
IMG_TAG=1.0.0

echo "Downloading fabric images from DockerHub...with tag = ${IMG_TAG}... need a while"
# TODO: we may need some checking on pulling result?
docker pull hyperledger/fabric-peer:$ARCH-$IMG_TAG
docker pull hyperledger/fabric-orderer:$ARCH-$IMG_TAG
docker pull hyperledger/fabric-ca:$ARCH-$IMG_TAG
docker pull hyperledger/fabric-tools:$ARCH-$IMG_TAG
docker pull hyperledger/fabric-ccenv:$ARCH-$PROJECT_VERSION
docker pull hyperledger/fabric-baseimage:$ARCH-$BASEIMAGE_RELEASE
docker pull hyperledger/fabric-baseos:$ARCH-$BASEIMAGE_RELEASE

# Only useful for debugging
# docker pull yeasy/hyperledger-fabric

echo "===Re-tagging images to *latest* tag"
docker tag hyperledger/fabric-peer:$ARCH-$IMG_TAG hyperledger/fabric-peer
docker tag hyperledger/fabric-orderer:$ARCH-$IMG_TAG hyperledger/fabric-orderer
docker tag hyperledger/fabric-ca:$ARCH-$IMG_TAG hyperledger/fabric-ca
docker tag hyperledger/fabric-tools:$ARCH-$IMG_TAG hyperledger/fabric-tools

从第三方仓库获取

这里也提供了调整(基于 golang:1.8 基础镜像制作)后的第三方镜像,与社区版本功能是一致的。

通过如下命令拉取相关镜像,并更新镜像别名。

$ ARCH=x86_64
$ BASEIMAGE_RELEASE=0.3.1
$ BASE_VERSION=1.0.0
$ PROJECT_VERSION=1.0.0
$ IMG_TAG=1.0.0
$ docker pull yeasy/hyperledger-fabric-base:$IMG_VERSION 
  && docker pull yeasy/hyperledger-fabric-peer:$IMG_VERSION 
  && docker pull yeasy/hyperledger-fabric-orderer:$IMG_VERSION 
  && docker pull yeasy/hyperledger-fabric-ca:$IMG_VERSION 
  && docker pull hyperledger/fabric-couchdb:$ARCH-$IMG_VERSION 
  && docker pull hyperledger/fabric-kafka:$ARCH-$IMG_VERSION 
  && docker pull hyperledger/fabric-zookeeper:$ARCH-$IMG_VERSION

$ docker tag yeasy/hyperledger-fabric-peer:$IMG_VERSION hyperledger/fabric-peer 
  && docker tag yeasy/hyperledger-fabric-orderer:$IMG_VERSION hyperledger/fabric-orderer 
  && docker tag yeasy/hyperledger-fabric-ca:$IMG_VERSION hyperledger/fabric-ca 
  && docker tag yeasy/hyperledger-fabric-peer:$IMG_VERSION hyperledger/fabric-tools 
  && docker tag yeasy/hyperledger-fabric-base:$IMG_VERSION hyperledger/fabric-ccenv:$ARCH-$PROJECT_VERSION 
  && docker tag yeasy/hyperledger-fabric-base:$IMG_VERSION hyperledger/fabric-baseos:$ARCH-$BASEIMAGE_RELEASE 
  && docker tag yeasy/hyperledger-fabric-base:$IMG_VERSION hyperledger/fabric-baseimage:$ARCH-$BASEIMAGE_RELEASE 
  && docker tag hyperledger/fabric-couchdb:$ARCH-$IMG_VERSION hyperledger/fabric-couchdb 
  && docker tag hyperledger/fabric-zookeeper:$ARCH-$IMG_VERSION hyperledger/fabric-zookeeper 
  && docker tag hyperledger/fabric-kafka:$ARCH-$IMG_VERSION hyperledger/fabric-kafka

启动 fabric 1.0 网络

通过如下命令快速启动。

$ bash scripts/start_fabric.sh

或者

$ docker-compose -f docker-compose-2orgs-4peers.yaml up

注意输出日志中无错误信息。

此时,系统中包括 7 个容器。

$ docker ps -a
CONTAINER ID        IMAGE                        COMMAND                  CREATED             STATUS              PORTS                                                                                 NAMES
8683435422ca        hyperledger/fabric-peer      "bash -c 'while true;"   19 seconds ago      Up 18 seconds       7050-7059/tcp                                                                         fabric-cli
f284c4dd26a0        hyperledger/fabric-peer      "peer node start --pe"   22 seconds ago      Up 19 seconds       7050/tcp, 0.0.0.0:7051->7051/tcp, 7052/tcp, 7054-7059/tcp, 0.0.0.0:7053->7053/tcp     peer0.org1.example.com
95fa3614f82c        hyperledger/fabric-ca        "fabric-ca-server sta"   22 seconds ago      Up 19 seconds       0.0.0.0:7054->7054/tcp                                                                fabric-ca
833ca0d8cf41        hyperledger/fabric-orderer   "orderer"                22 seconds ago      Up 19 seconds       0.0.0.0:7050->7050/tcp                                                                orderer.example.com
cd21cfff8298        hyperledger/fabric-peer      "peer node start --pe"   22 seconds ago      Up 20 seconds       7050/tcp, 7052/tcp, 7054-7059/tcp, 0.0.0.0:9051->7051/tcp, 0.0.0.0:9053->7053/tcp     peer0.org2.example.com
372b583b3059        hyperledger/fabric-peer      "peer node start --pe"   22 seconds ago      Up 20 seconds       7050/tcp, 7052/tcp, 7054-7059/tcp, 0.0.0.0:10051->7051/tcp, 0.0.0.0:10053->7053/tcp   peer1.org2.example.com
47ce30077276        hyperledger/fabric-peer      "peer node start --pe"   22 seconds ago      Up 20 seconds       7050/tcp, 7052/tcp, 7054-7059/tcp, 0.0.0.0:8051->7051/tcp, 0.0.0.0:8053->7053/tcp     peer1.org1.example.com

测试网络

启动 fabric 网络后,可以进行 chaincode 操作,验证网络是否启动正常。

进入到 cli 容器里面,执行 initialize.sh 和 test_4peers.sh 脚本。

通过如下命令进入容器 cli 并执行测试脚本。

$ docker exec -it fabric-cli bash
$ bash ./scripts/initialize.sh

注意输出日志无错误提示,最终返回结果应该为:

UTC [main] main -> INFO 00c Exiting.....
===================== Chaincode Instantiation on PEER2 on channel 'businesschannel' is successful ===================== 


===================== All GOOD, initialization completed ===================== 


 _____   _   _   ____  
| ____| |  | | |  _  
|  _|   |  | | | | | |
| |___  | |  | | |_| |
|_____| |_| \_| |____/

之后同样是在 cli 容器里执行 test_4peers.sh 脚本

$ bash ./scripts/test_4peers.sh

输出日志无错误提示,最终返回结果应该为:

Query Result: 80
UTC [main] main -> INFO 008 Exiting.....
===================== Query on PEER3 on channel 'businesschannel' is successful ===================== 

===================== All GOOD, End-2-End execution completed ===================== 


 _____   _   _   ____  
| ____| |  | | |  _  
|  _|   |  | | | | | |
| |___  | |  | | |_| |
|_____| |_| \_| |____/

至此,整个网络启动并验证成功。

使用 Hyperledger Fabric SDK Node 进行测试

Hyperledger Fabric Client SDK 能够非常简单的使用API和 Hyperledger Fabric Blockchain 网络进行交互。其v1.1及其以上的版本添加了一个重要的功能Conection-Profile来保存整个network中必要的配置信息,方便client读取和配置。 该Demo基于Connection-Profile测试了整个网络的如下功能:

  • Fabric CA 相关
    • Enroll用户
    • Register用户
  • Channel 相关
    • 创建Channel
    • 将指定Peer join Channel
    • 查询Channel相关信息
    • 动态更新Channel配置信息
  • Chaincode 相关
    • Install Chaincode
    • Instantiate Chaincode
    • Invoke Chaincode
    • Query Chaincode
    • 查询Chaincode相关信息

主要依赖

  • Node v8.9.0 或更高 (注意目前v9.0+还不支持)
  • npm v5.5.1 或更高
  • gulp命令。 必须要进行全局安装 npm install -g gulp
  • docker运行环境
  • docker compose工具

主要fabric环境可参考Fabric 1.0

下载 Demo 工程

$ git clone https://github.com/Sunnykaby/Hyperledger-fabric-node-sdk-demo

进入 Hyperledger-fabric-node-sdk-demo 目录,查看各文件夹和文件,功能如下。

文件/文件夹 功能
artifacts-local 本地准备好构建fabric网络的基础材料
artifacts-remote 使用官方fabric-sample动态构建网络
extra 一些拓展性的材料
node 基于Fabric SDK Node的demo核心代码
src 测试用chaincode
Init.sh 构建Demo的初始化脚本

构建Demo

该项目提供两种Demo构建方式:

  • 利用本地已经准备好的相关网络资源,启动fabric network。
  • 利用官方fabric-sample项目,动态启动fabric network。

当然,你也可以使用自己已经创建好的fabric network和其相关的connection-profile来测试Demo。

##进入项目根目录

##使用本地资源构建Demo
./Init.sh local

##使用官方资源构建Demo
./Init.sh remote

执行之后,会在根目录中生成一个demo文件夹,其就是Demo程序的入口。

清理Demo资源,使用./Init.sh clean

启动Fabric网络

首先,我们需要准备一个fabric网络来进行测试。 进入到demo文件夹。

本地资源构建网络

进入资源目录,利用脚本启动网络即可。

cd artifacts
##启动网络
./net.sh up
##关闭网络
./net.sh down

用该脚本启动网络中包含:1个orderer, 2个organisation, 4个peer(每个组织有2个peer)和两个ca(每个组织一个)。

官方资源构建网络

在demo目录,利用脚本启动网络即可。

##启动网络,并配置本地资源
./net.sh init
##关闭网络并清理资源
./net.sh clean

用该脚本启动网络中包含:1个orderer, 2个organisation, 4个peer(每个组织有2个peer)和两个ca(每个组织一个)。

与本地资源启动不同,该方案主要有以下步骤:

  • 将官方fabric-sample项目clone到本地
  • 利用fabric-sample/first-network/bynf.sh up启动fabric脚本
  • 将一些资源文件连接到指定位置,方便node程序使用
  • 通过资源文件构建connection-profile(替换密钥等)
  • 创建一个新的channel的binary

详细信息可以直接查看net.sh脚本。

clean命令会将所有相关的docker 容器和remote的动态资源全部删除。还原到最初的demo文件状态。

资源清单

无论是remote还是local模式,最终资源和网络准备完成之后,核心资源列表如下:

demo/artifacts/  
├── channel-artifacts                
│   ├── channel2.tx    
│   ├── channel.tx  
│   ├── genesis.block  
│   ├── Org1MSPanchors.tx  
│   └── Org2MSPanchors.tx  
├── connection-profile              
│   ├── network.yaml  
│   ├── org1.yaml  
│   ├── org2.yaml  
├── crypto-config  
│   ├── ordererOrganizations  
│   │   └── example.com  
│   └── peerOrganizations  
│       ├── org1.example.com  
│       └── org2.example.com

运行Demo

网络和相关资源准备成功之后,进入demo/node目录。 其主要结构为:

├── app                             //核心应用接口
│   ├── api-handler.js              //接口定义文件
│   ├── *.js                        //应用实现模块
│   ├── tools                       //通用工具类
│   │   ├── ca-tools.js
│   │   ├── config-tool.js
│   │   └── helper.js
├── app-test.js                     //Demo程序启动文件
├── package.json
└── readme.md

使用命令node app-test.js即可进行一个完整workflow的测试,包括最开始我们提到的所有功能。 同时可以使用node app-test.js -m ca|createChannel|joinChannel|install|instantiate|invoke|query|queryChaincodeInfo|queryChannelInfo来运行单个功能。

程序使用的均为默认参数,其定义在app-test.js文件中。可以按照需求修改对应的参数,再运行程序即可。

持续更新

如果在使用途中发现任何问题,或者有任何需求可以在该项目的issue中提出改进方案或者建议。 Github地址:Hyperledger-fabric-node-sdk-demo

Fabric v0.6

Fabric 目前的稳定版本为 v0.6,最新的版本 1.0 还在演进中,即将发布。

v0.6 的架构相对简单,适合作为实验或 PoC 场景使用。

Fabric v0.6 安装部署

如果是初次接触 Hyperledger Fabric 项目,推荐采用如下的步骤,基于 Docker-Compose 的一键部署。

官方文档现在也完善了安装部署的步骤,具体可以参考代码 doc 目录下内容。

动手前,建议适当了解一些 Docker 相关知识

安装 Docker

Docker 支持 Linux 常见的发行版,如 Redhat/Centos/Ubuntu 等。

$ curl -fsSL https://get.docker.com/ | sh

以 Ubuntu 14.04 为例,安装成功后,修改 Docker 服务配置(/etc/default/docker 文件)。

DOCKER_OPTS="$DOCKER_OPTS -H tcp://0.0.0.0:2375 -H unix:///var/run/docker.sock --api-cors-header='*'"

重启 Docker 服务。

$ sudo service docker restart

Ubuntu 16.04 中默认采用了 systemd 管理启动服务,Docker 配置文件在 /etc/systemd/system/docker.service.d/override.conf

修改后,需要通过如下命令重启 Docker 服务。

$ sudo systemctl daemon-reload
$ sudo systemctl restart docker.service

安装 docker-compose

首先,安装 python-pip 软件包。

$ sudo aptitude install python-pip

安装 docker-compose(推荐为 1.7.0 及以上版本)。

$ sudo pip install docker-compose>=1.7.0

下载镜像

目前 1.0 代码还没有正式发布,推荐使用 v0.6 分支代码进行测试。

下载相关镜像,并进行配置。

$ docker pull yeasy/hyperledger-fabric:0.6-dp 
  && docker pull yeasy/hyperledger-fabric-peer:0.6-dp 
  && docker pull yeasy/hyperledger-fabric-base:0.6-dp 
  && docker pull yeasy/blockchain-explorer:latest 
  && docker tag yeasy/hyperledger-fabric-peer:0.6-dp hyperledger/fabric-peer 
  && docker tag yeasy/hyperledger-fabric-base:0.6-dp hyperledger/fabric-baseimage 
  && docker tag yeasy/hyperledger-fabric:0.6-dp hyperledger/fabric-membersrvc

也可以使用 官方仓库 中的镜像。

$ docker pull hyperledger/fabric-peer:x86_64-0.6.1-preview 
  && docker pull hyperledger/fabric-membersrvc:x86_64-0.6.1-preview 
  && docker pull yeasy/blockchain-explorer:latest 
  && docker tag hyperledger/fabric-peer:x86_64-0.6.1-preview hyperledger/fabric-peer 
  && docker tag hyperledger/fabric-peer:x86_64-0.6.1-preview hyperledger/fabric-baseimage 
  && docker tag hyperledger/fabric-membersrvc:x86_64-0.6.1-preview hyperledger/fabric-membersrvc

之后,用户可以选择采用不同的一致性机制,包括 noops、pbft 两类。

使用 noops 模式

noops 默认没有采用 consensus 机制,1 个节点即可,可以用来进行快速测试。

$ docker run --name=vp0 
    --restart=unless-stopped 
    -it 
    -p 7050:7050 
    -p 7051:7051 
    -v /var/run/docker.sock:/var/run/docker.sock 
    -e CORE_PEER_ID=vp0 
    -e CORE_PEER_ADDRESSAUTODETECT=true 
    -e CORE_NOOPS_BLOCK_WAIT=10 
    hyperledger/fabric-peer:latest peer node start

使用 PBFT 模式

PBFT 是经典的分布式一致性算法,也是 hyperledger 目前最推荐的算法,该算法至少需要 4 个节点。

首先,下载 Compose 模板文件。

$ git clone https://github.com/yeasy/docker-compose-files

进入 hyperledger/0.6/pbft 目录,查看包括若干模板文件,功能如下。

  • 4-peers.yml: 启动 4 个 PBFT peer 节点。
  • 4-peers-with-membersrvc.yml: 启动 4 个 PBFT peer 节点 + 1 个 CA 节点,并启用 CA 功能。
  • 4-peers-with-explorer.yml: 启动 4 个 PBFT peer 节点 + 1 个 Blockchain-explorer,可以通过 Web 界面监控集群状态。
  • 4-peers-with-membersrvc-explorer.yml: 启动 4 个 PBFT peer 节点 + 1 个 CA 节点 + 1 个 Blockchain-explorer,并启用 CA 功能。

例如,快速启动一个 4 个 PBFT 节点的集群。

$ docker-compose -f 4-peers.yml up

多物理节点部署

上述方案的典型场景是单物理节点上部署多个 Peer 节点。如果要扩展到多物理节点,需要容器云平台的支持,如 Swarm 等。

当然,用户也可以分别在各个物理节点上通过手动启动容器的方案来实现跨主机组网,每个物理节点作为一个 peer 节点。

首先,以 4 节点下的 PBFT 模式为例,配置 4 台互相连通的物理机,分别按照上述步骤配置 Docker,下载镜像。

4 台物理机分别命名为 vp0 ~ vp3。

vp0

vp0 作为初始的探测节点。

$ docker run --name=vp0 
    --net="host" 
    --restart=unless-stopped 
    -it --rm 
    -v /var/run/docker.sock:/var/run/docker.sock 
    -e CORE_PEER_ID=vp0 
    -e CORE_PBFT_GENERAL_N=4 
    -e CORE_LOGGING_LEVEL=debug 
    -e CORE_PEER_ADDRESSAUTODETECT=true 
    -e CORE_PEER_NETWORKID=dev 
    -e CORE_PEER_VALIDATOR_CONSENSUS_PLUGIN=pbft 
    -e CORE_PBFT_GENERAL_MODE=batch 
    -e CORE_PBFT_GENERAL_TIMEOUT_REQUEST=10s 
    hyperledger/fabric-peer:latest peer node start

vp1 ~ vp3

以 vp1 为例,假如 vp0 的地址为 10.0.0.1。

$ NAME=vp1
$ ROOT_NODE=10.0.0.1
$ docker run --name=${NAME} 
    --net="host" 
    --restart=unless-stopped 
    -it --rm 
    -v /var/run/docker.sock:/var/run/docker.sock 
    -e CORE_PEER_ID=${NAME} 
    -e CORE_PBFT_GENERAL_N=4 
    -e CORE_LOGGING_LEVEL=debug 
    -e CORE_PEER_ADDRESSAUTODETECT=true 
    -e CORE_PEER_NETWORKID=dev 
    -e CORE_PEER_VALIDATOR_CONSENSUS_PLUGIN=pbft 
    -e CORE_PBFT_GENERAL_MODE=batch 
    -e CORE_PBFT_GENERAL_TIMEOUT_REQUEST=10s 
    -e CORE_PEER_DISCOVERY_ROOTNODE=${ROOT_NODE}:7051 
    hyperledger/fabric-peer:latest peer node start

服务端口

Hyperledger 默认监听的服务端口包括:

  • 7050: REST 服务端口,推荐 NVP 节点开放,0.6 之前版本中为 5000;
  • 7051:peer gRPC 服务监听端口,0.6 之前版本中为 30303;
  • 7052:peer CLI 端口,0.6 之前版本中为 30304;
  • 7053:peer 事件服务端口,0.6 之前版本中为 31315;
  • 7054:eCAP
  • 7055:eCAA
  • 7056:tCAP
  • 7057:tCAA
  • 7058:tlsCAP
  • 7059:tlsCAA

使用 chaincode

下面演示 example02 chaincode,完成两方(如 a 和 b)之间进行价值的转移。

部署 chaincode

集群启动后,进入一个 VP 节点。以 pbft 模式为例,节点名称为 pbft_vp0_1

$ docker exec -it pbft_vp0_1 bash

部署 chaincode example02。

$ peer chaincode deploy -p github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example02 -c '{"Function":"init", "Args": ["a","100", "b", "200"]}'
03:08:44.740 [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
03:08:44.740 [main] main -> INFO 002 Exiting.....

返回 chaincode id 为 ee5b24a1f17c356dd5f6e37307922e39ddba12e5d2e203ed93401d7d05eb0dd194fb9070549c5dc31eb63f4e654dbd5a1d86cbb30c48e3ab1812590cd0f78539,后面将用这个 id 来标识这次交易。为了方便,把它记录到环境变量 CC_ID 中。

$ CC_ID="ee5b24a1f17c356dd5f6e37307922e39ddba12e5d2e203ed93401d7d05eb0dd194fb9070549c5dc31eb63f4e654dbd5a1d86cbb30c48e3ab1812590cd0f78539"

部署成功后,系统中会自动生成几个 chaincode 容器,例如

CONTAINER ID        IMAGE                                                                                                                                      COMMAND                  CREATED             STATUS              PORTS                                   NAMES
e86c26bad76f        dev-vp1-ee5b24a1f17c356dd5f6e37307922e39ddba12e5d2e203ed93401d7d05eb0dd194fb9070549c5dc31eb63f4e654dbd5a1d86cbb30c48e3ab1812590cd0f78539   "/opt/gopath/bin/ee5b"   2 minutes ago       Up 2 minutes                                                dev-vp1-ee5b24a1f17c356dd5f6e37307922e39ddba12e5d2e203ed93401d7d05eb0dd194fb9070549c5dc31eb63f4e654dbd5a1d86cbb30c48e3ab1812590cd0f78539
597ebaf929a0        dev-vp2-ee5b24a1f17c356dd5f6e37307922e39ddba12e5d2e203ed93401d7d05eb0dd194fb9070549c5dc31eb63f4e654dbd5a1d86cbb30c48e3ab1812590cd0f78539   "/opt/gopath/bin/ee5b"   2 minutes ago       Up 2 minutes                                                dev-vp2-ee5b24a1f17c356dd5f6e37307922e39ddba12e5d2e203ed93401d7d05eb0dd194fb9070549c5dc31eb63f4e654dbd5a1d86cbb30c48e3ab1812590cd0f78539
8748a3b47312        dev-vp3-ee5b24a1f17c356dd5f6e37307922e39ddba12e5d2e203ed93401d7d05eb0dd194fb9070549c5dc31eb63f4e654dbd5a1d86cbb30c48e3ab1812590cd0f78539   "/opt/gopath/bin/ee5b"   2 minutes ago       Up 2 minutes                                                dev-vp3-ee5b24a1f17c356dd5f6e37307922e39ddba12e5d2e203ed93401d7d05eb0dd194fb9070549c5dc31eb63f4e654dbd5a1d86cbb30c48e3ab1812590cd0f78539
cf6e762f6a2e        dev-vp0-ee5b24a1f17c356dd5f6e37307922e39ddba12e5d2e203ed93401d7d05eb0dd194fb9070549c5dc31eb63f4e654dbd5a1d86cbb30c48e3ab1812590cd0f78539   "/opt/gopath/bin/ee5b"   2 minutes ago       Up 2 minutes                                                dev-vp0-ee5b24a1f17c356dd5f6e37307922e39ddba12e5d2e203ed93401d7d05eb0dd194fb9070549c5dc31eb63f4e654dbd5a1d86cbb30c48e3ab1812590cd0f78539

查询 chaincode

查询 a 手头的价值,为初始值 100。

$ peer chaincode query -n ${CC_ID} -c '{"Function": "query", "Args": ["a"]}'
03:22:31.420 [chaincodeCmd] chaincodeInvokeOrQuery -> INFO 001 Successfully queried transaction: chaincodeSpec:<type:GOLANG chaincodeID:<name:"ee5b24a1f17c356dd5f6e37307922e39ddba12e5d2e203ed93401d7d05eb0dd194fb9070549c5dc31eb63f4e654dbd5a1d86cbb30c48e3ab1812590cd0f78539" > ctorMsg:<args:"query" args:"a" > >
Query Result: 100
03:22:31.420 [main] main -> INFO 002 Exiting.....

调用 chaincode

a 向 b 转账 10 元。

$ peer chaincode invoke -n ${CC_ID} -c '{"Function": "invoke", "Args": ["a", "b", "10"]}'
03:22:57.345 [chaincodeCmd] chaincodeInvokeOrQuery -> INFO 001 Successfully invoked transaction: chaincodeSpec:<type:GOLANG chaincodeID:<name:"ee5b24a1f17c356dd5f6e37307922e39ddba12e5d2e203ed93401d7d05eb0dd194fb9070549c5dc31eb63f4e654dbd5a1d86cbb30c48e3ab1812590cd0f78539" > ctorMsg:<args:"invoke" args:"a" args:"b" args:"10" > > (fc298ffb-c763-4ed0-9da2-072de2ab20b1)
03:22:57.345 [main] main -> INFO 002 Exiting.....

查询 a 手头的价值,为新的值 90。

```sh $ peer chaincode query -n ${CC_ID} -c '{"Function": "query", "Args": ["a"]}' 03:23:33.045 [chaincodeCmd] chaincodeInvokeOrQuery -> INFO 001 Successfully queried transaction: chaincodeSpec:ctorMsg: > Query Result: 90 03:23:33.045 [main] main -> INFO 002 Exiting..... ···

权限管理

权限管理机制是 hyperledger fabric 项目的一大特色。下面给出使用权限管理的一个应用案例。

启动集群

首先下载相关镜像。

$ docker pull yeasy/hyperledger:latest
$ docker tag yeasy/hyperledger:latest hyperledger/fabric-baseimage:latest
$ docker pull yeasy/hyperledger-peer:latest
$ docker pull yeasy/hyperledger-membersrvc:latest

进入 hyperledger 项目,启动带成员管理的 PBFT 集群。

$ git clone https://github.com/yeasy/docker-compose-files
$ cd docker-compose-files/hyperledger/0.6/pbft
$ docker-compose -f 4-peers-with-membersrvc.yml up

用户登陆

当启用了权限管理后,首先需要登录,例如以内置账户 jim 账户登录。

登录 vp0,并执行登录命令。

$ docker exec -it pbft_vp0_1 bash
# peer network login jim
06:57:13.603 [networkCmd] networkLogin -> INFO 001 CLI client login...
06:57:13.603 [networkCmd] networkLogin -> INFO 002 Local data store for client loginToken: /var/hyperledger/production/client/
Enter password for user 'jim': 6avZQLwcUe9b
06:57:25.022 [networkCmd] networkLogin -> INFO 003 Logging in user 'jim' on CLI interface...
06:57:25.576 [networkCmd] networkLogin -> INFO 004 Storing login token for user 'jim'.
06:57:25.576 [networkCmd] networkLogin -> INFO 005 Login successful for user 'jim'.
06:57:25.576 [main] main -> INFO 006 Exiting.....

也可以用 REST 方式:

POST  HOST:7050/registrar

Request:

{
  "enrollId": "jim",
  "enrollSecret": "6avZQLwcUe9b"
}

Response:

{
    "OK": "User jim is already logged in."
}

chaincode 部署

登录之后,chaincode 的部署、调用等操作与之前类似,只是需要通过 -u 选项来指定用户名。

在 vp0 上执行命令:

# peer chaincode deploy -u jim -p github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example02 -c '{"Function":"init", "Args": ["a","100", "b", "200"]}'
06:58:20.099 [chaincodeCmd] getChaincodeSpecification -> INFO 001 Local user 'jim' is already logged in. Retrieving login token.
06:58:22.178 [chaincodeCmd] chaincodeDeploy -> INFO 002 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
06:58:22.178 [main] main -> INFO 003 Exiting.....

记录下返回的 chaincode ID。

# CC_ID=ee5b24a1f17c356dd5f6e37307922e39ddba12e5d2e203ed93401d7d05eb0dd194fb9070549c5dc31eb63f4e654dbd5a1d86cbb30c48e3ab1812590cd0f78539

此时,查询账户值应当为初始值。

# peer chaincode query -u jim -n ${CC_ID} -c '{"Function": "query", "Args": ["a"]}'
07:28:39.925 [chaincodeCmd] getChaincodeSpecification -> INFO 001 Local user 'jim' is already logged in. Retrieving login token.
07:28:40.281 [chaincodeCmd] chaincodeInvokeOrQuery -> INFO 002 Successfully queried transaction: chaincodeSpec:<type:GOLANG chaincodeID:<name:"ee5b24a1f17c356dd5f6e37307922e39ddba12e5d2e203ed93401d7d05eb0dd194fb9070549c5dc31eb63f4e654dbd5a1d86cbb30c48e3ab1812590cd0f78539" > ctorMsg:<args:"query" args:"a" > secureContext:"jim" >
Query Result: 100
07:28:40.281 [main] main -> INFO 003 Exiting.....

也可以通过 REST 方式进行:

POST  HOST:7050/chaincode

Request:

{
  "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"]
    },
    "secureContext": "jim"
  },
  "id": 1
}

Response:

{
    "jsonrpc": "2.0",
    "result": {
        "status": "OK",
        "message": "ee5b24a1f17c356dd5f6e37307922e39ddba12e5d2e203ed93401d7d05eb0dd194fb9070549c5dc31eb63f4e654dbd5a1d86cbb30c48e3ab1812590cd0f78539"
    },
    "id": 1
}

chaincode 调用

在账户 a、b 之间进行转账 10 元的操作。

# peer chaincode invoke -u jim -n ${CC_ID} -c '{"Function": "invoke", "Args": ["a", "b", "10"]}'
07:29:25.245 [chaincodeCmd] getChaincodeSpecification -> INFO 001 Local user 'jim' is already logged in. Retrieving login token.
07:29:25.585 [chaincodeCmd] chaincodeInvokeOrQuery -> INFO 002 Successfully invoked transaction: chaincodeSpec:<type:GOLANG chaincodeID:<name:"ee5b24a1f17c356dd5f6e37307922e39ddba12e5d2e203ed93401d7d05eb0dd194fb9070549c5dc31eb63f4e654dbd5a1d86cbb30c48e3ab1812590cd0f78539" > ctorMsg:<args:"invoke" args:"a" args:"b" args:"10" > secureContext:"jim" > (f8347e3b-7230-4561-9017-3946756a0bf4)
07:29:25.585 [main] main -> INFO 003 Exiting.....

也可以通过 REST 方式进行:

POST  HOST:7050/chaincode

Request:

{
  "jsonrpc": "2.0",
  "method": "invoke",
  "params": {
      "type": 1,
      "chaincodeID":{
          "name":"980d4bb7f69578592e5775a6da86d81a221887817d7164d3e9d4d4df1c981440abf9a61417eaf8ad6f7fc79893da36de2cf4709131e9af39bca6ebc2e5a1cd9d"
      },
      "ctorMsg": {
         "function":"invoke",
         "args":["a", "b", "100"]
      },
    "secureContext": "jim"
  },
  "id": 3
}

Response:

{
    "jsonrpc": "2.0",
    "result": {
        "status": "OK",
        "message": "66308740-a2c5-4a60-81f1-778dbed49cc3"
    },
    "id": 3
}

chaincode 查询

查询 a 账户的余额。

# peer chaincode query -u jim -n ${CC_ID} -c '{"Function": "query", "Args": ["a"]}'
07:29:55.844 [chaincodeCmd] getChaincodeSpecification -> INFO 001 Local user 'jim' is already logged in. Retrieving login token.
07:29:56.198 [chaincodeCmd] chaincodeInvokeOrQuery -> INFO 002 Successfully queried transaction: chaincodeSpec:<type:GOLANG chaincodeID:<name:"ee5b24a1f17c356dd5f6e37307922e39ddba12e5d2e203ed93401d7d05eb0dd194fb9070549c5dc31eb63f4e654dbd5a1d86cbb30c48e3ab1812590cd0f78539" > ctorMsg:<args:"query" args:"a" > secureContext:"jim" >
Query Result: 90
07:29:56.198 [main] main -> INFO 003 Exiting.....

也可以通过 REST 方式进行:

POST  HOST:7050/chaincode

Request:

{
  "jsonrpc": "2.0",
  "method": "query",
  "params": {
      "type": 1,
      "chaincodeID":{
          "name":"980d4bb7f69578592e5775a6da86d81a221887817d7164d3e9d4d4df1c981440abf9a61417eaf8ad6f7fc79893da36de2cf4709131e9af39bca6ebc2e5a1cd9d"
      },
      "ctorMsg": {
         "function":"query",
         "args":["a"]
      },
      "secureContext": "jim"
  },
  "id": 5
}

Response:

{
    "jsonrpc": "2.0",
    "result": {
        "status": "OK",
        "message": "900"
    },
    "id": 5
}

区块信息查询

URL:

GET  HOST:7050/chain/blocks/2

Response:

{
    "transactions": [
        {
            "type": 2,
            "chaincodeID": "EoABMjhiYjJiMjMxNjE3MWE3MDZiYjI4MTBlYzM1ZDA5NWY0MzA4NzdiZjQ0M2YxMDYxZWYwZjYwYmJlNzUzZWQ0NDA3MDBhNTMxMmMxNjM5MGQzYjMwMTk5ZmU5NDY1YzNiNzVkNTk0NDM1OGNhYWUwMWNhODFlZjI4MTI4YTFiZmI=",
            "payload": "Cp0BCAESgwESgAEyOGJiMmIyMzE2MTcxYTcwNmJiMjgxMGVjMzVkMDk1ZjQzMDg3N2JmNDQzZjEwNjFlZjBmNjBiYmU3NTNlZDQ0MDcwMGE1MzEyYzE2MzkwZDNiMzAxOTlmZTk0NjVjM2I3NWQ1OTQ0MzU4Y2FhZTAxY2E4MWVmMjgxMjhhMWJmYhoTCgZpbnZva2USAWESAWISAzEwMA==",
            "uuid": "2b3b6cf3-9887-4dd5-8f2e-3634ec9c719a",
            "timestamp": {
                "seconds": 1466577447,
                "nanos": 399637431
            },
            "nonce": "5AeA6S1odhPIDiGjFTFG8ttcihOoNNsh",
            "cert": "MIICPzCCAeSgAwIBAgIRAMndnS+Me0G6gs4J9/fb8HcwCgYIKoZIzj0EAwMwMTELMAkGA1UEBhMCVVMxFDASBgNVBAoTC0h5cGVybGVkZ2VyMQwwCgYDVQQDEwN0Y2EwHhcNMTYwNjIyMDYzMzE4WhcNMTYwOTIwMDYzMzE4WjAxMQswCQYDVQQGEwJVUzEUMBIGA1UEChMLSHlwZXJsZWRnZXIxDDAKBgNVBAMTA2ppbTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABDLd2W8PxzgB4A85Re2x44BApbOGqP05tnkygbXSctLiqi5HVfwRAACS6znVA9+toni59Yy+XAH3w2offdjFW3mjgdwwgdkwDgYDVR0PAQH/BAQDAgeAMAwGA1UdEwEB/wQCMAAwDQYDVR0OBAYEBAECAwQwDwYDVR0jBAgwBoAEAQIDBDBNBgYqAwQFBgcBAf8EQAfASTE6bZ0P5mrEzTa5r1UyKFv+dKezBiGU0V3l2iWzk9evlGMvaC2pwhEKfKDdKxs7YSMYe/7cLq/oF++GBVowSgYGKgMEBQYIBEBEO3TKXuORl5Geuco8Gnn5TkoIl4+b96aPGDGvKbmDjMXR9vEBuUXTnsbDL53j7kC8/XQs1kZboC1ojLeUSN03MAoGCCqGSM49BAMDA0kAMEYCIQCZqyANMFcu1WiMe2So0pC7eRU95F0+qUXLAKZsPWv/YQIhALmNaglP7CoMOe2qxehucmffDlu0BRLSYDHyV9xcxmkH",
            "signature": "MEYCIQDob3NqdrfwlSGhi+zz+Ypl7S9QQ07RIFr8nV92e8KDNgIhANIljz4tRS8vwQk01hTemNQFJX2zMI6DhSUFZivbbtoR"
        }
    ],
    "stateHash": "7YUoVvYnMLHbLf47uTixLtkjF6xM9DuvgSWC92MbOUzk09xhcRBBLZqe5FvJElgZemELBOcuIFnubL0LiGH0yw==",
    "previousBlockHash": "On4BlpqCYNpugUKluqvOcbvkr3TAQxmlISLdd6qrONtIgmQ4iUDeWxAA9lUCceZfF8tke8A0Wy7m9tksNpKodw==",
    "consensusMetadata": "CAI=",
    "nonHashData": {
        "localLedgerCommitTimestamp": {
            "seconds": 1466577447,
            "nanos": 653618964
        },
        "transactionResults": [
            {
                "uuid": "2b3b6cf3-9887-4dd5-8f2e-3634ec9c719a"
            }
        ]
    }
}

Python 客户端

前面应用案例,都是直接通过 HTTP API 来跟 hyperledger 进行交互,操作比较麻烦。

还可以直接通过 hyperledger-py 客户端来进行更方便的操作。

安装

$ pip install hyperledger --upgrade

或直接源码安装

$ git clone https://github.com/yeasy/hyperledger-py.git
$ cd hyperledger-py
$ pip install -r requirements.txt
$ python setup.py install

使用

>>> from hyperledger.client import Client
>>> c = Client(base_url="http://127.0.0.1:7050")
>>> c.peer_list()
{u'peers': [{u'type': 1, u'ID': {u'name': u'vp1'}, u'address': u'172.17.0.2:30303'}, {u'type': 1, u'ID': {u'name': u'vp2'}, u'address': u'172.17.0.3:30303'}]}

更多使用方法,可以参考 API 文档

其它客户端

目前,HyperLedger Fabric 已经成立了 SDK 工作组

目前在实现的客户端 SDK 包括:

原文地址:https://www.cnblogs.com/hzcya1995/p/13312703.html