Try   HackMD
作者: 史綽琳
撰寫日期: 2021/01/19

第一個區塊鏈服務 Fabric-sample

Fabric-sample 是官方提供給初學 Hyperledger Fabric 的人使用的一套範例,github 連結在這裡,我下面所示範的是v2.2的版本,我不確定你看到的時候已經更新到哪裡了,至少保證2.2是這樣玩! 請放心服用

環境安裝

首先我們先讓環境符合 Hyperledger Fabric 的需求,以下是我的環境

  • ubuntu 20.04
  • go1.15.2 linux/amd64
  • docker 19.03.8
  • fabric-sample 2.2

部署完成後的架構會長這樣

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

相依套件安裝

基本套件

$ sudo apt update && sudo apt upgrade -y
$ sudo apt-get install git curl wget -y

安裝 docker

$ sudo apt-get -y install docker-compose
$ sudo usermod -aG docker ${USER}

===> logout and login are needed after adding docker group,
check everything is ok with the command below

$ id -nG

安裝 go

$ wget https://golang.org/dl/go1.15.2.linux-amd64.tar.gz
$ sudo tar -xvf go1.15.2.linux-amd64.tar.gz
$ sudo chown -R root:root ./go
$ sudo mv go /usr/local
$ sudo ln -s /usr/local/go/bin/go /usr/bin/go
$ go version

取得 fabric-sample

# 若後續均不接任何版本資訊,則預設抓最新版本
$ curl -sSL http://bit.ly/2ysbOFE | bash

# 若取得特定版本,則在後方接版本編號
$ curl -sSL http://bit.ly/2ysbOFE | bash -s -- <fabric_version> <fabric-ca_version> <thirdparty_version>
$ curl -sSL http://bit.ly/2ysbOFE | bash -s -- 2.2

完成後就會像這樣

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

這樣就算完成環境的準備了,接下來

進行操作

建立container

fabric 其實是由許多的container組合而成的服務,官方提供的 sample 中會建出1個 orderer、2個 peer 與2個 org,我們直接用官方提供的 script 進行演練。
進入操作資料夾位置

$ cd fabric-samples/test-network
$ ls

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

這邊可以看到幾個資料夾,我們針對重點進行說明

  1. configtx - 此資料夾裝著創世區塊的設定 configtx.yaml ,這個設定檔會定義你的 orderer 共識演算法、組織的 policy、peer 和 orderer 的名稱與金鑰擺放位置。(以後再細說)。
  2. docker - 此資料夾中裝著基本的 orderer 和 peer 的 docker-compose 設定檔,這當中定義了 orderer 和 peer 的初始設定,對於金鑰、憑證、身分、地址等都會在此定義,其他檔案則是示範ca server 與 couch db 的範例,此處不多贅述。
  3. network.sh - 就是 fabric-sample 的主要運作流程啦,把它裡面的指令一個一個拆出來就是手動部署的步驟了,那後面我會快速地針對這作解釋。
  4. organizations - 這裡存放著此範例中所有的金鑰與憑證,是重要的資料夾,之後透過 ca server 的部署,有很大一部分是參考此處作比較的,因此之後也會對此資料夾中的東西作說明。
  5. 其他 暫時用不到,不再贅述。

啟動 fabric 的 container 吧

./network.sh up

完成後可以看到3個container啟動了,分別是 peer0.org2.example.compeer0.org1.example.comorderer.example.com

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

至此代表 fabric 環境已經建立完成了

建立通道

如果看過前面介紹 Hyperledger Fabric ,相信你已經大略了解 channel 的重要性,部署 channel 便會用到上面提到的 configtx ,透過該 yaml 檔可以定義整個 Fabric 的走向,再加上區塊鏈不可逆的特性,初始區塊是非常重要的,記得開始部署前先想好自己要的架構再部署,否則就是無限的重頭。這裡因為官方都幫你設定好了,就直接下手吧

./network.sh createChannel

完成後可以看到這句小小的提示

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

至此代表 channel 建立成功並且 peer 也加入 channel

部署 chaincode

Chaincdoe 就是核心啦,官方 script 都幫妳寫好了就簡單這個指令下下去就對了

./network.sh deployCC

完成後可以看到這令人匪夷所思的結語

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

「Chaincode initialization is not required」什麼意思呢? 是不是部署出錯了?
別擔心,因為2.2開始此 script 只是幫你把預設的 chaincode 打包好並且安裝在 peer 和 channel 中,而1.4的則是連 init 都幫你完成了,所以如果你是從1.4跳到2.2的話,別緊張~這一切還在掌控中。

接著,我們便需要手動 init 該 chaincode。在 init 之前請先切換身分成 peer0.org1.example.com (當然你要使用 peer0.org2.example.com 也可以),才可以接續操作喔!

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →
提示: 如果你實際部署的環境中有cli的話,直接進去cli進行操作就可以了!
ex:
docker exec -it <container name of cli> /bin/bash
kubectl exec -it <container/pod name of cli> /bin/bash

export PATH=${PWD}/../bin:$PATH
export FABRIC_CFG_PATH=$PWD/../config/
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/Admin@org1.example.com/msp
export CORE_PEER_ADDRESS=localhost:7051

身份切換完成後,便可以 init 已安裝的 chaincode 了,如下

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 mychannel -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":[]}'

當你看到如下圖的提示訊息,便代表 init 成功了,接著便可以嘗試查詢帳本內容

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

peer chaincode query -C mychannel -n basic -c '{"Args":["GetAllAssets"]}'

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

這樣一個熱騰騰的 Hyperledger Fabric 的服務便完成了,真是可喜可賀!!

過程說明

好啦,如果你只是想要透過 fabric-sample 先成功部署出來的話,上述的過程就足夠了,接下來我們會來拆解上述過程中跑出來的訊息所代表的意思

建立container

在此步驟中,我們主要是透要取得 peer 、orderer 與 org 的相關憑證與金鑰,在沒有 ca server 的狀況下,Fabric 提供一個產金鑰的套件叫做「cryptogen」,此套件的原理跟 openssl 差不多~有興趣的自己去找資料。
我們會提供他一個設定檔,定義出我們有幾個 organization 、該 organization 有幾個 peer、同時我們會有幾個 orderer 等資訊,因此我們先來看看 script 輸出的流程

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

在圖中我們可以看到提供給 cryptogen 的 config 檔案,以下先貼出 org1 的設定

# Copyright IBM Corp. All Rights Reserved.
#
# SPDX-License-Identifier: Apache-2.0
#


# ---------------------------------------------------------------------------
# "PeerOrgs" - Definition of organizations managing peer nodes
# ---------------------------------------------------------------------------
PeerOrgs:
  # ---------------------------------------------------------------------------
  # Org1
  # ---------------------------------------------------------------------------
  - Name: Org1
    Domain: org1.example.com
    EnableNodeOUs: true
    # ---------------------------------------------------------------------------
    # "Specs"
    # ---------------------------------------------------------------------------
    # Uncomment this section to enable the explicit definition of hosts in your
    # configuration.  Most users will want to use Template, below
    #
    # Specs is an array of Spec entries.  Each Spec entry consists of two fields:
    #   - Hostname:   (Required) The desired hostname, sans the domain.
    #   - CommonName: (Optional) Specifies the template or explicit override for
    #                 the CN.  By default, this is the template:
    #
    #                              "{{.Hostname}}.{{.Domain}}"
    #
    #                 which obtains its values from the Spec.Hostname and
    #                 Org.Domain, respectively.
    # ---------------------------------------------------------------------------
    #   - Hostname: foo # implicitly "foo.org1.example.com"
    #     CommonName: foo27.org5.example.com # overrides Hostname-based FQDN set above
    #   - Hostname: bar
    #   - Hostname: baz
    # ---------------------------------------------------------------------------
    # "Template"
    # ---------------------------------------------------------------------------
    # Allows for the definition of 1 or more hosts that are created sequentially
    # from a template. By default, this looks like "peer%d" from 0 to Count-1.
    # You may override the number of nodes (Count), the starting index (Start)
    # or the template used to construct the name (Hostname).
    #
    # Note: Template and Specs are not mutually exclusive.  You may define both
    # sections and the aggregate nodes will be created for you.  Take care with
    # name collisions
    # ---------------------------------------------------------------------------
    Template:
      Count: 1
      SANS:
        - localhost
      # Start: 5
      # Hostname: {{.Prefix}}{{.Index}} # default
    # ---------------------------------------------------------------------------
    # "Users"
    # ---------------------------------------------------------------------------
    # Count: The number of user accounts _in addition_ to Admin
    # ---------------------------------------------------------------------------
    Users:
      Count: 1

前面比較不需要說明,org 的 Name 和 Domain 在此進行定義,EnableNodeOUs 則是 Fabric 中 policy 會用到的一種功能,未來在針對 fabric ca 的時候會在說明,這邊先知道就好。
下面 Template 與 Users 的部分雖然註解也有說明了,我這邊就簡要的提一下:

  • Template 是在說明我這個組織要建立多少個 peer 節點
  • Users 則是說已 admin 權限進行操作的最大連線數,簡單來說我同時只允許一個連線是已 admin 的身分進行的

Org2 的部分也相同,這邊就跳過,接著來看看 orderer 的

# Copyright IBM Corp. All Rights Reserved.
#
# SPDX-License-Identifier: Apache-2.0
#

# ---------------------------------------------------------------------------
# "OrdererOrgs" - Definition of organizations managing orderer nodes
# ---------------------------------------------------------------------------
OrdererOrgs:
  # ---------------------------------------------------------------------------
  # Orderer
  # ---------------------------------------------------------------------------
  - Name: Orderer
    Domain: example.com
    EnableNodeOUs: true
    # ---------------------------------------------------------------------------
    # "Specs" - See PeerOrgs for complete description
    # ---------------------------------------------------------------------------
    Specs:
      - Hostname: orderer
        SANS:
          - localhost

對 orderer 來說就相對簡單一點,前面的 Name、Domain、EnableNodeOUs 是相同的意思,代過
Spec 則是你會用到的主機名稱,在實際的 fabric 環境中我們會使用多主機的方式進行分布式部署,而在 k8s 的環境中更是會透過多個 pod 組合成一個完整的 k8s 環境,因此此處便需要定義你環境中會用的主機名稱或是域名。 此範例因為都在 localhost,所以就不需要設定額外的域名了。

當產生完這些金鑰與憑證後,script 便會開始產生創世區塊,也就是前面所說會用到的 configtx.yaml,因為該 yaml 的內容太多了這邊實在沒辦法一次說完,因此先針對執行的指令進行說明

configtxgen -profile TwoOrgsOrdererGenesis -channelID system-channel -outputBlock ./system-genesis-block/genesis.block
  • TwoOrgsOrdererGenesis 是你想要執行的共識演算法,在 configtx 定義最後一項 Profiles 中的名稱,他會帶入上面所有設定的參數。
  • genesis.block 便是此區塊鏈的最根本 - 「創世區塊」,此創世區塊便是所有節點在加入時必須取得的訊息,因此請好好保留著!

接著就是啟動各個 container,當然所有設定檔都已經先行完成了,在 fabric-samples/test-network/docker 資料夾中,以後在 k8s 部署的時候再說明。

建立通道

channel 的部分我們將所有的指令分成兩個部分來看

第一部分,基本節點結構

主要來說在創建通道前,我們要提供一些訊息給通道知道,例如有多少組織在上面跑、組織對外溝通的 anchorpeer 是誰等

configtxgen -profile TwoOrgsChannel -outputCreateChannelTx ./channel-artifacts/mychannel.tx -channelID mychannel
configtxgen -profile TwoOrgsChannel -outputAnchorPeersUpdate ./channel-artifacts/Org1MSPanchors.tx -channelID mychannel -asOrg Org1MSP
configtxgen -profile TwoOrgsChannel -outputAnchorPeersUpdate ./channel-artifacts/Org2MSPanchors.tx -channelID mychannel -asOrg Org2MSP
  • TwoOrgsChannel 也是在 configtx.yaml 中定義的,並產出一個名為[mychannel]的通道資訊 (mychannel.tx)
  • mychannel.tx 是在上述產生創世區塊時一併產出的,用以作為 channel 的初始區塊作使用
  • Org1MSPanchors.tx 是在上述產生創世區塊時一併產出的,根據 configtx 定義 org1 的 anchorpeer 是誰。
  • Org2MSPanchors.tx 是在上述產生創世區塊時一併產出的,根據 configtx 定義 org2 的 anchorpeer 是誰。

第二部分,通道結構

接著就是實際建立通道的時候了,首先先根據先前產生的通道初始訊息 (mychannel.tx) 進行搭建通道的初始區塊 (mychannel.block)

peer channel create -o localhost:7050 -c mychannel --ordererTLSHostnameOverride orderer.example.com -f ./channel-artifacts/mychannel.tx --outputBlock ./channel-artifacts/mychannel.block --tls --cafile /root/max-test/fabric-samples/test-network/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem

由於 fabric-sample 預設是有啟用 TLS 的服務,因此此處必須將 cafile 帶入執行參數中,所以指令才會這麼長,當你看到下圖的狀況,即代表你成功創建通道了!

接著將兩個組織加入此通道之中,並且告訴通道組織中的 anchorpeer 是誰

peer channel join -b ./channel-artifacts/mychannel.block
peer channel update -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com -c mychannel -f ./channel-artifacts/Org1MSPanchors.tx --tls --cafile /root/max-test/fabric-samples/test-network/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem

這邊或許有小夥伴會搞混,上面不是已經知道 anchorpeer 是誰了嗎? 為甚麼還要再說一次?
上面產出的 Org1MSPanchors.tx 有注意到副檔名嗎? 沒錯,他對於通道來說只是一個敘述設定檔,因此必須透過 *.tx 這個檔案告訴通道說,org1 和 org2 的 anchorpeer 是誰,這樣才會確實在該通道上運行。

之後看到上圖,就可以結束這回合了!!

部署 chaincode

接著就是部署 chaincode 的時間啦,首先 fabric 預設是會使用 go 進行部署,畢竟整個 fabric 就是透過 go 寫出來的,當然她也支援 java、javascript,有興趣的可以試著透過 java 等方式部署看看

在部署之前,系統會先幫你透過 go 安裝一些相依的組件,會先運行下列指令,在 script 輸出的狀況下應該是看不到的

GO111MODULE=on go mod vendor

完成後查看檔案會多了一個 vendor 的檔案,這是該 chaincode 會用到的相依檔案

接著我們要將 chaincode 打包成 tar 檔,讓 peer 可以進行安裝。

peer lifecycle chaincode package basic.tar.gz --path ../asset-transfer-basic/chaincode-go/ --lang golang --label basic_1.0

之後便是讓兩個組織的 peer 安裝該 tar 檔

peer lifecycle chaincode install basic.tar.gz

當完成此步驟後,系統會輸出一串 packet ID,這個 ID 是根據你所安裝的 chaincode 隨機產出的代碼,主要用於識別在通道的 chaincode。

通常當看到這個 packet ID 即代表 chaincode 已經安裝完成了,不過我們還是可以透過指令查看在 peer 上已經安裝的 chaincode

peer lifecycle chaincode queryinstalled

接著讓我們允許該 chaincode 允許在我們的通道上運行吧!!

peer lifecycle chaincode approveformyorg -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile /root/max-test/fabric-samples/test-network/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem --channelID mychannel --name basic --version 1.0 --package-id basic_1.0:4ec191e793b27e953ff2ede5a8bcc63152cecb1e4c3f301a26e22692c61967ad --sequence 1
  • version 由於你的 chaincode 可能還會需要修正,但已經在上面的 chaincode 是不可以被刪除的,所以當更新該 chaincode 基礎設定時,便會有 version 的差異
  • sequence 這是確認該 chaincode 是否有重複安裝在相同的 channel 中,以此避免相同的 chaincode 發生打架事件

這時候我們可以來看看,在通道上的組織們是不是都批准了該 chaincode 的運行,當組織都批准後便會出現下圖狀況

peer lifecycle chaincode checkcommitreadiness --channelID mychannel --name basic --version 1.0 --sequence 1 --output json

當組織們都批准這隻 chaincode 之後,我們便可以把 chaincode 上傳到通道上進行使用了;是的不要懷疑,你上面剛剛作的所有事情都只是把 chaincode 安裝到 peer,並且允許他運行而已,不代表他已經在通道中使用了!

peer lifecycle chaincode commit -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls --cafile /root/max-test/fabric-samples/test-network/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem --channelID mychannel --name basic --peerAddresses localhost:7051 --tlsRootCertFiles /root/max-test/fabric-samples/test-network/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt --peerAddresses localhost:9051 --tlsRootCertFiles /root/max-test/fabric-samples/test-network/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt --version 1.0 --sequence 1

完成上船之後,我就來檢查看看該 channel 上的 chaincode 有哪些

peer lifecycle chaincode querycommitted --channelID mychannel --name basic

這樣就恭喜你完成了 chaincode 的部署了!! 也恭喜你終於看完了整個 fabric 的部署流程了!!

事後屁話

乾,不得不說這真的很煩,裡面的毛很多,一下又要因為權限失敗、一下又因為網路失敗、還有ㄊㄇㄉ版本問題,搞的心很累。前期因為版本的問題,用的設定檔會有點不一樣,尤其不知道原理的時候看著 script 跑完之後心裡只有一種「阿然後呢?」的想法,拆他 script 的時候也花了不少時間去理解他到底在公三小,希望這篇可以提升你對於 fabric 的一些流程概念,這樣之後手動分布式部署、手動k8s 部署都是遵從這些規則,之後再慢慢更新吧,我先睡了

じゃあまたね