MENU

搭建Hyperledger Fabric多机网络

搭建fabric-v1.0.0 1peer+1orderer网络

前言

考虑到虚拟机的复杂和服务器的方便又昂贵,最终选择两台服务器,模拟搭建一个orderer服务节点,一个peer节点,实现了简单的fabric平台记账功能。本文记录了Hyperledger Fabric从环境搭建,到跨机器间通过证书、公密钥等方式部署,实现了fabric自带样例example02中智能合约的记账功能,可通过如下方式拓展至多节点、多组织机构,构建更广的分布式区块链网络,并在运行、更新智能合约的时候增加背书功能。以下是我的主机分布和配置:

HOSTS_NAMEIP
peer0.org1.example.com47.100.178.167
orderer.example.com129.211.29.99

两台主机版本:

[root@VM_0_7_centos orderer]# cat /proc/version 
Linux version 3.10.0-514.21.1.el7.x86_64 (builder@kbuilder.dev.centos.org) (gcc version 4.8.5 20150623 (Red Hat 4.8.5-11) (GCC) ) #1 SMP Thu May 25 17:04:51 UTC 2017

[root@izuf6aqowtvq0ud222hha1z org]# cat /proc/version 
Linux version 3.10.0-514.26.2.el7.x86_64 (builder@kbuilder.dev.centos.org) (gcc version 4.8.5 20150623 (Red Hat 4.8.5-11) (GCC) ) #1 SMP Tue Jul 4 15:04:05 UTC 2017

环境配置配置:

# Hyperledger Fabric version
v1.0.0

# go version
go version go1.12.2 linux/amd64

# docker version
Client:
 Version:           18.09.6
 API version:       1.39
 Go version:        go1.10.8
 Git commit:        481bc77156
 Built:             Sat May  4 02:34:58 2019
 OS/Arch:           linux/amd64
 Experimental:      false

Server: Docker Engine - Community
 Engine:
  Version:          18.09.6
  API version:      1.39 (minimum version 1.12)
  Go version:       go1.10.8
  Git commit:       481bc77
  Built:            Sat May  4 02:02:43 2019
  OS/Arch:          linux/amd64
  Experimental:     false

# docker-compose version
docker-compose version 1.11.2, build dfed245
docker-py version: 2.1.0
CPython version: 2.7.13
OpenSSL version: OpenSSL 1.0.1t  3 May 2016

# git version
git version 1.8.3.1

# gcc version (gcc -v)
gcc 版本 4.8.5

# python version
Python 2.7.5

# pip version (pip -V)
pip 8.1.2 from /usr/lib/python2.7/site-packages (python 2.7)

接下来构建以上环境配置。


安装基本环境

1.基本依赖包

yum install -y git bzip2 gcc gcc-c++ libtool libltdl-dev libtool-ltdl-devel openssl

2.go环境

官网下载go-1.12.2.linux-amd64包(当然现在可以下载最新版)

sudo tar -C /usr/local -xzf go1.12.2.linux-amd64.tar.gz

编辑当前用户的环境变量:

vi ~/.profile
添加以下内容:
export PATH=$PATH:/usr/local/go/bin 
export GOROOT=/usr/local/go 
export GOPATH=$HOME/go 
export PATH=$PATH:$HOME/go/bin

编辑保存并退出vi后,记得把这些环境载入:

source ~/.profile

然后在/etc/profile下加以下内容并保存:

export PATH=$PATH:/usr/local/go/bin 
export GOROOT=/usr/local/go 
export GOPATH=$HOME/go 
export PATH=$PATH:$HOME/go/bin
source ~/.profile

接着在终端执行:

source /etc/profile

我们把go的目录GOPATH设置为当前用户的文件夹下,所以记得创建go文件夹

cd ~
mkdir go

3.docker环境

# step 1: 安装必要的一些系统工具
sudo yum install -y yum-utils device-mapper-persistent-data lvm2
# Step 2: 添加软件源信息
sudo yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
# Step 3: 更新并安装Docker-CE
sudo yum makecache fast
sudo yum -y install docker-ce
# Step 4: 开启Docker服务
sudo service docker start

# 注意:
# 官方软件源默认启用了最新的软件,您可以通过编辑软件源的方式获取各个版本的软件包。例如官方并没有将测试版本的软件源置为可用,您可以通过以下方式开启。同理可以开启各种测试版本等。
# vim /etc/yum.repos.d/docker-ee.repo
#   将[docker-ce-test]下方的enabled=0修改为enabled=1
#
# 安装指定版本的Docker-CE:
# Step 1: 查找Docker-CE的版本:
# yum list docker-ce.x86_64 --showduplicates | sort -r
#   Loading mirror speeds from cached hostfile
#   Loaded plugins: branch, fastestmirror, langpacks
#   docker-ce.x86_64            17.03.1.ce-1.el7.centos            docker-ce-stable
#   docker-ce.x86_64            17.03.1.ce-1.el7.centos            @docker-ce-stable
#   docker-ce.x86_64            17.03.0.ce-1.el7.centos            docker-ce-stable
#   Available Packages
# Step2: 安装指定版本的Docker-CE: (VERSION例如上面的17.03.0.ce.1-1.el7.centos)
# sudo yum -y install docker-ce-[VERSION]

开机自启动:

chkconfig docker on

4.安装docker-compose:

curl -L https://github.com/docker/compose/releases/download/1.11.2/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose
chmod +x /usr/local/bin/docker-compose
# docker-compose version可查看docker-compose版本

5.Fabric源码下载

我们可以使用Git命令下载源码,也可以使用go get命令,偷懒一点,我们直接用go get命令获取最新的Fabric源码:

go get github.com/hyperledger/fabric

这个可能等的时间比较久,等完成后,我们可以在~/go/src/github.com/hyperledger/fabric中找到所有的最新的源代码。如果上述方法被那个了(无法访问,原因不可描述[滑稽]),那么可创建目录/root/go/src/github.com/hyperledger/,并执行:

git clone https://github.com/hyperledger/fabric.git

由于Fabric一直在更新,所有我们并不需要最新最新的源码,需要切换到v1.0.0版本的源码即可:

cd ~/go/src/github.com/hyperledger/fabric
git checkout v1.0.0

6.Fabric Docker镜像的下载

这个其实很简单,因为我们已经设置了Docker Hub镜像地址,所以下载也会很快。官方文件也提供了批量下载的脚本。我们直接运行:

cd ~/go/src/github.com/hyperledger/fabric/examples/e2e_cli/
source download-dockerimages.sh -c x86_64-1.0.0 -f x86_64-1.0.0

# 如果发现某些镜像缺失,可用如下方式下载对应缺失版本的镜像:
# docker pull hyperledger/fabric-baseimage:x86_64-0.3.2
# docker pull hyperledger/fabric-baseos:x86_64-0.3.2
# docker pull hyperledger/fabric-tools:x86_64-1.0.5
# docker pull hyperledger/fabric-kafka:x86_64-1.0.5
# docker pull hyperledger/fabric-zookeeper:x86_64-1.0.5
# docker pull hyperledger/fabric-orderer:x86_64-1.0.5
# docker pull hyperledger/fabric-ccenv:x86_64-1.0.5

# 如果出现创建channel失败,删除 /etc/resolv.conf文件即可
# 但/etc/resolv.conf是DNS配置文件,尽量不要删除,若误删重启服务器即可恢复

构建网络

上述步骤即完成了fabric-v1.0.0的基本环境搭建,如go语言,docker环境,docker fabric镜像,docker-compose及一些基本的依赖环境等,接下来我们构建自己的1peer+1orderer网络。

1.orderer节点服务器配置

在fabric下的examples目录的中新建一个自定义文件夹orderer:

[root@VM_0_7_centos orderer]# pwd
/root/go/src/github.com/hyperledger/fabric/examples/orderer

准备fabric提供的二进制编译工具:Fabric平台特定使用的二进制文件cryptogenconfigtxgenconfigtxlator,以及peer。我们可以通过configtxgencryptogen手动生成证书/密钥以及各项配置文件。也可通过e2c_cli例子中的generateArtifacts.sh自动生成,由于我们需要自定义各节点的域名,及联盟链的统一域名,下面手动生成。通过运行generateArtifacts.sh脚本,会在release下创建目录linux-amd64,找到fabric目录release/linux-amd64/bin中的二进制文件:

[root@VM_0_7_centos bin]# pwd
/root/go/src/github.com/hyperledger/fabric/release/linux-amd64/bin
[root@VM_0_7_centos bin]# ll
总用量 85296
-rwxr-xr-x 1 root root 16457479 5月  13 10:27 configtxgen
-rwxr-xr-x 1 root root 17530145 5月  13 10:27 configtxlator
-rwxr-xr-x 1 root root  8585051 5月  13 10:27 cryptogen
-rwxr-xr-x 1 root root      441 5月  13 10:27 get-byfn.sh
-rwxr-xr-x 1 root root      757 5月  13 10:27 get-docker-images.sh
-rwxr-xr-x 1 root root 20798659 5月  13 10:27 orderer
-rwxr-xr-x 1 root root 23959314 5月  13 10:27 peer

bin目录复制到刚刚新建的文件夹目录orderer中,并创建新文件夹base,即orderer下有两个文件夹binbase

/root/go/src/github.com/hyperledger/fabric/examples/orderer目录关系:

orderer
├── base
└── bin

1.1.生成组织证书与私钥

在bin目录中新建crypto-config.yaml文件,可参照e2e_cli例子中的crypto-config.yaml,文件内容如下:

OrdererOrgs:
  - Name: Orderer
    Domain: example.com
    Specs:
      - Hostname: orderer
 
PeerOrgs:
  - Name: Demo
    Domain: demo.example.com
    Template:
     Count: 1
    Users:
     Count: 1

文件定义了orderer节点以及peer节点的域名及数量等信息。我们组建一个名为example的联盟,且我们自己的组织名称为Demo,我们会创建一个Orderer排序服务节点,同时还会创建一个peer节点。接下来,使用crytogen工具给我们不同的网络实体(peer/client)生成加密证书(X509 certs)。这些证书代表了身份,当我们的网络实体在进行通信以及transact的时候进行签名与验证身份。

crypto-config.yaml配置文件将被crytogen工具调用,文件中包括了网络拓扑,同时允许我们给organization(Demo)以及component(隶属于organization的组件)生成一个证书与私钥的集合。每一个organization(Demo)被分配一个唯一的根证书(绑定了隶属于organization(Demo)的具体的component,包括peers与orderers)。Hyperledger Fabric的transaction与通信均被节点的私钥(keystore)进行签名,截止被公钥进行验证(signcerts)。 这个配置文件中有一个计数(count)的变量,我们使用其定义organization(Demo)中peer的数量,在本例中我们定义Demo组织有一个peer。

在bin目录下执行命令:

./cryptogen generate --config=./crypto-config.yaml

执行成功后,bin目录下生成crypto-config文件夹,其中会有ordererOrganizationspeerOrganizations两个目录:

[root@VM_0_7_centos crypto-config]# pwd
/root/go/src/github.com/hyperledger/fabric/examples/orderer/bin/crypto-config
[root@VM_0_7_centos crypto-config]# ll
总用量 8
drwxr-xr-x 3 root root 4096 5月  13 15:47 ordererOrganizations
drwxr-xr-x 3 root root 4096 5月  13 15:47 peerOrganizations

1.2.定义configtx.yaml文件

使用configtxgen工具来执行configtx.yaml文件创建orderer/Genesis/block,在此之前需要为configtxgen工具指定configtx.yaml文件的路径,我们需要设置一个环境变量,进入bin目录,执行如下命令:

export FABRIC_CFG_PATH=$PWD

bin目录下创建channel-artifacts目录,用来存放各种渠道的源文件。新建configtx.yaml文件,可参照e2e_cli中示例文件。文件内容如下:


Profiles:
 
    ExampleOrdererGenesis:
        Orderer:
            <<: *OrdererExample
            Organizations:
                - *OrdererDemo
        Consortiums:
            ExampleConsortium:
                Organizations:
                    - *Demo
    ExampleChannel:
        Consortium: ExampleConsortium
        Application:
            <<: *ApplicationExample
            Organizations:
                - *Demo
Organizations:
 
    - &OrdererDemo
        Name: OrdererDemo
        ID: OrdererMSP
        MSPDir: crypto-config/ordererOrganizations/example.com/msp
 
    - &Demo
        Name: DemoMSP
        ID: DemoMSP
        MSPDir: crypto-config/peerOrganizations/demo.example.com/msp
        AnchorPeers:
            - Host: peer0.demo.example.com
              Port: 7051
 
Orderer: &OrdererExample
 
    OrdererType: solo
 
    Addresses:
        - orderer.example.com:7050
 
    BatchTimeout: 2s
    BatchSize:
        MaxMessageCount: 10
        AbsoluteMaxBytes: 99 MB
        PreferredMaxBytes: 512 KB
 
    Kafka:
        Brokers:
            - 127.0.0.1:9092
    Organizations:
 
Application: &ApplicationExample
 
    Organizations:

在该文件中,我们定义了组织名称peer0.demo.example.com、组织排序服务名称、组织渠道名称、应用渠道名称、应用联盟名称等。

1.3.生成初始区块

接下来,通过configtxgen工具生成初始区块genesis.block

./configtxgen -profile ExampleOrdererGenesis -outputBlock ./channel-artifacts/genesis.block

命令执行完成后,在bin目录下可见genesis.block文件。

1.4.生成channel源文件

生成ID为examplechannel的通道文件:

./configtxgen -profile ExampleChannel -outputCreateChannelTx ./channel-artifacts/channel.tx -channelID examplechannel

1.5.生成channel下节点集合认证文件

examplechannel通道生成ID为DemoMSP的认证文件DEMOMSPanchors.tx

./configtxgen -profile ExampleChannel -outputAnchorPeersUpdate ./channel-artifacts/DEMOMSPanchors.tx -channelID examplechannel -asOrg DemoMSP

完成以上步骤后,bin目录下将生成orderer节点所需的所有配置文件。

channel-artifacts文件夹下文件:

[root@VM_0_7_centos channel-artifacts]# pwd
/root/go/src/github.com/hyperledger/fabric/examples/orderer/bin/channel-artifacts
[root@VM_0_7_centos channel-artifacts]# ll
总用量 16
-rw-r--r-- 1 root root  354 5月  13 16:05 channel.tx
-rw-r--r-- 1 root root  260 5月  13 16:06 DEMOMSPanchors.tx
-rw-r--r-- 1 root root 6349 5月  13 16:02 genesis.block

2.orderer节点启动

在orderer目录下创建一个docker-compose-orderer.yaml文件:

version: '2'
 
services:
 
  orderer.example.com:
    extends:
      file:   base/docker-compose-base.yaml
      service: orderer.example.com
    container_name: orderer.example.com

这里有一个协助启动文件,是位于base目录下的docker-compose-base.yaml文件,这个文件的参数配置如下:

version: '2'

services:

  orderer.example.com:
    container_name: orderer.example.com
    image: hyperledger/fabric-orderer
    environment:
      - ORDERER_GENERAL_LOGLEVEL=debug
      - ORDERER_GENERAL_LISTENADDRESS=0.0.0.0
      - ORDERER_GENERAL_GENESISMETHOD=file
      - ORDERER_GENERAL_GENESISFILE=/var/hyperledger/orderer/orderer.genesis.block
      - ORDERER_GENERAL_LOCALMSPID=OrdererMSP
      - ORDERER_GENERAL_LOCALMSPDIR=/var/hyperledger/orderer/msp
      # enabled TLS
      - ORDERER_GENERAL_TLS_ENABLED=true
      - ORDERER_GENERAL_TLS_PRIVATEKEY=/var/hyperledger/orderer/tls/server.key
      - ORDERER_GENERAL_TLS_CERTIFICATE=/var/hyperledger/orderer/tls/server.crt
      - ORDERER_GENERAL_TLS_ROOTCAS=[/var/hyperledger/orderer/tls/ca.crt]
    working_dir: /opt/gopath/src/github.com/hyperledger/fabric
    command: orderer
    volumes:
        - ../bin/channel-artifacts/genesis.block:/var/hyperledger/orderer/orderer.genesis.block
        - ../bin/crypto-config/ordererOrganizations/example.com/orderers/orderer.example.com/msp:/var/hyperledger/orderer/msp
        - ../bin/crypto-config/ordererOrganizations/example.com/orderers/orderer.example.com/tls/:/var/hyperledger/orderer/tls
    ports:
      - 7050:7050

随后在orderer目录下执行启动命令:

docker-compose -f docker-compose-orderer.yaml up -d

查看docker容器启动情况:

[root@VM_0_7_centos orderer]# docker ps -a
CONTAINER ID        IMAGE                        COMMAND             CREATED             STATUS              PORTS                    NAMES
ed359d5eca1c        hyperledger/fabric-orderer   "orderer"           6 seconds ago       Up 5 seconds        0.0.0.0:7050->7050/tcp   orderer.example.com

# orderer节点启动成功

3.peer节点配置及启动

通过scporderer节点在bin目录下的生成的channel-artifacts/目录和crypto-config/目录拷贝至peer节点的新建org/bin/目录下,并提前在org下创建base目录。

新建在org/docker-compose-org.yaml文件:

version: '2'

services:

  peer0.demo.example.com:
    container_name: peer0.demo.example.com
    extends:
      file:  base/docker-compose-base.yaml
      service: peer0.demo.example.com
    extra_hosts:
      - "orderer.example.com:129.211.29.99"

  cli:
    container_name: cli
    image: hyperledger/fabric-tools
    tty: true
    environment:
      - GOPATH=/opt/gopath
      - CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock
      - CORE_LOGGING_LEVEL=DEBUG
      - CORE_PEER_ID=cli
      - CORE_PEER_ADDRESS=peer0.demo.example.com:7051
      - CORE_PEER_LOCALMSPID=DemoMSP
      - CORE_PEER_TLS_ENABLED=true
      - CORE_PEER_TLS_CERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/demo.example.com/peers/peer0.demo.example.com/tls/server.crt
      - CORE_PEER_TLS_KEY_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/demo.example.com/peers/peer0.demo.example.com/tls/server.key
      - CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/demo.example.com/peers/peer0.demo.example.com/tls/ca.crt
      - CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/demo.example.com/users/Admin@demo.example.com/msp
    working_dir: /opt/gopath/src/github.com/hyperledger/fabric/peer
    volumes:
        - /var/run/:/host/var/run/
        - ../chaincode/go/:/opt/gopath/src/github.com/hyperledger/fabric/examples/chaincode/go
        - ./bin/crypto-config:/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/
        - ./scripts:/opt/gopath/src/github.com/hyperledger/fabric/peer/scripts/
        - ./bin/channel-artifacts:/opt/gopath/src/github.com/hyperledger/fabric/peer/channel-artifacts
    depends_on:
      - peer0.demo.example.com
    extra_hosts:
     - "orderer.example.com:129.211.29.99"
     - "peer0.demo.example.com:47.100.178.167"
  • 想吐槽的一点是CSDN博客上很多配置文件拷贝过来但是docker数据卷映射目录有问题,也就是上述yaml中的volumes项!

这里与orderer不同,有两个协助启动文件,分别是位于base目录下的docker-compose-base.yamlpeer-base.yaml文件,这两个文件的参数配置分别如下:

docker-compose-base.yaml

version: '2'

services:

  peer0.demo.example.com:
    container_name: peer0.demo.example.com
    extends:
      file: peer-base.yaml
      service: peer-base
    environment:
      - CORE_PEER_ID=peer0.demo.example.com
      - CORE_PEER_ADDRESS=peer0.demo.example.com:7051
      - CORE_PEER_CHAINCODELISTENADDRESS=peer0.demo.example.com:7052
      - CORE_PEER_GOSSIP_EXTERNALENDPOINT=peer0.demo.example.com:7051
      - CORE_PEER_LOCALMSPID=DemoMSP
    volumes:
        - /var/run/:/host/var/run/
        - ../bin/crypto-config/peerOrganizations/demo.example.com/peers/peer0.demo.example.com/msp:/etc/hyperledger/fabric/msp
        - ../bin/crypto-config/peerOrganizations/demo.example.com/peers/peer0.demo.example.com/tls:/etc/hyperledger/fabric/tls
    ports:
      - 7051:7051
      - 7052:7052
      - 7053:7053

peer-base.yaml

version: '2'
services:
  peer-base:
    image: hyperledger/fabric-peer
    environment:
      - CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock
      # the following setting starts chaincode containers on the same
      # bridge network as the peers
      # https://docs.docker.com/compose/networking/

      - CORE_VM_DOCKER_HOSTCONFIG_NETWORKMODE=org_default
      #- CORE_LOGGING_LEVEL=ERROR
      - CORE_LOGGING_LEVEL=DEBUG
      - CORE_PEER_TLS_ENABLED=true
      - CORE_PEER_GOSSIP_USELEADERELECTION=true
      - CORE_PEER_GOSSIP_ORGLEADER=false
      - CORE_PEER_PROFILE_ENABLED=true
      - CORE_PEER_TLS_CERT_FILE=/etc/hyperledger/fabric/tls/server.crt
      - CORE_PEER_TLS_KEY_FILE=/etc/hyperledger/fabric/tls/server.key
      - CORE_PEER_TLS_ROOTCERT_FILE=/etc/hyperledger/fabric/tls/ca.crt
    working_dir: /opt/gopath/src/github.com/hyperledger/fabric/peer
    command: peer node start

3.1.启动peer节点:

docker-compose -f docker-compose-org.yaml up -d

查看docker容器,启动了peer0.demo.example.comcli 两个容器

[root@izuf6aqowtvq0ud222hha1z org]# docker ps -a
CONTAINER ID        IMAGE                      COMMAND             CREATED             STATUS              PORTS                              NAMES
6d658097f3b1        hyperledger/fabric-tools   "/bin/bash"         8 seconds ago       Up 8 seconds                                           cli
61a7765829d9        hyperledger/fabric-peer    "peer node start"   9 seconds ago       Up 8 seconds        0.0.0.0:7051-7053->7051-7053/tcp   peer0.demo.example.com

peer节点启动成功。

3.2创建并加入channel

首先我们进入映射的docker cli容器中:

docker exec -it cli bash

执行生成channel id文件命令:

peer channel create -o orderer.example.com:7050 -c examplechannel -f ./channel-artifacts/channel.tx --tls $CORE_PEER_TLS_ENABLED --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem

peer节点加入channel:

peer channel join -b examplechannel.block

4.安装并实例化链码

4.1安装

仍在docker cli容器中安装链码,链码为fabric自带的chaincode_example02实例:

peer chaincode install -n test -v 1.0 -p github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example02

chaincode_example02实现了一个简单的键值对存储账单功能和转帐功能,代码如下供参考:

/*
Copyright IBM Corp. 2016 All Rights Reserved.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

                 http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package main

//WARNING - this chaincode's ID is hard-coded in chaincode_example04 to illustrate one way of
//calling chaincode from a chaincode. If this example is modified, chaincode_example04.go has
//to be modified as well with the new ID of chaincode_example02.
//chaincode_example05 show's how chaincode ID can be passed in as a parameter instead of
//hard-coding.

import (
        "fmt"
        "strconv"

        "github.com/hyperledger/fabric/core/chaincode/shim"
        pb "github.com/hyperledger/fabric/protos/peer"
)

// SimpleChaincode example simple Chaincode implementation
type SimpleChaincode struct {
}

func (t *SimpleChaincode) Init(stub shim.ChaincodeStubInterface) pb.Response {
        fmt.Println("ex02 Init")
        _, args := stub.GetFunctionAndParameters()
        var A, B string    // Entities
        var Aval, Bval int // Asset holdings
        var err error

        if len(args) != 4 {
                return shim.Error("Incorrect number of arguments. Expecting 4")
        }

        // Initialize the chaincode
        A = args[0]
        Aval, err = strconv.Atoi(args[1])
        if err != nil {
                return shim.Error("Expecting integer value for asset holding")
        }
        B = args[2]
        Bval, err = strconv.Atoi(args[3])
        if err != nil {
                return shim.Error("Expecting integer value for asset holding")
        }
        fmt.Printf("Aval = %d, Bval = %d\n", Aval, Bval)

        // Write the state to the ledger
        err = stub.PutState(A, []byte(strconv.Itoa(Aval)))
        if err != nil {
                return shim.Error(err.Error())
        }

        err = stub.PutState(B, []byte(strconv.Itoa(Bval)))
        if err != nil {
                return shim.Error(err.Error())
        }

        return shim.Success(nil)
}

func (t *SimpleChaincode) Invoke(stub shim.ChaincodeStubInterface) pb.Response {
        fmt.Println("ex02 Invoke")
        function, args := stub.GetFunctionAndParameters()
        if function == "invoke" {
                // Make payment of X units from A to B
                return t.invoke(stub, args)
        } else if function == "delete" {
                // Deletes an entity from its state
                return t.delete(stub, args)
        } else if function == "query" {
                // the old "Query" is now implemtned in invoke
                return t.query(stub, args)
        }

        return shim.Error("Invalid invoke function name. Expecting \"invoke\" \"delete\" \"query\"")
}

// Transaction makes payment of X units from A to B
func (t *SimpleChaincode) invoke(stub shim.ChaincodeStubInterface, args []string) pb.Response {
        var A, B string    // Entities
        var Aval, Bval int // Asset holdings
        var X int          // Transaction value
        var err error

        if len(args) != 3 {
                return shim.Error("Incorrect number of arguments. Expecting 3")
        }

        A = args[0]
        B = args[1]

        // Get the state from the ledger
        // TODO: will be nice to have a GetAllState call to ledger
        Avalbytes, err := stub.GetState(A)
        if err != nil {
                return shim.Error("Failed to get state")
        }
        if Avalbytes == nil {
                return shim.Error("Entity not found")
        }
        Aval, _ = strconv.Atoi(string(Avalbytes))

        Bvalbytes, err := stub.GetState(B)
        if err != nil {
                return shim.Error("Failed to get state")
        }
        if Bvalbytes == nil {
                return shim.Error("Entity not found")
        }
        Bval, _ = strconv.Atoi(string(Bvalbytes))

        // Perform the execution
        X, err = strconv.Atoi(args[2])
        if err != nil {
                return shim.Error("Invalid transaction amount, expecting a integer value")
        }
        Aval = Aval - X
        Bval = Bval + X
        fmt.Printf("Aval = %d, Bval = %d\n", Aval, Bval)

        // Write the state back to the ledger
        err = stub.PutState(A, []byte(strconv.Itoa(Aval)))
        if err != nil {
                return shim.Error(err.Error())
        }

        err = stub.PutState(B, []byte(strconv.Itoa(Bval)))
        if err != nil {
                return shim.Error(err.Error())
        }

        return shim.Success(nil)
}

// Deletes an entity from state
func (t *SimpleChaincode) delete(stub shim.ChaincodeStubInterface, args []string) pb.Response {
        if len(args) != 1 {
                return shim.Error("Incorrect number of arguments. Expecting 1")
        }

        A := args[0]

        // Delete the key from the state in ledger
        err := stub.DelState(A)
        if err != nil {
                return shim.Error("Failed to delete state")
        }

        return shim.Success(nil)
}

// query callback representing the query of a chaincode
func (t *SimpleChaincode) query(stub shim.ChaincodeStubInterface, args []string) pb.Response {
        var A string // Entities
        var err error

        if len(args) != 1 {
                return shim.Error("Incorrect number of arguments. Expecting name of the person to query")
        }

        A = args[0]

        // Get the state from the ledger
        Avalbytes, err := stub.GetState(A)
        if err != nil {
                jsonResp := "{\"Error\":\"Failed to get state for " + A + "\"}"
                return shim.Error(jsonResp)
        }

        if Avalbytes == nil {
                jsonResp := "{\"Error\":\"Nil amount for " + A + "\"}"
                return shim.Error(jsonResp)
        }

        jsonResp := "{\"Name\":\"" + A + "\",\"Amount\":\"" + string(Avalbytes) + "\"}"
        fmt.Printf("Query Response:%s\n", jsonResp)
        return shim.Success(Avalbytes)
}

func main() {
        err := shim.Start(new(SimpleChaincode))
        if err != nil {
                fmt.Printf("Error starting Simple chaincode: %s", err)
        }
}

4.2实例化

初始化链码,指定a有100rmb,b有200rmb

peer chaincode instantiate -o orderer.example.com:7050 --tls $CORE_PEER_TLS_ENABLED --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C examplechannel -n test -v 1.0 -c '{"Args":["init","a","100","b","200"]}'

调用invoke函数方法,从b向a转50rmb

peer chaincode invoke -o orderer.example.com:7050 --tls $CORE_PEER_TLS_ENABLED --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C examplechannel -n test -c '{"Args":["invoke","b","a","50"]}'

然后我们可以查询a或b的余额,具体调用query方法,比如查询a余额:

peer chaincode invoke -o orderer.example.com:7050 --tls $CORE_PEER_TLS_ENABLED --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C examplechannel -n test -c '{"Args":["query","a"]}'

至此,基本的环境搭建和实例测试就完成了。网上遇到的很多各种各样的错误,许多都来源于yaml文件中的配置出错。如下即是我参考的博客,他们写的博客或多或少在表达和逻辑上有很多错误,我也是慢慢摸索出来的,如果以上博客有任何问题,请及时向我提出宝贵意见。

参考博客:

  1. fabric两台机器部署
  2. fabric多机部署体验
  3. 区块链100HyperledgerFabric区块链多机部署
  4. Fabric 1.0的多机部署
最后编辑于: May 21, 2019
Archives Tip
QR Code for this page
Tipping QR Code