天天看點

Hyperledger Fabric 2.0 外部鍊碼的開發/建構/部署/通路

在Hyperledger Fabric 2.0中引入的一個新特性,就是可以使用外部的鍊碼啟動器,這種外部啟動鍊碼的方式非常适合使用kubenetes或dowcker swarm來統一管理節點容器和鍊碼容器。在這片文章中,我們将學習如何使用外部鍊碼啟動器在K8s叢集中部署鍊碼。

1、Fabric外部鍊碼實驗的前提條件

Hyperledger Fabric區塊鍊開發教程: Fabric Node.js開發詳解 |
Fabric Java開發詳解 Fabric Golang開發詳解

下面是我們實驗的一些前提條件

  • 一個kubenetes叢集,你可以使用minikube或一個單節點的kubeadmin。在 本文中我們使用kubeadmin
  • hyperledger fabric 2.0.1 docker鏡像
  • hyperledger fabric 2.0.1 預編譯程式。我們需要其中的工具來建立 密碼學資料和通道交易配置檔案。可以從 這裡 下載下傳。
  • 下載下傳本文的代碼

2、安裝預編譯程式

使用以下指令安裝預編譯程式:

wget https://github.com/hyperledger/fabric/releases/download/v2.0.1/hyperledger-fabric-linux-amd64-2.0.1.tar.gz

tar -xzf hyperledger-fabric-linux-amd64-2.0.1.tar.gz# Move to the bin path

mv bin/* /bin# Check that you have successfully installed the tools by executing

configtxgen --version# Should print the following output:
# configtxgen:
#  Version: 2.0.1
#  Commit SHA: 1cfa5da98
#  Go version: go1.13.4
#  OS/Arch: linux/amd64           

3、啟動Hyperledger Fabric網絡

一旦我們啟動了kubernetes叢集,就可以啟動Fabric網絡了。但是我們先要生成基本的密碼學資料以及網絡創世區塊。在configtx.yaml中有一些修改以适應fabric 2.0中新的

lifecycle chaincode

指令,這些修改對于使用外部鍊碼啟動器是必須的。

Fabric區塊鍊網絡中包含3個RAFT排序服務節點,2個機構org1和org2各含1個peer節點以及一個CA。這些資訊已經編碼在configtx.yaml和crypto-config.yaml檔案中,不需要修改。

有了配置檔案,現在我們可以生成fabric區塊鍊網絡的密碼學資料和創世區塊。我們使用fabricOps.sh腳本:

$ ./fabricOps.sh start           

上面的指令将生成所有的密碼學資料,例如節點和CA的證書等,以及通道的創世區塊。

現在需要為Hyperledger Fabric工作負載建立一個新的k8s命名空間,指令如下:

$ kubectl create ns hyperledger           

然後建立一個檔案夾來儲存Hyperledger Fabric工作負載的持久化資料:

$ mkdir /home/storage           

好了,現在可以開始部署Fabric排序節點了:

$ kubectl create -f orderer-service/           

使用下面指令檢查Fabric網絡是否啟動正常:

$ kubectl get pods -n hyperledger

### Should print a similar output
NAME                        READY   STATUS    RESTARTS   AGE
orderer0-58666b6bd7-pflf7    1/1     Running   0          5m47s
orderer1-c4fd65c7d-c27ll    1/1     Running   0          5m47s
orderer2-557cb7865-wlcmh    1/1     Running   0          5m47s           

接下來建立org1的工作負載,這主要包含部署機構的CA和peer節點:

$ kubectl create -f org1/           

同樣用下面指令檢查Fabric網絡節點是否啟動:

$ kubectl get pods -n hyperledger

### Should print a similar output
NAME                          READY   STATUS    RESTARTS   AGE
ca-org1-84945b8c7b-9px4s      1/1     Running   0          19m
cli-org1-bc9f895f6-zmmdc      1/1     Running   0          2m56s
orderer0-58666b6bd7-pflf7      1/1     Running   0          79m
orderer1-c4fd65c7d-c27ll      1/1     Running   0          79m
orderer2-557cb7865-wlcmh      1/1     Running   0          79m
peer0-org1-798b974467-vv4zz   1/1     Running   0          19m           

重複上面的步驟來加載org2的工作負載:

$ kubectl create -f org2/           

檢查Fabric網絡情況:

$ kubectl get pods -n hyperledger

### Should print a similar output
NAME                          READY   STATUS    RESTARTS   AGE
ca-org1-84945b8c7b-9px4s      1/1     Running   0          71m
ca-org2-7454f69c48-q8lft      1/1     Running   0          2m20s
cli-org1-bc9f895f6-zmmdc      1/1     Running   0          55m
cli-org2-7779cc8788-8q4ns     1/1     Running   0          2m20s
orderer0-58666b6bd7-pflf7      1/1     Running   0          131m
orderer1-c4fd65c7d-c27ll      1/1     Running   0          131m
orderer2-557cb7865-wlcmh      1/1     Running   0          131m
peer0-org1-798b974467-vv4zz   1/1     Running   0          71m
peer0-org2-5849c55fcd-mbn5h   1/1     Running   0          2m19s           

3、設定Fabric網絡的通道

一旦部署完Fabric網絡的工作負載,我們可以開始建立通道并将peer節點加入通道。進入org1的cli:

$ kubectl exec -it cli_org1_pod_name sh -n hyperledger           

在這個pod内執行如下指令:

$ peer channel create -o orderer0:7050 -c mychannel -f ./scripts/channel-artifacts/channel.tx --tls true --cafile $ORDERER_CA

### Should print a similar output
2020-03-06 11:54:57.582 UTC [channelCmd] InitCmdFactory -> INFO 001 Endorser and orderer connections initialized
2020-03-06 11:54:58.903 UTC [cli.common] readBlock -> INFO 002 Received block: 0           

現在mychannel通道已經建立好了,接下來将org1的peer節點加入通道:

$ peer channel join -b mychannel.block

### Should print a similar output
2020-03-06 12:01:41.608 UTC [channelCmd] InitCmdFactory -> INFO 001 Endorser and orderer connections initialized
2020-03-06 12:01:41.688 UTC [channelCmd] executeJoin -> INFO 002 Successfully submitted proposal to join channel           

同樣的操作将org2的peer節點加入通道。不過由于org1已經建立了通道,是以我們需要從排序服務提取通道創世塊。首先進入pod:

$ kubectl exec -it cli_org2_pod_name sh -n hyperledger           

然後在pod内執行如下操作:

$ peer channel fetch 0 mychannel.block -c mychannel -o orderer0:7050 --tls --cafile $ORDERER_CA

### Should print a similar output
2020-03-06 12:18:14.880 UTC [channelCmd] InitCmdFactory -> INFO 001 Endorser and orderer connections initialized
2020-03-06 12:18:14.895 UTC [cli.common] readBlock -> INFO 002 Received block: 0           

然後加入通道:

$ peer channel join -b mychannel.block

### Should print a similar output
2020-03-06 12:20:41.475 UTC [channelCmd] InitCmdFactory -> INFO 001 Endorser and orderer connections initialized
2020-03-06 12:20:41.561 UTC [channelCmd] executeJoin -> INFO 002 Successfully submitted proposal to join channel           

用下面的指令檢查目前節點是否已經加入了通道:

$ peer channel list

### Should print a similar output
2020-03-06 12:22:41.102 UTC [channelCmd] InitCmdFactory -> INFO 001 Endorser and orderer connections initialized
Channels peers has joined: 
mychannel           

4、在Fabric節點安裝外部鍊碼

現在開始我們進入真正有趣的環節。我們将部署marbles鍊碼作為外部鍊碼。你可以在Fabric-samples

中找到原始的鍊碼,但是為了将其作為外部鍊碼部署,我們需要在imports和init函數中進行一些修改,

以将其聲明為外部鍊碼伺服器。

新版本的Hyperledger Fabric同樣包含了新的鍊碼處理流程來支援外部方式安裝和啟動鍊碼。為了使用外部鍊碼特性,我們也需要使用這一新的流程。

第一件要做的事情就是将peer節點配置為可以處理外部鍊碼。外部鍊碼建構器就是基于buildpack

實作,是以我們建立3個腳本:detect、build和release。這三個腳本必須在peer容器内定義。你可以

在buildpack/bin目錄下找到這些腳本。

鍊碼建構器定義在org1目錄下的builders-config.yaml中,其中的自定義建構器配置:

# List of directories to treat as external builders and launchers for
  # chaincode. The external builder detection processing will iterate over the
  # builders in the order specified below.
  externalBuilders:
    - name: external-builder
      path: /builders/external
      environmentWhitelist:
         - GOPROXY           

kubernetes使用環境變量來配置peer節點,這些環境變量将覆寫core.yaml中的預設值。

Fabric 2.0采用了與之前版本不同的方式來打包和安裝鍊碼。由于我們要使用外部鍊碼特性,是以鍊碼代碼不需要在peer的pod内進行編譯和安裝,而是在另一個pod中進行。在peer程序中唯一需要的就是用來連接配接外部鍊碼程序的資訊。

為此,我們需要打包鍊碼的一些準備。需要一個connection.json檔案,其中包含連接配接外部鍊碼伺服器的資訊,例如位址、TLS證書、連接配接逾時配置等。

{
    "address": "chaincode-marbles-org1.hyperledger:7052",
    "dial_timeout": "10s",
    "tls_required": false,
    "client_auth_required": false,
    "client_key": "-----BEGIN EC PRIVATE KEY----- ... -----END EC PRIVATE KEY-----",
    "client_cert": "-----BEGIN CERTIFICATE----- ... -----END CERTIFICATE-----",
    "root_cert": "-----BEGIN CERTIFICATE---- ... -----END CERTIFICATE-----"
}           

這個檔案需要打包進一個tar檔案,code.tar.gz,使用如下指令進行壓縮打包:

$ cd chaincode/packaging
$ tar cfz code.tar.gz connection.json           

一旦有了code.tar.gz檔案,我們需要将其與另一個檔案metadata.json一起重新打包。在metadata.json中包含了鍊碼類型、路徑、标簽等資訊:

{"path":"","type":"external","label":"marbles"}           

使用下面的指令打包:

$ tar cfz marbles-org1.tgz code.tar.gz metadata.json           

一旦有了上面的打封包件,我們就可以使用新的

lifecycle chaincode install

指令來安裝鍊碼了:

$ peer lifecycle chaincode install marbles-org1.tgz

### Should print a similar output
2020-03-07 14:33:18.120 UTC [cli.lifecycle.chaincode] submitInstallProposal -> INFO 001 Installed remotely: response:<status:200 payload:"\nGdmarbles:e001937433673b11673d660d142c722fc372905db87f88d2448eee42c9c63064\022\006degree" > 
2020-03-07 14:33:18.126 UTC [cli.lifecycle.chaincode] submitInstallProposal -> INFO 002 Chaincode code package identifier: marbles:e001937433673b11673d660d142c722fc372905db87f88d2448eee42c9c63064           

記下來上面的鍊碼包辨別符,我們接下來會用到,不過你也可以随時用下面的指令查詢鍊碼包的辨別符:

$ peer lifecycle chaincode queryinstalled

### Should print a similar output
Installed chaincodes on peer:
Package ID: marbles:030eec59c7d74fbb4e9fd57bbd50bb904a715ffb9de8fea85b6a6d4b8ca9ea12, Label: marbles           

現在我們為org2重複上面的步驟,但是由于我們希望用另一個pod為org2的peer節點提供鍊碼服務,

是以我們需要修改connection.json中的位址配置:

"address": "chaincode-marbles-org2.hyperledger:7052",           

然後重複之前的步驟,在org2的cli pod中執行如下指令:

$ rm -f code.tar.gz
$ tar cfz code.tar.gz connection.json
$ tar cfz marbles-org2.tgz code.tar.gz metadata.json
$ peer lifecycle chaincode install marbles-org2.tgz

### Should print a similar output
2020-03-07 15:10:15.093 UTC [cli.lifecycle.chaincode] submitInstallProposal -> INFO 001 Installed remotely: response:<status:200 payload:"\nGmarbles:c422c797444e4ee25a92a8eaf97765288a8d68f9c29cedf1e0cd82e4aa2c8a5b\022\006degree" > 
2020-03-07 15:10:15.093 UTC [cli.lifecycle.chaincode] submitInstallProposal -> INFO 002 Chaincode code package identifier: marbles:c422c797444e4ee25a92a8eaf97765288a8d68f9c29cedf1e0cd82e4aa2c8a5b           

同樣記錄鍊碼包的辨別符,它應該與之前org1的不同。

當我們安裝鍊碼時在peer内部發生了什麼?如果定義了外部建構器或啟動器,那麼就不會執行内置的鍊碼建構過程。由于我們已經定義了外部建構器,那麼将按下面的順序執行外部建構腳本:

detect

腳本檢測要安裝的鍊碼是否在metadata.json中配置為external類型。如果腳本失敗,那麼peer将認為這個外部建構器不需要建構鍊碼并嘗試其他外部建構器,直到最終沒有可用的外部建構器時,使用内置的docker建構流程。

#!/bin/sh

# The bin/detect script is responsible for determining whether or not a buildpack 
# should be used to build a chaincode package and launch it. 
# 
# The peer invokes detect with two arguments:
# bin/detect CHAINCODE_SOURCE_DIR CHAINCODE_METADATA_DIR
#
# When detect is invoked, CHAINCODE_SOURCE_DIR contains the chaincode source and 
# CHAINCODE_METADATA_DIR contains the metadata.json file from the chaincode package installed to the peer. 
# The CHAINCODE_SOURCE_DIR and CHAINCODE_METADATA_DIR should be treated as read only inputs. 
# If the buildpack should be applied to the chaincode source package, detect must return an exit code of 0; 
# any other exit code will indicate that the buildpack should not be applied.

CHAINCODE_METADATA_DIR="$2"

set -euo pipefail

# use jq to extract the chaincode type from metadata.json and exit with
# success if the chaincode type is golang
if [ "$(cat "$CHAINCODE_METADATA_DIR/metadata.json" | sed -e 's/[{}]/''/g' | awk -F"[,:}]" '{for(i=1;i<=NF;i++){if($i~/'type'\042/){print $(i+1)}}}' | tr -d '"')" = "external" ]; then
    exit 0
fi

exit 1           

如果

detect

腳本成功,那麼就調用

build

腳本。如果在peer内部建構鍊碼,那麼這個腳本應當生成二進制程式。但是由于我們希望作為外部服務,那麼隻需要簡單的拷貝connection.json檔案到build的輸出目錄就可以了。

#!/bin/sh

# The bin/build script is responsible for building, compiling, or transforming the contents 
# of a chaincode package into artifacts that can be used by release and run.
#
# The peer invokes build with three arguments:
# bin/build CHAINCODE_SOURCE_DIR CHAINCODE_METADATA_DIR BUILD_OUTPUT_DIR
#
# When build is invoked, CHAINCODE_SOURCE_DIR contains the chaincode source and 
# CHAINCODE_METADATA_DIR contains the metadata.json file from the chaincode package installed to the peer.
# BUILD_OUTPUT_DIR is the directory where build must place artifacts needed by release and run. 
# The build script should treat the input directories CHAINCODE_SOURCE_DIR and 
# CHAINCODE_METADATA_DIR as read only, but the BUILD_OUTPUT_DIR is writeable.

CHAINCODE_SOURCE_DIR="$1"
CHAINCODE_METADATA_DIR="$2"
BUILD_OUTPUT_DIR="$3"

set -euo pipefail

#external chaincodes expect connection.json file in the chaincode package
if [ ! -f "$CHAINCODE_SOURCE_DIR/connection.json" ]; then
    >&2 echo "$CHAINCODE_SOURCE_DIR/connection.json not found"
    exit 1
fi

#simply copy the endpoint information to specified output location
cp $CHAINCODE_SOURCE_DIR/connection.json $BUILD_OUTPUT_DIR/connection.json

if [ -d "$CHAINCODE_SOURCE_DIR/metadata" ]; then
    cp -a $CHAINCODE_SOURCE_DIR/metadata $BUILD_OUTPUT_DIR/metadata
fi

exit 0           

最後,一旦

build

腳本執行完畢,就會調用

release

腳本。這個腳本負責提供connection.json檔案給peer節點,它隻需要将該檔案放到release輸出目錄就可以了。是以,peer現在知道如何調用鍊碼了。

#!/bin/sh

# The bin/release script is responsible for providing chaincode metadata to the peer. 
# bin/release is optional. If it is not provided, this step is skipped. 
#
# The peer invokes release with two arguments:
# bin/release BUILD_OUTPUT_DIR RELEASE_OUTPUT_DIR
#
# When release is invoked, BUILD_OUTPUT_DIR contains the artifacts 
# populated by the build program and should be treated as read only input. 
# RELEASE_OUTPUT_DIR is the directory where release must place artifacts to be consumed by the peer.

set -euo pipefail

BUILD_OUTPUT_DIR="$1"
RELEASE_OUTPUT_DIR="$2"

# copy indexes from metadata/* to the output directory
# if [ -d "$BUILD_OUTPUT_DIR/metadata" ] ; then
#    cp -a "$BUILD_OUTPUT_DIR/metadata/"* "$RELEASE_OUTPUT_DIR/"
# fi

#external chaincodes expect artifacts to be placed under "$RELEASE_OUTPUT_DIR"/chaincode/server
if [ -f $BUILD_OUTPUT_DIR/connection.json ]; then
   mkdir -p "$RELEASE_OUTPUT_DIR"/chaincode/server
   cp $BUILD_OUTPUT_DIR/connection.json "$RELEASE_OUTPUT_DIR"/chaincode/server

   #if tls_required is true, copy TLS files (using above example, the fully qualified path for these fils would be "$RELEASE_OUTPUT_DIR"/chaincode/server/tls)

   exit 0
fi

exit 1           

5、Fabric外部鍊碼的建構與部署

一旦我們在peer節點上安裝了鍊碼,就可以建構并在我們的kubernetes叢集上部署這些鍊碼了。讓我們看一下必要的修改。

首先需要import一些必要的子產品:

import (
    "bytes"
    "encoding/json"
    "fmt"
    "strconv"
    "strings"
    "time"
    "os"

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

需要指出的一點是,在建構代碼之前需要定義go.mod檔案。最新版本的shim子產品中包含了對外部鍊碼特性的支援 —— 目前隻有go 鍊碼開發包支援外部鍊碼。

module github.com/marbles
  
go 1.12

require (
        github.com/hyperledger/fabric-chaincode-go v0.0.0-20200128192331-2d899240a7ed
        github.com/hyperledger/fabric-protos-go v0.0.0-20200124220212-e9cfc186ba7b
        golang.org/x/net v0.0.0-20200202094626-16171245cfb2 // indirect
        golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4 // indirect
        golang.org/x/text v0.3.2 // indirect
        google.golang.org/genproto v0.0.0-20200218151345-dad8c97a84f5 // indirect
)           

其他的變化包括修改鍊碼伺服器的監聽位址、端口等。因為我們希望使用kubernetes的yaml描述檔案來修改這些配置,是以我們使用os子產品來擷取這些值:

func main() {

    server := &shim.ChaincodeServer{
        CCID:    os.Getenv("CHAINCODE_CCID"),
        Address: os.Getenv("CHAINCODE_ADDRESS"),
        CC:      new(SimpleChaincode),
        TLSProps: shim.TLSProperties{
                Disabled: true,
        },
    }

    // Start the chaincode external server
    err := server.Start()

    if err != nil {
        fmt.Printf("Error starting Marbles02 chaincode: %s", err)
    }
}           

現在可以用下面的Dockerfile來建構鍊碼鏡像:

# This image is a microservice in golang for the Degree chaincode
FROM golang:1.13.8-alpine AS build

COPY ./ /go/src/github.com/marbles
WORKDIR /go/src/github.com/marbles

# Build application
RUN go build -o chaincode -v .

# Production ready image
# Pass the binary to the prod image
FROM alpine:3.11 as prod

COPY --from=build /go/src/github.com/marbles/chaincode /app/chaincode

USER 1000

WORKDIR /app
CMD ./chaincode           

鍊碼是使用一個golang的alpine鏡像建構的。執行如下指令建立鍊碼鏡像:

$ docker build -t chaincode/marbles:1.0 .           

一切順利的話,就可以部署了。修改鍊碼部署檔案org1-chaincode-deployment.yaml和org2-chaincode-deployment.yaml中的CHAINCODE_CCID變量為你需要安裝的鍊碼。

#---------------- Chaincode Deployment ---------------------
apiVersion: apps/v1 # for versions before 1.8.0 use apps/v1beta1
kind: Deployment
metadata:
  name: chaincode-marbles-org1
  namespace: hyperledger
  labels:
    app: chaincode-marbles-org1
spec:
  selector:
    matchLabels:
      app: chaincode-marbles-org1
  strategy:
    type: Recreate
  template:
    metadata:
      labels:
        app: chaincode-marbles-org1
    spec:
      containers:
        - image: chaincode/marbles:1.0
          name: chaincode-marbles-org1
          imagePullPolicy: IfNotPresent
          env:
            - name: CHAINCODE_CCID
              value: "marbles:d8140fbc1a0903bd88611a96c5b0077a2fdeef00a95c05bfe52e207f5f9ab79d"
            - name: CHAINCODE_ADDRESS
              value: "0.0.0.0:7052"
          ports:
            - containerPort: 7052           

然後進行部署:

$ kubectl create -f chaincode/k8s           

現在fabric網絡看起來應該是這樣:

$ kubectl get pods -n hyperledgerNAME                                      READY   STATUS    RESTARTS   AGE
ca-org1-84945b8c7b-tx59g                  1/1     Running   0          19h
ca-org2-7454f69c48-nfzsq                  1/1     Running   0          19h
chaincode-marbles-org1-6fc8858855-wdz7z   1/1     Running   0          20m
chaincode-marbles-org2-77bf56fdfb-6cdfm   1/1     Running   0          14m
cli-org1-589944999c-cvgbx                 1/1     Running   0          19h
cli-org2-656cf8dd7c-kcxd7                 1/1     Running   0          19h
orderer0-5844bd9bcc-6td8c                 1/1     Running   0          46h
orderer1-75d8df99cd-6vbjl                 1/1     Running   0          46h
orderer2-795cf7c4c-6lsdd                  1/1     Running   0          46h
peer0-org1-5bc579d766-kq2qd               1/1     Running   0          19h
peer0-org2-77f58c87fd-sczp8               1/1     Running   0          19h           

現在我們需要為每個機構審批鍊碼。這是鍊碼生命周期過程的一個新特性,每個機構都需要同意新鍊碼的定義。我們将為org1審批marble鍊碼定義。在org1的cli pod内執行如下指令,記得修改CHAINCODE_CCID:

$ peer lifecycle chaincode approveformyorg --channelID mychannel --name marbles --version 1.0 --init-required --package-id marbles:e001937433673b11673d660d142c722fc372905db87f88d2448eee42c9c63064 --sequence 1 -o orderer0:7050 --tls --cafile $ORDERER_CA --signature-policy "AND ('org1MSP.peer','org2MSP.peer')"

### Should print a similar output
2020-03-08 10:02:46.192 UTC [chaincodeCmd] ClientWait -> INFO 001 txid [4d81ea5fd494e9717a0c860812d2b06bc62e4fc6c4b85fa6c3a916eee2c78e85] committed with status (VALID)           

你可以用如下指令檢查整個網絡中的審批狀态:

$ peer lifecycle chaincode checkcommitreadiness --channelID mychannel --name marbles --version 1.0 --init-require
d --sequence 1 -o -orderer0:7050 --tls --cafile $ORDERER_CA --signature-policy "AND ('org1MSP.peer','org2MSP.peer')"

### Should print a similar output
Chaincode definition for chaincode 'marbles', version '1.0', sequence '1' on channel 'mychannel' approval status by org:
org1MSP: true
org2MSP: false           

現在讓我們為org2準許鍊碼定義。在org2的cli pod中執行如下指令,記得修改CHAINCODE_CCID:

$ peer lifecycle chaincode approveformyorg --channelID mychannel --name marbles --version 1.0 --init-required --package-id marbles:25a9f6fe26161d29af928228ca1db0c41892e26e46335c84952336ee26d1fd93 --sequence 1 -o orderer0:7050 --tls --cafile $ORDERER_CA --signature-policy "AND ('org1MSP.peer','org2MSP.peer')"

### Should print a similar output
2020-03-08 10:26:43.992 UTC [chaincodeCmd] ClientWait -> INFO 001 txid [74a89f3c93c10f14c626bd4d6cb654b37889908c9e6f7b983d2cad79f1e82267] committed with status (VALID)           

再次檢查鍊碼送出狀态:

$ peer lifecycle chaincode checkcommitreadiness --channelID mychannel --name marbles --version 1.0 --init-required --sequence 1 -o orderer0:7050 --tls --cafile $ORDERER_CA --signature-policy "AND ('org1MSP.peer','org2MSP.peer')"

### Should print a similar output
Chaincode definition for chaincode 'marbles', version '1.0', sequence '1' on channel 'mychannel' approval status by org:
org1MSP: true
org2MSP: true           

現在我們得到所有機構的準許,讓我們将鍊碼定義在通道上送出。可以在任何peer上執行如下操作:

$ peer lifecycle chaincode commit -o orderer0:7050 --channelID mychannel --name marbles --version 1.0 --sequence 1 --init-required --tls true --cafile $ORDERER_CA --peerAddresses peer0-org1:7051 --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1/peers/peer0-org1/tls/ca.crt --peerAddresses peer0-org2:7051 --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2/peers/peer0-org2/tls/ca.crt --signature-policy "AND ('org1MSP.peer','org2MSP.peer')"

### Should print a similar output
2020-03-08 14:13:49.516 UTC [chaincodeCmd] ClientWait -> INFO 001 txid [568cb81f821698025bbc61f4c6cd3b4baf1aea632e1e1a8cfdf3ec3902d1c6bd] committed with status (VALID) at peer0-org1:7051
2020-03-08 14:13:49.533 UTC [chaincodeCmd] ClientWait -> INFO 002 txid [568cb81f821698025bbc61f4c6cd3b4baf1aea632e1e1a8cfdf3ec3902d1c6bd] committed with status (VALID) at peer0-org2:7051           

好了,現在鍊碼已經就緒,可以查詢和調用了!

6、測試Fabric外部鍊碼

我們可以從cli pod中測試鍊碼的查詢和交易調用。首先建立一些寶石:

$ peer chaincode invoke -o orderer0:7050 --tls true --cafile $ORDERER_CA -C mychannel -n marbles --peerAddresses 
peer0-org1:7051 --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1/peers/peer0-org1/tls/ca.crt --peerAddresses peer
0-org2:7051 --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2/peers/peer0-org2/tls/ca.crt -c '{"Args":["initMarble
","marble1","blue","35","tom"]}' --waitForEvent

### Should print a similar output
2020-03-08 14:23:03.569 UTC [chaincodeCmd] ClientWait -> INFO 001 txid [83aeeaac47cf6302bc139addc4aa38116a40eaff788846d87cc815d2e1318f44] committed with status (VALID) at peer0-org2:7051
2020-03-08 14:23:03.575 UTC [chaincodeCmd] ClientWait -> INFO 002 txid [83aeeaac47cf6302bc139addc4aa38116a40eaff788846d87cc815d2e1318f44] committed with status (VALID) at peer0-org1:7051
2020-03-08 14:23:03.576 UTC [chaincodeCmd] chaincodeInvokeOrQuery -> INFO 003 Chaincode invoke successful. result: status:200           

建立另一個寶石:

$ peer chaincode invoke -o orderer0:7050 --tls true --cafile $ORDERER_CA -C mychannel -n marbles --peerAddresses peer0-org1:7051 --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1/peers/peer0-org1/tls/ca.crt --peerAddresses peer0-org2:7051 --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2/peers/peer0-org2/tls/ca.crt -c '{"Args":["initMarble","marble2","red","50","tom"]}' --waitForEvent

### Should print a similar output
2020-03-08 14:23:40.404 UTC [chaincodeCmd] ClientWait -> INFO 001 txid [8391f9f8ea84887a56f99e4dc4501eaa6696cd7bd6c524e4868bd6cfd5b85e78] committed with status (VALID) at peer0-org2:7051
2020-03-08 14:23:40.434 UTC [chaincodeCmd] ClientWait -> INFO 002 txid [8391f9f8ea84887a56f99e4dc4501eaa6696cd7bd6c524e4868bd6cfd5b85e78] committed with status (VALID) at peer0-org1:7051
2020-03-08 14:23:40.434 UTC [chaincodeCmd] chaincodeInvokeOrQuery -> INFO 003 Chaincode invoke successful. result: status:200           

查詢寶石資訊:

$ peer chaincode query -C mychannel -n marbles -c '{"Args":["readMarble","marble1"]}'

{"docType":"marble","name":"marble1","color":"blue","size":35,"owner":"tom"}           

也可以執行如下指令查詢鍊碼日志:

$ kubectl logs chaincode_pod_name -n hyperledger

### Should print a similar output
invoke is running initMarble
- start init marble
- end init marble
invoke is running initMarble
- start init marble
- end init marble
invoke is running readMarble           

原文連結:

Hyperledger Fabric 2.0外部鍊碼實戰 — 彙智網