Hyperledger Fabric多通道實驗【V1.4.x】

Hyperledger Fabric支持在一組相同的機構之間的多通道部署, 每個通道都相當於一個單獨的區塊鏈。Fabric的多通道特性 不僅可以滿足機構之間不同的數據共享需求,同時也可以提高 整個Fabric網絡的吞吐量。本文將演示如何使用Hyperledger Fabric 1.4.3搭建一個多通道的區塊鏈網絡、部署並訪問鏈碼。

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

1、Hyperledger Fabric多通道網絡實驗環境概述

我們將構造一個包含3個機構的Hyperledger Fabric網絡:Org1、Org2和Org3, 每個機構中包含一個節點Peer0。網絡包含兩個通道:由Org1、 Org2和Org3組成的ChannelAll,以及由Org1和Org2組成的Channel12,因此 這個Fabric網絡是多通道的配置。在這兩個Fabric通道上我們將部署同樣的鏈碼, 即Fabrc-Samples中提供的Simple Asset鏈碼:

Hyperledger Fabric多通道實驗【V1.4.x】

2、Hyperledger Fabric多通道網絡實驗環境搭建

Step 1:在Hyperledger官方提供的fabric-samples目錄下克隆本教程提供的示例代碼:

<code>cd fabric-samples
git clone https://github.com/kctam/3org2ch_143.git
cd 3org2ch_143/<code>

Step 2:為參與Fabric通道的機構生成所需的密碼學資料

<code>../bin/cryptogen generate --config=./crypto-config.yaml/<code>

Step 3:生成Fabric通道素材

<code>mkdir channel-artifacts && export FABRIC_CFG_PATH=$PWD

../bin/configtxgen -profile OrdererGenesis \\
-outputBlock ./channel-artifacts/genesis.block

export CHANNEL_ONE_NAME=channelall
export CHANNEL_ONE_PROFILE=ChannelAll
export CHANNEL_TWO_NAME=channel12
export CHANNEL_TWO_PROFILE=Channel12

../bin/configtxgen -profile ${CHANNEL_ONE_PROFILE} \\
-outputCreateChannelTx ./channel-artifacts/${CHANNEL_ONE_NAME}.tx \\
-channelID $CHANNEL_ONE_NAME

../bin/configtxgen -profile ${CHANNEL_TWO_PROFILE} \\
-outputCreateChannelTx ./channel-artifacts/${CHANNEL_TWO_NAME}.tx \\
-channelID $CHANNEL_TWO_NAME

../bin/configtxgen -profile ${CHANNEL_ONE_PROFILE} \\
-outputAnchorPeersUpdate ./channel-artifacts/Org1MSPanchors_${CHANNEL_ONE_NAME}.tx \\
-channelID $CHANNEL_ONE_NAME -asOrg Org1MSP

../bin/configtxgen -profile ${CHANNEL_ONE_PROFILE} \\
-outputAnchorPeersUpdate ./channel-artifacts/Org2MSPanchors_${CHANNEL_ONE_NAME}.tx \\
-channelID $CHANNEL_ONE_NAME -asOrg Org2MSP

../bin/configtxgen -profile ${CHANNEL_ONE_PROFILE} \\
-outputAnchorPeersUpdate ./channel-artifacts/Org3MSPanchors_${CHANNEL_ONE_NAME}.tx \\

-channelID $CHANNEL_ONE_NAME -asOrg Org3MSP

../bin/configtxgen -profile ${CHANNEL_TWO_PROFILE} \\
-outputAnchorPeersUpdate ./channel-artifacts/Org1MSPanchors_${CHANNEL_TWO_NAME}.tx \\
-channelID $CHANNEL_TWO_NAME -asOrg Org1MSP

../bin/configtxgen -profile ${CHANNEL_TWO_PROFILE} \\
-outputAnchorPeersUpdate ./channel-artifacts/Org2MSPanchors_${CHANNEL_TWO_NAME}.tx \\
-channelID $CHANNEL_TWO_NAME -asOrg Org2MSP/<code>

Step 4:啟動所有的容器,最後應當看到有5個容器

<code>docker-compose up -d
docker ps/<code>

Step 5:為了便於演示,開啟3個終端,並設置排序節點的CA

Org1

<code>docker exec -it cli bash 

export ORDERER_CA=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem/<code>

Org2

<code>docker exec -e "CORE_PEER_LOCALMSPID=Org2MSP" \\
-e "CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt" \\
-e "CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/users/[email protected]/msp" \\
-e "CORE_PEER_ADDRESS=peer0.org2.example.com:7051" \\
-it cli bash

export ORDERER_CA=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem/<code>

Org3

<code>docker exec -e "CORE_PEER_LOCALMSPID=Org3MSP" \\
-e "CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org3.example.com/peers/peer0.org3.example.com/tls/ca.crt" \\
-e "CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org3.example.com/users/[email protected]/msp" \\
-e "CORE_PEER_ADDRESS=peer0.org3.example.com:7051" \\
-it cli bash

export ORDERER_CA=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem/<code>

Step 5:在Fabric網絡中創建多通道,並將各peer節點分別加入多個通道

首先創建channelall通道,並將3個機構的節點都加入該通道:

Org1

<code>peer channel create -o orderer.example.com:7050 -c channelall \\
-f /opt/gopath/src/github.com/hyperledger/fabric/peer/channel-artifacts/channelall.tx \\
--tls --cafile $ORDERER_CA

peer channel join -b channelall.block --tls --cafile $ORDERER_CA

peer channel update -o orderer.example.com:7050 -c channelall \\
-f /opt/gopath/src/github.com/hyperledger/fabric/peer/channel-artifacts/Org1MSPanchors_channelall.tx \\
--tls --cafile $ORDERER_CA/<code>

Org2

<code>peer channel join -b channelall.block --tls --cafile $ORDERER_CA

peer channel update -o orderer.example.com:7050 -c channelall \\
-f /opt/gopath/src/github.com/hyperledger/fabric/peer/channel-artifacts/Org2MSPanchors_channelall.tx \\
--tls --cafile $ORDERER_CA/<code>

Org3

<code>peer channel join -b channelall.block --tls --cafile $ORDERER_CA

peer channel update -o orderer.example.com:7050 -c channelall \\
-f /opt/gopath/src/github.com/hyperledger/fabric/peer/channel-artifacts/Org3MSPanchors_channelall.tx \\
--tls --cafile $ORDERER_CA/<code>

然後創建channel12,並將Org1和Org2都加入該通道:

Org1

<code>peer channel create -o orderer.example.com:7050 -c channel12 \\
-f /opt/gopath/src/github.com/hyperledger/fabric/peer/channel-artifacts/channel12.tx \\
--tls --cafile $ORDERER_CA

peer channel join -b channel12.block --tls --cafile $ORDERER_CA

peer channel update -o orderer.example.com:7050 -c channel12 \\
-f /opt/gopath/src/github.com/hyperledger/fabric/peer/channel-artifacts/Org1MSPanchors_channel12.tx \\
--tls --cafile $ORDERER_CA/<code>

Org2

<code>peer channel join -b channel12.block --tls --cafile $ORDERER_CA

peer channel update -o orderer.example.com:7050 -c channel12 \\
-f /opt/gopath/src/github.com/hyperledger/fabric/peer/channel-artifacts/Org2MSPanchors_channel12.tx \\
--tls --cafile $ORDERER_CA/<code>

Step 6:檢查各節點已經加入的Fabric通道

在各節點對應的終端中使用如下命令查看當前節點加入的通道:

<code>peer channel list/<code>

你應當可以看到org1和org2分別加入了兩個通道,而org3則只加入了一個通道。

如果一切順利,現在你就有了一個包含3個機構的多通道Fabric網絡,可以用於測試 任何鏈碼了。

Step 7:在測試完畢後記得清理實驗環境,命令如下:

<code>docker-compose down -v
docker rm $(docker ps -aq)
docker rmi $(docker images dev-* -q)/<code>

3、Fabric多通道安裝Simple Asset鏈碼(SACC)

現在我們的Fabric多通道實驗網絡已經起來了,可以開始部署鏈碼了。

我們使用fabric-samples內置的SACC鏈碼,其內容如下:

<code>/*
* Copyright IBM Corp All Rights Reserved
*
* SPDX-License-Identifier: Apache-2.0

*/

package main

import (
\t"fmt"

\t"github.com/hyperledger/fabric/core/chaincode/shim"
\t"github.com/hyperledger/fabric/protos/peer"
)

// SimpleAsset implements a simple chaincode to manage an asset
type SimpleAsset struct {
}

// Init is called during chaincode instantiation to initialize any
// data. Note that chaincode upgrade also calls this function to reset
// or to migrate data.
func (t *SimpleAsset) Init(stub shim.ChaincodeStubInterface) peer.Response {
\t// Get the args from the transaction proposal
\targs := stub.GetStringArgs()
\tif len(args) != 2 {
\t\treturn shim.Error("Incorrect arguments. Expecting a key and a value")
\t}

\t// Set up any variables or assets here by calling stub.PutState()

\t// We store the key and the value on the ledger
\terr := stub.PutState(args[0], []byte(args[1]))
\tif err != nil {
\t\treturn shim.Error(fmt.Sprintf("Failed to create asset: %s", args[0]))
\t}
\treturn shim.Success(nil)
}

// Invoke is called per transaction on the chaincode. Each transaction is
// either a 'get' or a 'set' on the asset created by Init function. The Set
// method may create a new asset by specifying a new key-value pair.
func (t *SimpleAsset) Invoke(stub shim.ChaincodeStubInterface) peer.Response {
\t// Extract the function and args from the transaction proposal
\tfn, args := stub.GetFunctionAndParameters()

\tvar result string
\tvar err error
\tif fn == "set" {
\t\tresult, err = set(stub, args)
\t} else { // assume 'get' even if fn is nil
\t\tresult, err = get(stub, args)
\t}
\tif err != nil {

\t\treturn shim.Error(err.Error())
\t}

\t// Return the result as success payload
\treturn shim.Success([]byte(result))
}

// Set stores the asset (both key and value) on the ledger. If the key exists,
// it will override the value with the new one
func set(stub shim.ChaincodeStubInterface, args []string) (string, error) {
\tif len(args) != 2 {
\t\treturn "", fmt.Errorf("Incorrect arguments. Expecting a key and a value")
\t}

\terr := stub.PutState(args[0], []byte(args[1]))
\tif err != nil {
\t\treturn "", fmt.Errorf("Failed to set asset: %s", args[0])
\t}
\treturn args[1], nil
}

// Get returns the value of the specified asset key
func get(stub shim.ChaincodeStubInterface, args []string) (string, error) {
\tif len(args) != 1 {
\t\treturn "", fmt.Errorf("Incorrect arguments. Expecting a key")
\t}

\tvalue, err := stub.GetState(args[0])
\tif err != nil {
\t\treturn "", fmt.Errorf("Failed to get asset: %s with error: %s", args[0], err)
\t}
\tif value == nil {
\t\treturn "", fmt.Errorf("Asset not found: %s", args[0])
\t}
\treturn string(value), nil
}

// main function starts up the chaincode in the container during instantiate
func main() {
\tif err := shim.Start(new(SimpleAsset)); err != nil {
\t\tfmt.Printf("Error starting SimpleAsset chaincode: %s", err)
\t}
}/<code>

Fabric Samples提供的SACC鏈碼的邏輯很簡單:

  • 當鏈碼實例化時就會執行Init()函數,該函數需要兩個參數,分別對應鍵和值
  • 將傳入Init()函數的鍵/值對使用PutState方法保存到賬本中
  • 在鏈碼實例化之後,對交易的處理是由Invoke()函數來負責的。 該函數的參數 包括一個方法名以及若干參數。
  • 如果調用Invoke()函數時方法名為set,那麼就需要傳入兩個參數,分別表示要 設置的鍵和值
  • 如果調用Invoke()函數時方法名為get,那麼就需要一個參數,表示要讀取的鍵

通過鏈碼安裝操作,就可以在各節點上啟動鏈碼。注意在鏈碼實例化之前還不可用。

在各節點對應的終端中使用如下命令安裝鏈碼:

<code>peer chaincode install -n sacc -p github.com/chaincode/sacc -v 1.0/<code>

我們應當可以看到如下的輸出結果:

Hyperledger Fabric多通道實驗【V1.4.x】

現在所有的節點上都安裝了SACC鏈碼,我們可以實例化這個鏈碼了。

4、Fabric多通道實驗1:ChannelAll通道上Fabric鏈碼的實例化與訪問

首先我們看包含所有三個機構的ChannelAll通道。

在Org1對應的終端中,在ChannelAll通道上實例化鏈碼:

<code>peer chaincode instantiate -o orderer.example.com:7050 --tls \\
--cafile $ORDERER_CA -C channelall -c '{"Args":["a", "100"]}' \\
-n sacc -v 1.0 -P "OR('Org1MSP.peer', 'Org2MSP.peer', 'Org3MSP.peer')"/<code>

我們設置了初始的鍵/值對為a/100。此外我們設置了背書策略:OR表示只需要 3個機構中的任何一個背書即可。

現在讓我們在通道ChannelAll上查詢鍵a的值。

進入Org1對應的終端,運行如下命令:

<code>peer chaincode query -C channelall -n sacc -c '{"Args":["get","a"]}'/<code>

結果如下:

Hyperledger Fabric多通道實驗【V1.4.x】

現在在Org2對應的終端中運行如下命令:

<code>peer chaincode query -C channelall -n sacc -c '{"Args":["get","a"]}'/<code>

結果如下:

Hyperledger Fabric多通道實驗【V1.4.x】

現在在Org3對應的終端中運行如下命令:

<code>peer chaincode query -C channelall -n sacc -c '{"Args":["get","a"]}'/<code>

結果如下:

Hyperledger Fabric多通道實驗【V1.4.x】

現在我們可以看到在三個節點上得到了相同的值,它們共享同一個賬本。

5、Fabric多通道實驗2:在Channel12通道上SACC鏈碼的實例化與交互

現在讓我們在通道Channel12上實例化這個SACC鏈碼。

在Org1對應的終端中,運行如下命令:

<code>peer chaincode instantiate -o orderer.example.com:7050 \\
--tls --cafile $ORDERER_CA -C channel12 \\
-c '{"Args":["b", "200"]}' -n sacc -v 1.0 \\
-P "OR('Org1MSP.peer', 'Org2MSP.peer')"/<code>

這次我們將初始的鍵/值對設置為b/200,背書策略為任一機構完成背書即可。

還是從Org1開始:

<code>peer chaincode query -C channel12 -n sacc -c '{"Args":["get","b"]}'/<code>

結果如下:

Hyperledger Fabric多通道實驗【V1.4.x】

然後進入Org2對應的終端:

<code>peer chaincode query -C channel12 -n sacc -c '{"Args":["get","b"]}'/<code>

結果如下:

Hyperledger Fabric多通道實驗【V1.4.x】

如果我們在Org3對應的終端運行同樣的命令,就會看到提示禁止訪問。這是 因為Org3沒有加入通道Channel12:

<code>peer chaincode query -C channel12 -n sacc -c '{"Args":["get","b"]}'/<code>

結果如下:

Hyperledger Fabric多通道實驗【V1.4.x】

如果我們嘗試在通道Channel12上讀取鍵a的值,會發現提示沒有定義a。 在Hyperledger Fabric中,每個通道都有自己的賬本,不同通道的狀態是不共享的。

在Org1和Org2的終端中運行如下命令:

<code>peer chaincode query -C channel12 -n sacc -c '{"Args":["get","a"]}'/<code>

結果如下:

Hyperledger Fabric多通道實驗【V1.4.x】

6、Fabric多通道實驗小節

在本教程中,我們介紹瞭如何搭建一個多通道Fabric網絡,並展示了不同 通道的數據隔離能力。如果你需要下載實驗中的源代碼,可以訪問這裡。


原文鏈接:http://blog.hubwiz.com/2020/03/17/fabric-multi-channel/


分享到:


相關文章: