搭建Hyperledger Fabric

搭建流程

环境搭建

一、自行下载虚拟机软件(这里使用VirtualBox)

二、下载iso光盘CentOS Linux release 7.8.2003 (Core)

http://mirrors.aliyun.com/centos/7/isos/x86_64/CentOS-7-x86_64-Minimal-2003.iso

三、创建虚拟机,桥接网络,内存4G,硬盘80G,挂载光盘,启动虚拟机。

四、配置linux

# 关闭防火墙
systemctl stop firewalld && systemctl disable firewalld
#CentOS关闭selinux
setenforce 0
sed -i "s/^SELINUX=.*/SELINUX=disabled/g" /etc/sysconfig/selinux
sed -i "s/^SELINUX=.*/SELINUX=disabled/g" /etc/selinux/config
sed -i "s/^SELINUX=.*/SELINUX=disabled/g" /etc/sysconfig/selinux
sed -i "s/^SELINUX=.*/SELINUX=disabled/g" /etc/selinux/config

# 修改时区
ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime

# 修改系统语言环境
echo 'LANG="en_US.UTF-8"' >> /etc/profile;source /etc/profile
 
# 设置dns
echo "nameserver 8.8.8.8" > /etc/resolv.conf

# 设置yum源
sudo cp /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.bak
echo '
[base]
name=CentOS-$releasever - Base - mirrors.aliyun.com
failovermethod=priority
baseurl=http://mirrors.aliyun.com/centos/$releasever/os/$basearch/
gpgcheck=1
gpgkey=http://mirrors.aliyun.com/centos/RPM-GPG-KEY-CentOS-7
 
#released updates 
[updates]
name=CentOS-$releasever - Updates - mirrors.aliyun.com
failovermethod=priority
baseurl=http://mirrors.aliyun.com/centos/$releasever/updates/$basearch/
gpgcheck=1
gpgkey=http://mirrors.aliyun.com/centos/RPM-GPG-KEY-CentOS-7
 
#additional packages that may be useful
[extras]
name=CentOS-$releasever - Extras - mirrors.aliyun.com
failovermethod=priority
baseurl=http://mirrors.aliyun.com/centos/$releasever/extras/$basearch/
gpgcheck=1
gpgkey=http://mirrors.aliyun.com/centos/RPM-GPG-KEY-CentOS-7
 
#additional packages that extend functionality of existing packages
[centosplus]
name=CentOS-$releasever - Plus - mirrors.aliyun.com
failovermethod=priority
baseurl=http://mirrors.aliyun.com/centos/$releasever/centosplus/$basearch/
gpgcheck=1
enabled=0
gpgkey=http://mirrors.aliyun.com/centos/RPM-GPG-KEY-CentOS-7
 
#contrib - packages by Centos Users
[contrib]
name=CentOS-$releasever - Contrib - mirrors.aliyun.com
failovermethod=priority
baseurl=http://mirrors.aliyun.com/centos/$releasever/contrib/$basearch/
gpgcheck=1
enabled=0
gpgkey=http://mirrors.aliyun.com/centos/RPM-GPG-KEY-CentOS-7

' > /etc/yum.repos.d/CentOS-Base.repo

# 更新内核与安装包
sudo yum update -y
# 重新缓存
yum clean all && yum makecache

五、安装docker-ce

# 安装docker-ce依赖包
sudo yum install -y yum-utils device-mapper-persistent-data lvm2 bash-completion
# 添加docker-ce yum源地址
sudo yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
# 安装docker-ce
yum -y install docker-ce
# 修改docker配置文件,添加docker镜像加速仓库,存储格式等
mkdir -p /etc/docker
echo '
{
  "max-concurrent-downloads": 3,
  "max-concurrent-uploads": 5,
  "registry-mirrors": ["https://7bezldxe.mirror.aliyuncs.com/"],
  "storage-driver": "overlay2",
  "storage-opts": ["overlay2.override_kernel_check=true"],
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "100m",
    "max-file": "3"
    }
}
' > /etc/docker/daemon.json
# 启动docker
systemctl start docker
# 检查状态及版本
systemctl status docker
docker version
# 设置开机启动
sudo systemctl enable docker

六、安装git

yum -y install git

七、安装docker-compose

# 安装epel源
yum -y install epel-release
如何不可用vim 一下/etc/yum.repos.d/epel.repo改为如下
[epel]
name=Extra Packages for Enterprise Linux 7 - $basearch
baseurl=http://download.fedoraproject.org/pub/epel/7/$basearch
#metalink=https://mirrors.fedoraproject.org/metalink?repo=epel-7&arch=$basearch
failovermethod=priority
enabled=1
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-7

[epel-debuginfo]
name=Extra Packages for Enterprise Linux 7 - $basearch - Debug
#baseurl=http://download.fedoraproject.org/pub/epel/7/$basearch/debug
metalink=https://mirrors.fedoraproject.org/metalink?repo=epel-debug-7&arch=$basearch
failovermethod=priority
enabled=0
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-7
gpgcheck=1

[epel-source]
name=Extra Packages for Enterprise Linux 7 - $basearch - Source
#baseurl=http://download.fedoraproject.org/pub/epel/7/SRPMS
metalink=https://mirrors.fedoraproject.org/metalink?repo=epel-source-7&arch=$basearch
failovermethod=priority
enabled=0
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-EPEL-7
gpgcheck=1
#安装python-pip包
yum -y install python-pip
# 对安装好的pip进行升级
pip install --upgrade pip
# 查看
pip -V
# 安装docker-compose
pip --default-timeout=200 install -U docker-compose
# 查看
docker-compose -version

八、git下载fabric源码,并切换master分支

mkdir -p /opt/gopath/src/github.com/hyperledger
cd /opt/gopath/src/github.com/hyperledger
git clone https://github.com/hyperledger/fabric.git
cd /opt/gopath/src/github.com/hyperledger/fabric
git branch

如git clone出现错误:Peer reports incompatible or unsupported protocol version.
请更新yum update -y nss curl libcurl

九、根据源码脚本拉取镜像、二进制文件等

cd /opt/gopath/src/github.com/hyperledger/fabric/scripts
./bootstrap.sh
# 查看
docker images
------------------------------------------------------------------------------------------------
REPOSITORY                   TAG                 IMAGE ID            CREATED             SIZE
hyperledger/fabric-ca        1.4                 dbbc768aec79        5 weeks ago         158MB
hyperledger/fabric-ca        1.4.9               dbbc768aec79        5 weeks ago         158MB
hyperledger/fabric-ca        latest              dbbc768aec79        5 weeks ago         158MB
hyperledger/fabric-tools     2.2                 e9b802fadb41        5 weeks ago         519MB
hyperledger/fabric-tools     2.2.1               e9b802fadb41        5 weeks ago         519MB
hyperledger/fabric-tools     latest              e9b802fadb41        5 weeks ago         519MB
hyperledger/fabric-peer      2.2                 ece149884124        5 weeks ago         55MB
hyperledger/fabric-peer      2.2.1               ece149884124        5 weeks ago         55MB
hyperledger/fabric-peer      latest              ece149884124        5 weeks ago         55MB
hyperledger/fabric-orderer   2.2                 78a16ddd2cf4        5 weeks ago         38.4MB
hyperledger/fabric-orderer   2.2.1               78a16ddd2cf4        5 weeks ago         38.4MB
hyperledger/fabric-orderer   latest              78a16ddd2cf4        5 weeks ago         38.4MB
hyperledger/fabric-ccenv     2.2                 8e554c280cac        5 weeks ago         586MB
hyperledger/fabric-ccenv     2.2.1               8e554c280cac        5 weeks ago         586MB
hyperledger/fabric-ccenv     latest              8e554c280cac        5 weeks ago         586MB
hyperledger/fabric-baseos    2.2                 0b99d26b26ad        5 weeks ago         6.85MB
hyperledger/fabric-baseos    2.2.1               0b99d26b26ad        5 weeks ago         6.85MB
hyperledger/fabric-baseos    latest              0b99d26b26ad        5 weeks ago         6.85MB
------------------------------------------------------------------------------------------------

十、安装Golang

yum -y install golang
# 自定义环境Go环境变量到linux文件
echo '
export PATH=$PATH:/usr/local/go/bin
export GOPATH=/opt/gopath
# 加载
source /etc/profile
' >> /etc/profile

十一、启动区块链网络

cd fabric-samples/test-network
./network.sh up
# 查看 (可以看到两个组织的peer节点与1个order节点)
docker ps
image.png

成功够可以看到启动了3个容器:2个peer、1个order节点。

十二、创建channel

./network.sh createChannel -c ch1

十三、在channel上创建chaincode,指定七牛云go依赖包仓库进行下载,这里chaincode默认加载的智能合约程序为/opt/gopath/src/github.com/hyperledger/fabric/scripts/fabric-samples下的basic资产程序

go env -w GO111MODULE=on
go env -w GOPROXY=https://goproxy.cn,direct
./network.sh deployCC -c ch1

十四、交互

cd /opt/gopath/src/github.com/hyperledger/fabric/scripts/fabric-samples/test-network
export PATH=${PWD}/../bin:$PATH
export FABRIC_CFG_PATH=$PWD/../config/

# 认证Org1
export CORE_PEER_TLS_ENABLED=true
export CORE_PEER_LOCALMSPID="Org1MSP"
export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org1.example.com/users/[email protected]/msp
export CORE_PEER_ADDRESS=localhost:7051

# 对账本初始化资产
peer chaincode invoke -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C ch1 -n basic --peerAddresses localhost:7051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt --peerAddresses localhost:9051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt -c '{"function":"InitLedger","Args":[]}'


# 查看我们添加的资产 
peer chaincode query -C ch1 -n basic -c '{"Args":["GetAllAssets"]}'
# 显示的资产列表 [{"ID":"asset1","color":"blue","size":5,"owner":"Tomoko","appraisedValue":300},{"ID":"asset2","color":"red","size":5,"owner":"Brad","appraisedValue":400},{"ID":"asset3","color":"green","size":10,"owner":"Jin Soo","appraisedValue":500},{"ID":"asset4","color":"yellow","size":10,"owner":"Max","appraisedValue":600},{"ID":"asset5","color":"black","size":15,"owner":"Adriana","appraisedValue":700},{"ID":"asset6","color":"white","size":15,"owner":"Michel","appraisedValue":800}]


# 转移资产
peer chaincode invoke -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C ch1 -n basic --peerAddresses localhost:7051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt --peerAddresses localhost:9051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt -c '{"function":"TransferAsset","Args":["asset6","Christopher"]}'

# 使用Org2认证,进行验证
export CORE_PEER_TLS_ENABLED=true
export CORE_PEER_LOCALMSPID="Org2MSP"
export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org2.example.com/users/[email protected]/msp
export CORE_PEER_ADDRESS=localhost:9051

# 查看刚才转移的第六个资产
peer chaincode query -C ch1 -n basic -c '{"Args":["ReadAsset","asset6"]}'

# 关闭区块链网络
./network.sh down

十五、添加新节点

cd addOrg3
./addOrg3.sh generate
./addOrg3.sh up -c ch1

# 使用org3认证
export CORE_PEER_TLS_ENABLED=true
export CORE_PEER_LOCALMSPID="Org3MSP"
export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org3.example.com/peers/peer0.org3.example.com/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org3.example.com/users/[email protected]/msp
export CORE_PEER_ADDRESS=localhost:11051

# 安装chaincode到org3Chaincode is installed on peer0.org3 
peer lifecycle chaincode install basic.tar.gz

# 查询安装是否成功
peer lifecycle chaincode queryinstalled

# 让org3上的链码定义在ch1通道上认可 Chaincode definition approved on peer0.org3 on channel 'ch1'
peer lifecycle chaincode approveformyorg -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile /opt/gopath/src/github.com/hyperledger/fabric/scripts/fabric-samples/test-network/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem --channelID ch1 --name basic --version 1.0 --package-id basic_1.0:4ec191e793b27e953ff2ede5a8bcc63152cecb1e4c3f301a26e22692c61967ad --sequence 1

十六、编写智能合约


# 创建智能合约程序目录并进入
mkdir atcc && cd atcc
# goland开启 go module模式并配置goproxy
![image.png](https://upload-images.jianshu.io/upload_images/10280146-81a5a1ff88b8795e.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
# 新建go文件
touch atcc.go
# 编写代码
package main

import (
    "encoding/json"
    "fmt"
    "github.com/hyperledger/fabric-contract-api-go/contractapi"
    "log"
)

func main() {
    assetChaincode, err := contractapi.NewChaincode(&SmartContract{})
    if err != nil {
        log.Panicf("Error creating asset-transfer-basic chaincode: %v", err)
    }

    if err := assetChaincode.Start(); err != nil {
        log.Panicf("Error starting asset-transfer-basic chaincode: %v", err)
    }
}

// SmartContract provides functions for managing an Asset
type SmartContract struct {
    contractapi.Contract
}

// Asset describes basic details of what makes up a simple asset
type Student struct {
    ID   string `json:"ID"`
    Name string `json:"name"`
    Age  int    `json:"age"`
}

func (s *SmartContract) InitLedger(ctx contractapi.TransactionContextInterface) error {
    stus := []Student{
        {ID: "a1", Name: "小明", Age: 16},
        {ID: "a2", Name: "小花", Age: 15},
        {ID: "a3", Name: "小强", Age: 17},
        {ID: "a4", Name: "小刚", Age: 16},
        {ID: "a5", Name: "小草", Age: 14},
        {ID: "a6", Name: "小新", Age: 14},
    }

    for _, stu := range stus {
        assetJSON, err := json.Marshal(stu)
        if err != nil {
            return err
        }

        err = ctx.GetStub().PutState(stu.ID, assetJSON)
        if err != nil {
            return fmt.Errorf("failed to put to world state. %v", err)
        }
    }

    return nil
}

// CreateAsset issues a new asset to the world state with given details.
func (s *SmartContract) CreateAsset(ctx contractapi.TransactionContextInterface, id string, name string, age int) error {
    exists, err := s.AssetExists(ctx, id)
    if err != nil {
        return err
    }
    if exists {
        return fmt.Errorf("the asset %s already exists", id)
    }

    stu := Student{
        ID:   id,
        Name: name,
        Age:  age,
    }
    assetJSON, err := json.Marshal(stu)
    if err != nil {
        return err
    }

    return ctx.GetStub().PutState(id, assetJSON)
}

// AssetExists returns true when asset with given ID exists in world state
func (s *SmartContract) AssetExists(ctx contractapi.TransactionContextInterface, id string) (bool, error) {
    assetJSON, err := ctx.GetStub().GetState(id)
    if err != nil {
        return false, fmt.Errorf("failed to read from world state: %v", err)
    }

    return assetJSON != nil, nil
}

// ReadAsset returns the asset stored in the world state with given id.
func (s *SmartContract) ReadAsset(ctx contractapi.TransactionContextInterface, id string) (*Student, error) {
    assetJSON, err := ctx.GetStub().GetState(id)
    if err != nil {
        return nil, fmt.Errorf("failed to read from world state: %v", err)
    }
    if assetJSON == nil {
        return nil, fmt.Errorf("the asset %s does not exist", id)
    }

    var stu Student
    err = json.Unmarshal(assetJSON, &stu)
    if err != nil {
        return nil, err
    }

    return &stu, nil
}

func (s *SmartContract) UpdateAsset(ctx contractapi.TransactionContextInterface, id string, name string, age int) error {
    exists, err := s.AssetExists(ctx, id)
    if err != nil {
        return err
    }
    if !exists {
        return fmt.Errorf("the asset %s does not exist", id)
    }

    // overwriting original asset with new asset
    stu := Student{
        ID:   id,
        Name: name,
        Age:  age,
    }
    assetJSON, err := json.Marshal(stu)
    if err != nil {
        return err
    }

    return ctx.GetStub().PutState(id, assetJSON)
}

// DeleteAsset deletes an given asset from the world state.
func (s *SmartContract) DeleteAsset(ctx contractapi.TransactionContextInterface, id string) error {
    exists, err := s.AssetExists(ctx, id)
    if err != nil {
        return err
    }
    if !exists {
        return fmt.Errorf("the asset %s does not exist", id)
    }

    return ctx.GetStub().DelState(id)
}

上面程序主要调用"github.com/hyperledger/fabric-contract-api-go/contractapi"接口的增删改查方法来操作自己的资产。

十七、部署智能合约

go env -w GO111MODULE=on
go env -w GOPROXY=https://goproxy.cn,direct
# 整理go依赖包
go mod tidy
# 使用vendor管理,将依赖包下载到module目录
go mod vendor

登录fabric network机器上,将写好的合约程序上传到/opt/gopath/src/github.com/hyperledger/fabric/scripts/fabric-samples/personal-demo/位置,mkdir -p /opt/gopath/src/github.com/hyperledger/fabric/scripts/fabric-samples/personal-demo

# 初始集群
cd /opt/gopath/src/github.com/hyperledger/fabric/scripts/fabric-samples/test-network
./network down
./network up
# 创建通道ch3
./network createChannel -c ch3
# 部署智能合约
./network.sh deployCC -ccp ../personal-demo/atcc -c ch3
# 调用智能合约api
cd /opt/gopath/src/github.com/hyperledger/fabric/scripts/fabric-samples/test-network
export PATH=${PWD}/../bin:$PATH
export FABRIC_CFG_PATH=$PWD/../config/

# 认证Org1
export CORE_PEER_TLS_ENABLED=true
export CORE_PEER_LOCALMSPID="Org1MSP"
export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org1.example.com/users/[email protected]/msp
export CORE_PEER_ADDRESS=localhost:7051

# 使用智能合约初始化方法
peer chaincode invoke -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C ch3 -n basic --peerAddresses localhost:7051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt --peerAddresses localhost:9051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt -c '{"function":"InitLedger","Args":[]}'

# 查看我们添加的资产 
peer chaincode query -C ch3 -n atcc  -c '{"function":"ReadAsset","Args":["a1"]}'
#显示结果{"ID":"a1","name":"小明","age":16}

十八、编写运行App调用智能合约

这里继续使用golang编写,调用智能合约相关sdk包
"github.com/hyperledger/fabric-sdk-go/pkg/core/config"
"github.com/hyperledger/fabric-sdk-go/pkg/gateway"
大体流程:
1.系统环境变量设置是否为本地app运行:true
2.创建钱包,钱包中为身份认证等信息,这里使用[email protected]的身份
3.通过gateway连接智能合约,传入wallet认证信息、通道名称、合约名称
4.获取合约对象后,调用合约方法
5.启动app

package main

import (
    "fmt"
    "io/ioutil"
    "log"
    "os"
    "path/filepath"

    "github.com/hyperledger/fabric-sdk-go/pkg/core/config"
    "github.com/hyperledger/fabric-sdk-go/pkg/gateway"
)

func main() {
    log.Println("============ application-golang starts ============")

    log.Println("系统环境变量设置是否为本地app运行:true ")

    err := os.Setenv("DISCOVERY_AS_LOCALHOST", "true")
    if err != nil {
        log.Fatalf("Error setting DISCOVERY_AS_LOCALHOST environemnt variable: %v", err)
    }

    log.Println("创建钱包,钱包中为身份认证等信息,这里使用[email protected]的身份.")

    wallet, err := gateway.NewFileSystemWallet("wallet")
    if err != nil {
        log.Fatalf("Failed to create wallet: %v", err)
    }

    if !wallet.Exists("appUser") {
        err = populateWallet(wallet)
        if err != nil {
            log.Fatalf("Failed to populate wallet contents: %v", err)
        }
    }


    log.Println("通过gateway连接智能合约,传入通道名称、合约名称.")

    ccpPath := filepath.Join(
        "..",
        "..",
        "test-network",
        "organizations",
        "peerOrganizations",
        "org1.example.com",
        "connection-org1.yaml",
    )

    gw, err := gateway.Connect(
        gateway.WithConfig(config.FromFile(filepath.Clean(ccpPath))),
        gateway.WithIdentity(wallet, "appUser"),
    )
    if err != nil {
        log.Fatalf("Failed to connect to gateway: %v", err)
    }
    defer gw.Close()

    network, err := gw.GetNetwork("ch3")
    if err != nil {
        log.Fatalf("Failed to get network: %v", err)
    }

    contract := network.GetContract("basic")

    log.Println("--> Submit Transaction: 调用智能合约InitLedger方法初始化所有同学的数据.")
    result, err := contract.SubmitTransaction("InitLedger")
    if err != nil {
        log.Fatalf("Failed to Submit transaction: %v", err)
    }
    log.Println(string(result))


    log.Println("--> Submit Transaction: 调用智能合约CreateAsset方法创建一个同学的信息, id=a8,name=小朵,age=13.")
    result, err = contract.SubmitTransaction("CreateAsset", "a8", "小朵", "13")
    if err != nil {
        log.Fatalf("Failed to Submit transaction: %v", err)
    }
    log.Println(string(result))

    log.Println("--> Evaluate Transaction: 调用智能合约ReadAsset方法读取刚刚创建的同学的信息.")
    result, err = contract.EvaluateTransaction("ReadAsset", "a8")
    if err != nil {
        log.Fatalf("Failed to evaluate transaction: %v\n", err)
    }
    log.Println(string(result))

    log.Println("--> Evaluate Transaction: 调用智能合约AssetExists方法判断刚刚创建的同学信息是否存在.")
    result, err = contract.EvaluateTransaction("AssetExists", "a8")
    if err != nil {
        log.Fatalf("Failed to evaluate transaction: %v\n", err)
    }
    log.Println(string(result))

    log.Println("============ application-golang ends ============")
}

func populateWallet(wallet *gateway.Wallet) error {
    log.Println("============ Populating wallet ============")
    credPath := filepath.Join(
        "..",
        "..",
        "test-network",
        "organizations",
        "peerOrganizations",
        "org1.example.com",
        "users",
        "[email protected]",
        "msp",
    )

    certPath := filepath.Join(credPath, "signcerts", "[email protected]")
    // read the certificate pem
    cert, err := ioutil.ReadFile(filepath.Clean(certPath))
    if err != nil {
        return err
    }

    keyDir := filepath.Join(credPath, "keystore")
    // there's a single file in this dir containing the private key
    files, err := ioutil.ReadDir(keyDir)
    if err != nil {
        return err
    }
    if len(files) != 1 {
        return fmt.Errorf("keystore folder should have contain one file")
    }
    keyPath := filepath.Join(keyDir, files[0].Name())
    key, err := ioutil.ReadFile(filepath.Clean(keyPath))
    if err != nil {
        return err
    }

    identity := gateway.NewX509Identity("Org1MSP", string(cert), string(key))

    return wallet.Put("appUser", identity)
}

go run xxx.go 运行该app

十九、test-network目录说明

├── addOrg3                             添加新组织相关文件及脚本文件夹
│   ├── addOrg3.sh
│   ├── ccp-generate.sh
│   ├── ccp-template.json
│   ├── ccp-template.yaml
│   ├── configtx.yaml
│   ├── docker
│   ├── fabric-ca
│   ├── org3-crypto.yaml
│   └── README.md
├── channel-artifacts                    通道文件
│   ├── ch5.block
│   ├── ch5.tx
│   ├── Org1MSPanchors.tx
│   └── Org2MSPanchors.tx
├── configtx
│   └── configtx.yaml             用于生成系统创世区块的配置文件  
├── docker                                                    用于启动docker容器的docker-compose配置文件
│   ├── docker-compose-ca.yaml          
│   ├── docker-compose-couch.yaml
│   └── docker-compose-test-net.yaml
├── log.txt
├── network.sh                     入口脚本
├── organizations
│   ├── ccp-generate.sh
│   ├── ccp-template.json
│   ├── ccp-template.yaml
│   ├── cryptogen                             使用cryptogen tool为组织生成证书、秘钥
│   ├── fabric-ca                               使用ca服务器来为每个身份 生成证书、秘钥时,其中包含相关的配置文件
│   │   ├── ordererOrg
│   │   ├── org1
│   │   ├── org2
│   │   └── registerEnroll.sh             生成证书、秘钥的脚本
│   ├── ordererOrganizations           order组织的证书文件
│   └── peerOrganizations               peer组织的证书文件
├── README.md
├── scripts                          子脚本文件夹
│   ├── createChannel.sh          createChannel.sh基于configtx/configtx.yaml使用指定的通道名称创建通道,向通道中加入peer0.org1.example.com和peer0.org2.example.com,并将它们更新为锚节点
│   ├── deployCC.sh                  deployCC.sh在peer0.org1.example.com和peer0.org2.example.com上安装fabric的链码,并在通道中定义chaincode,最后调用chaincode显示结果
│   ├── envVar.sh                       系统环境变量
│   └── org3-scripts                    添加新组织相关脚本
├── scriptUtils.sh                        通用脚本-help等
└── system-genesis-block       系统创世区块文件夹
    └── genesis.block                生成的系统创世区块

附录

安装go环境

1.下载go sdk
非科学上网访问:https://studygolang.com/dl

image.png

安装后请确认环境变量可用
go version
go env
2.下载Goland
访问:https://www.jetbrains.com/zh-cn/go/

cryptogen介绍

1.MSP是什么


  MSP一个提供虚拟成员操作的管理框架组件

  每个节点都有一个MSP账号

  每个用户也都有MSP账号  

  MSP下面有一个管理员账号和证书

  验证身份的证书都在MSP下面。

2.cryptogen使用方法

cryptogen --help  //查看使用方法

 

cryptogen generate --help   //查看generate后的使用方法

//使用cryptogen generate需要指定模板文件,不然就是默认模板

cryptogen generate --config == 某文件

会生成peer节点和orderer节点文件

 

根据yaml的模块修改 cryptogen showtemplate    //查看模板

使用重定向命令将模板放在别的地方通过修改成自己的

cryptogen showtemplate > a.yaml  //一般起名叫crypto-config.yaml

3.模板说明

OrdererOrgs:    //排序节点的组织信息,这里不能改
# ---------------------------------------------------------------------------
# Orderer
# ---------------------------------------------------------------------------
- Name: Orderer  //排序节点组织的名字,可以修改可以不修改
Domain: example.com    //根域名,排序节点组织的根域名,测试的时候随便取

# ---------------------------------------------------------------------------
# "Specs" - See PeerOrgs below for complete description
# ---------------------------------------------------------------------------
Specs:      //User去指定
  - Hostname: orderer    //生成一个子域名,去访问当前唯一排序节点。orderer对应的访问域名应该是:orderer.example.com

  Hostname有几个就有几个排序节点,通过队友的域名

    排序节点名字.根域名去访问

 

第二部分:

PeerOrgs:    Org1和Org2是指定的默认peer节点的组织可以无限添加
# ---------------------------------------------------------------------------
# Org1
# ---------------------------------------------------------------------------
- Name: Org1    //名字,自己指定
Domain: org1.example.com    //域名同样跟orderer的域名一样
EnableNodeOUs: false      //是否支持nodejs来编写链码

Template:    //模板
  Count: 1  //生成的peer节点数,访问的域名peer0.org1.example.com //0对应1,1对2  

Users:
  Count: 1    //操作节点的普通用户的个数,还会默认生成一个管理员用户

    [email protected]

使用template和specs的区别:

使用specs二级域名可以自己指定
使用template二级域名就是默认的peer0这种类似
可以单独也可以混合使用

新增组织

1.新增组织证书配置

echo '
PeerOrgs:
  # ---------------------------------------------------------------------------
  # Org4
  # ---------------------------------------------------------------------------
  - Name: Org4
    Domain: org4.example.com
    EnableNodeOUs: true
    Template:
      Count: 1
    Users:
      Count: 1
' > crypto-config.yaml
      
cryptogen extend --config=./crypto-config.yaml
  1. 新增组织定义到区块链
echo '
Organizations:
    - &Org4
        Name: Org4MSP
        ID: Org4MSP
        MSPDir: crypto-config/peerOrganizations/org4.example.com/msp
        Policies:
            Readers:
                Type: Signature
                Rule: "OR('Org4MSP.admin', 'Org4MSP.peer', 'Org4MSP.client')"
            Writers:
                Type: Signature
                Rule: "OR('Org4MSP.admin', 'Org4MSP.client')"
            Admins:
                Type: Signature
                Rule: "OR('Org4MSP.admin')"
            Endorsement:
                Type: Signature
                Rule: "OR('Org4MSP.peer')"
        AnchorPeers:
            - Host: peer0.org4.example.com
              Port: 7051
' > configtx.yaml

configtxgen -printOrg Org4MSP > ./channel-artifacts/org.json

3.启动新组织容器

docker run -tid \
    --name=peer0.org4.example.com \
    --restart=always \
    -p 7051:7051 \
    -p 7052:7052 \
    -p 7053:7053 \
    -w /opt/gopath/src/github.com/hyperledger/fabric/peer \
    -e CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock \
    -e CORE_PEER_ID=peer0.org4.example.com \
    -e CORE_PEER_ADDRESS=peer0.org4.example.com:7051 \
    -e CORE_PEER_LISTENADDRESS=0.0.0.0:7051 \
    -e CORE_PEER_CHAINCODEADDRESS=peer0.org4.example.com:7052 \
    -e CORE_PEER_CHAINCODELISTENADDRESS=0.0.0.0:7052 \
    -e CORE_PEER_GOSSIP_BOOTSTRAP=peer0.org4.example.com:7051 \
    -e CORE_PEER_GOSSIP_EXTERNALENDPOINT=peer0.org4.example.com:7051 \
    -e CORE_PEER_LOCALMSPID=Org4MSP \
    -e FABRIC_LOGGING_SPEC=INFO \
    -e CORE_PEER_TLS_ENABLED=true \
    -e CORE_PEER_GOSSIP_USELEADERELECTION=true \
    -e CORE_PEER_GOSSIP_ORGLEADER=false \
    -e CORE_PEER_PROFILE_ENABLED=true \
    -e CORE_PEER_TLS_CERT_FILE=/etc/hyperledger/fabric/tls/server.crt \
    -e CORE_PEER_TLS_KEY_FILE=/etc/hyperledger/fabric/tls/server.key \
    -e CORE_PEER_TLS_ROOTCERT_FILE=/etc/hyperledger/fabric/tls/ca.crt \
    -e CORE_CHAINCODE_EXECUTETIMEOUT=300s \
    -v /var/run/:/host/var/run/ \
    -v /opt/multiple-deployment/crypto-config/peerOrganizations/org4.example.com/peers/peer0.org4.example.com/msp:/etc/hyperledger/fabric/msp \
    -v /opt/multiple-deployment/crypto-config/peerOrganizations/org4.example.com/peers/peer0.org4.example.com/tls:/etc/hyperledger/fabric/tls \
    --add-host=orderer0.example.com:10.160.0.122 \
    --add-host=orderer1.example.com:10.160.0.115 \
    --add-host=orderer2.example.com:10.160.0.200 \
    hyperledger/fabric-peer:latest sh -c 'peer node start'

docker run -tid \
    --name=peer0.org4.example.com.cli \
    --restart=always \
    -w /opt/gopath/src/github.com/hyperledger/fabric/peer \
    -e GOPATH=/opt/gopath \
    -e CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock \
    -e FABRIC_LOGGING_SPEC=INFO \
    -e CORE_PEER_ID=peer0.org4.example.com \
    -e CORE_PEER_ADDRESS=peer0.org4.example.com:7051 \
    -e CORE_PEER_LOCALMSPID=Org4MSP \
    -e CORE_PEER_TLS_ENABLED=true \
    -e CORE_PEER_TLS_CERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org4.example.com/peers/peer0.org4.example.com/tls/server.crt \
    -e CORE_PEER_TLS_KEY_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org4.example.com/peers/peer0.org4.example.com/tls/server.key \
    -e CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org4.example.com/peers/peer0.org4.example.com/tls/ca.crt \
    -e CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org4.example.com/users/[email protected]/msp \
    -v /var/run/:/host/var/run/ \
    -v /opt/multiple-deployment/chaincode/go/:/opt/gopath/src/github.com/hyperledger/multiple-deployment/chaincode/go \
    -v /opt/multiple-deployment/crypto-config:/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ \
    -v /opt/multiple-deployment/channel-artifacts:/opt/gopath/src/github.com/hyperledger/fabric/peer/channel-artifacts \
    --add-host=orderer0.example.com:10.160.0.122 \
    --add-host=orderer1.example.com:10.160.0.115 \
    --add-host=orderer2.example.com:10.160.0.200 \
    --add-host=peer0.org1.example.com:10.160.0.122 \
    --add-host=peer1.org1.example.com:10.160.0.122 \
    --add-host=peer0.org2.example.com:10.160.0.115 \
    --add-host=peer1.org2.example.com:10.160.0.115 \
    --add-host=peer0.org3.example.com:10.160.0.200 \
    --add-host=peer1.org3.example.com:10.160.0.200 \
    --add-host=peer0.org4.example.com:10.160.0.162 \
    --add-host=peer1.org4.example.com:10.160.0.200 \
    hyperledger/fabric-tools:latest /bin/bash
    
  1. 更新通道配置
channelName=mychannel
ordererAddr=orderer0.example.com:7050
ordererCa=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer0.example.com/msp/tlscacerts/tlsca.example.com-cert.pem

4.1 获取配置 获取最新块
在peer0.org1.cli容器中

docker exec -ti peer0.org1.example.com.cli bash
peer channel fetch config config_block.pb -o orderer0.example.com:7050 -c mychannel --tls --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer0.example.com/msp/tlscacerts/tlsca.example.com-cert.pem

4.2 修改配置
将pb文件转json

configtxlator proto_decode --input config_block.pb --type common.Block | jq .data.data[0].payload.data.config > config.json

先把之前生成的org.json放进去Org3cli容器

将org.json添加到config.json

jq -s '.[0] * {"channel_group":{"groups":{"Application":{"groups": {"Org4MSP":.[1]}}}}}' config.json ./channel-artifacts/org.json > modified_config.json

将config.json 跟modified_config.json 转pb编码

configtxlator proto_encode --input config.json --type common.Config --output config.pb
configtxlator proto_encode --input modified_config.json --type common.Config --output modified_config.pb

计算两个pb差异

configtxlator compute_update --channel_id mychannel --original config.pb --updated modified_config.pb --output org_update.pb

将更新的pb解析为json

configtxlator proto_decode --input org_update.pb --type common.ConfigUpdate | jq . > org_update.json

现在我们有一个解码后的更新文件org_update.json,我们需要将其包装在信封消息中。此步骤将使我们返回之前删除的header字段。我们将这个文件命名为org_update_in_envelope.json:

echo '{"payload":{"header":{"channel_header":{"channel_id":"'mychannel'", "type":2}},"data":{"config_update":'$(cat org_update.json)'}}}' | jq . > org_update_in_envelope.json

转pb编码

configtxlator proto_encode --input org_update_in_envelope.json --type common.Envelope --output org_update_in_envelope.pb

4.3 签名并提交更新配置

peer channel signconfigtx -f org_update_in_envelope.pb

切换环境为org2执行更新配置,因为update也会为当前组织签名,所以不需要再org2签名

docker cp peer0.org1.example.com.cli:/opt/gopath/src/github.com/hyperledger/fabric/peer/org_update_in_envelope.pb ./
scp org_update_in_envelope.pb [email protected]:/opt/multiple-deployment/channel-artifacts
docker exec -ti peer0.org2.example.com.cli bash
peer channel update -f org_update_in_envelope.pb -c mychannel -o orderer0.example.com:7050 --tls --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer0.example.com/msp/tlscacerts/tlsca.example.com-cert.pem
  1. 新组织加入通道
docker exec -ti peer0.org4.example.com.cli bash
peer channel fetch 0 mychannel.block -o orderer0.example.com:7050 -c mychannel --tls --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer0.example.com/msp/tlscacerts/tlsca.example.com-cert.pem
peer channel join -b mychannel.block
peer channel list 

你可能感兴趣的:(搭建Hyperledger Fabric)