Hyperledger Fabric 2.0外部鏈碼實戰

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


Hyperledger Fabric 2.0外部鏈碼實戰


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、安裝預編譯程序

使用以下命令安裝預編譯程序:

<code>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/<code>

3、啟動Hyperledger Fabric網絡

一旦我們啟動了kubernetes集群,就可以啟動Fabric網絡了。但是我們先要 生成基本的密碼學資料以及網絡創世區塊。在configtx.yaml中有一些修改 以適應fabric 2.0中新的chaincode lifecycle命令,這些修改對於使用外部 鏈碼啟動器是必須的。

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

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

<code>$ ./fabricOps.sh start/<code>

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

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

<code>$ kubectl create ns hyperledger/<code>

然後創建一個文件夾來保存Hyperledger Fabric工作負載的持久化數據:

<code>$ mkdir /home/storage/<code>

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

<code>$ kubectl create -f orderer-service//<code>

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

<code>$ 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/<code>

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

<code>$ kubectl create -f org1//<code>

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

<code>$ 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/<code>

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

<code>$ kubectl create -f org2//<code>

檢查Fabric網絡情況:

<code>$ 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/<code>

3、設置Fabric網絡的通道

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

<code>$ kubectl exec -it cli_org1_pod_name sh -n hyperledger/<code>

在這個pod內執行如下命令:

<code>$ 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/<code>

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

<code>$ 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/<code>

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

<code>$ kubectl exec -it cli_org2_pod_name sh -n hyperledger/<code>

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

<code>$ 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/<code>

然後加入通道:

<code>$ 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/<code>

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

<code>$ 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/<code>

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

現在開始我們進入真正有趣的環節。我們將部署marbles鏈碼作為外部鏈碼。你可以在Fabric-samples 中找到原始的鏈碼,但是為了將其作為外部鏈碼部署,我們需要在imports和init函數中進行一些修改, 以將其聲明為外部鏈碼服務器。

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

第一件要做的事情就是將peer節點配置為可以處理外部鏈碼。外部鏈碼構建器就是基於buildpack 實現,因此我們創建3個腳本:detect、build和release。這三個腳本必須在peer容器內定義。你可以 在buildpack/bin目錄下找到這些腳本。

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

<code># 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/<code>

kubernetes使用環境變量來配置peer節點,這些環境變量將覆蓋core.yaml中 的默認值。

Fabric 2.0採用了與之前版本不同的方式來打包和安裝鏈碼。由於我們要使用 外部鏈碼特性,因此鏈碼代碼不需要在peer的pod內進行編譯和安裝,而是在另一個 pod中進行。在peer進程中唯一需要的就是用來連接外部鏈碼進程的信息。

為此,我們需要打包鏈碼的一些準備。需要一個connection.json文件,其中 包含連接外部鏈碼服務器的信息,例如地址、TLS證書、連接超時配置等。

<code>{
"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-----"
}/<code>

這個文件需要打包進一個tar文件,code.tar.gz,使用如下命令進行壓縮打包:

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

一旦有了code.tar.gz文件,我們需要將其與另一個文件metadata.json一起重新打包。在 metadata.json中包含了鏈碼類型、路徑、標籤等信息:

<code>{"path":"","type":"external","label":"marbles"}/<code>

使用下面的命令打包:

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

一旦有了上面的打包文件,我們就可以使用新的 lifecycle chaincode install 命令來安裝鏈碼了:

<code>$ 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:<200 payload:="">
2020-03-07 14:33:18.126 UTC [cli.lifecycle.chaincode] submitInstallProposal -> INFO 002 Chaincode code package identifier: marbles:e001937433673b11673d660d142c722fc372905db87f88d2448eee42c9c63064/<code>

記下來上面的鏈碼包標識符,我們接下來會用到,不過你也可以隨時用下面 的命令查詢鏈碼包的標識符:

<code>$ peer lifecycle chaincode queryinstalled

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

現在我們為org2重複上面的步驟,但是由於我們希望用另一個pod為org2的peer節點提供鏈碼服務, 因此我們需要修改connection.json中的地址配置:

<code>"address": "chaincode-marbles-org2.hyperledger:7052",/<code>

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

<code>$ 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:<200 payload:="">
2020-03-07 15:10:15.093 UTC [cli.lifecycle.chaincode] submitInstallProposal -> INFO 002 Chaincode code package identifier: marbles:c422c797444e4ee25a92a8eaf97765288a8d68f9c29cedf1e0cd82e4aa2c8a5b/<code>

同樣記錄鏈碼包的標識符,它應該與之前org1的不同。

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

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

<code>#!/bin/sh

# The bin/detect/># 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/<code>

如果detect腳本成功,那麼就調用build腳本。如果在peer內部構建鏈碼,那麼 這個腳本應當生成二進制程序。但是由於我們希望作為外部服務,那麼只需要簡單 的拷貝connection.json文件到build的輸出目錄就可以了。

<code>#!/bin/sh

# The bin/build/># 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/># 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/<code>

最後,一旦build腳本執行完畢,就會調用release腳本。這個腳本負責 提供connection.json文件給peer節點,它只需要將該文件放到release輸出目錄 就可以了。因此,peer現在知道如何調用鏈碼了。

<code>#!/bin/sh

# The bin/release/># 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/<code>

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

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

首先需要import一些必要的模塊:

<code>import (
\t"bytes"
\t"encoding/json"
\t"fmt"
\t"strconv"
\t"strings"
\t"time"
\t"os"

\t"github.com/hyperledger/fabric-chaincode-go/shim"
\tpb "github.com/hyperledger/fabric-protos-go/peer"
)/<code>

需要指出的一點是,在構建代碼之前需要定義go.mod文件。最新版本的shim 模塊中包含了對外部鏈碼特性的支持 —— 目前只有go 鏈碼開發包支持外部鏈碼。

<code>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
)/<code>

其他的變化包括修改鏈碼服務器的監聽地址、端口等。因為我們希望使用kubernetes 的yaml描述文件來修改這些配置,因此我們使用os模塊來獲取這些值:

<code>func main() {

\tserver := &shim.ChaincodeServer{
\t\tCCID: os.Getenv("CHAINCODE_CCID"),
\t\tAddress: os.Getenv("CHAINCODE_ADDRESS"),
\t\tCC: new(SimpleChaincode),
\t\tTLSProps: shim.TLSProperties{
\t\t\t\tDisabled: true,
\t\t},
\t}

\t// Start the chaincode external server
\terr := server.Start()

\tif err != nil {
\t\tfmt.Printf("Error starting Marbles02 chaincode: %s", err)
\t}
}/<code>

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

<code># 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/<code>

鏈碼是使用一個golang的alpine鏡像構建的。執行如下命令創建鏈碼鏡像:

<code>$ docker build -t chaincode/marbles:1.0 ./<code>

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

<code>#---------------- 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/<code>

然後進行部署:

<code>$ kubectl create -f chaincode/k8s/<code>

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

<code>$ 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/<code>

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

<code>$ 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)/<code>

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

<code>$ 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/<code>

現在讓我們為org2批准鏈碼定義。在org2的cli pod中執行如下命令,記得修改CHAINCODE_CCID:

<code>$ 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)/<code>

再次檢查鏈碼提交狀態:

<code>$ 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/<code>

現在我們得到所有機構的批准,讓我們將鏈碼定義在通道上提交。可以在任何peer上執行如下操作:

<code>$ 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/<code>

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

6、測試Fabric外部鏈碼

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

<code>$ 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/<code>

創建另一個寶石:

<code>$ 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/<code>

查詢寶石信息:

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


{"docType":"marble","name":"marble1","color":"blue","size":35,"owner":"tom"}/<code>

也可以執行如下命令查詢鏈碼日誌:

<code>$ 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/<code>

原文鏈接:http://blog.hubwiz.com/2020/03/12/fabric-2-external-chaincode/


分享到:


相關文章: