在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外部鍊碼實戰 — 彙智網