Hyperledger Fabric1.4.4開發(fā)應(yīng)用程序-建立您的第一個(gè)網(wǎng)絡(luò)

建立您的第一個(gè)網(wǎng)絡(luò)

注意

這些說(shuō)明已通過(guò)驗(yàn)證,可與提供的tar文件中的最新穩(wěn)定Docker映像和預(yù)編譯的設(shè)置實(shí)用程序一起使用。如果使用當(dāng)前主分支中的圖像或工具運(yùn)行這些命令,則可能會(huì)看到配置和緊急錯(cuò)誤。

構(gòu)建您的第一個(gè)網(wǎng)絡(luò)(BYFN)方案將提供一個(gè)示例Hyperledger Fabric網(wǎng)絡(luò),該網(wǎng)絡(luò)由兩個(gè)組織組成,每個(gè)組織維護(hù)兩個(gè)對(duì)等節(jié)點(diǎn)。盡管可以使用其他訂購(gòu)服務(wù)實(shí)現(xiàn),但默認(rèn)情況下還將部署“ Solo”訂購(gòu)服務(wù)。

安裝先決條件

在我們開始之前,如果您尚未這樣做,則不妨檢查一下是否已在要開發(fā)區(qū)塊鏈應(yīng)用程序和/或運(yùn)行Hyperledger Fabric的平臺(tái)上安裝了所有必備軟件。

您還需要安裝Samples,Binaries和Docker Images。您會(huì)注意到fabric-samples存儲(chǔ)庫(kù)中包含許多示例。我們將使用 first-network示例?,F(xiàn)在打開該子目錄。

cd fabric-samples/first-network

注意

本文檔中提供的命令必須從存儲(chǔ)庫(kù)克隆first-network的子目錄中運(yùn)行 fabric-samples。如果選擇從其他位置運(yùn)行命令,則提供的各種腳本將無(wú)法找到二進(jìn)制文件。

要立即運(yùn)行嗎?

我們提供了一個(gè)帶有完整注釋的腳本- byfn.sh利用這些Docker映像快速引導(dǎo)Hyperledger Fabric網(wǎng)絡(luò),該網(wǎng)絡(luò)默認(rèn)情況下由代表兩個(gè)不同組織的四個(gè)對(duì)等方和一個(gè)訂購(gòu)者節(jié)點(diǎn)組成。它還將啟動(dòng)一個(gè)容器來(lái)運(yùn)行腳本執(zhí)行,該腳本執(zhí)行會(huì)將對(duì)等方加入到通道中,部署鏈碼并根據(jù)已部署的鏈碼推動(dòng)事務(wù)的執(zhí)行。

這是byfn.sh腳本的幫助文本:

Usage:
byfn.sh <mode> [-c <channel name>] [-t <timeout>] [-d <delay>] [-f <docker-compose-file>] [-s <dbtype>] [-l <language>] [-o <consensus-type>] [-i <imagetag>] [-v]"
  <mode> - one of 'up', 'down', 'restart', 'generate' or 'upgrade'"
    - 'up' - bring up the network with docker-compose up"
    - 'down' - clear the network with docker-compose down"
    - 'restart' - restart the network"
    - 'generate' - generate required certificates and genesis block"
    - 'upgrade'  - upgrade the network from version 1.3.x to 1.4.0"
  -c <channel name> - channel name to use (defaults to \"mychannel\")"
  -t <timeout> - CLI timeout duration in seconds (defaults to 10)"
  -d <delay> - delay duration in seconds (defaults to 3)"
  -f <docker-compose-file> - specify which docker-compose file use (defaults to docker-compose-cli.yaml)"
  -s <dbtype> - the database backend to use: goleveldb (default) or couchdb"
  -l <language> - the chaincode language: golang (default), node, or java"
  -o <consensus-type> - the consensus-type of the ordering service: solo (default), kafka, or etcdraft"
  -i <imagetag> - the tag to be used to launch the network (defaults to \"latest\")"
  -v - verbose mode"
byfn.sh -h (print this message)"

Typically, one would first generate the required certificates and
genesis block, then bring up the network. e.g.:"

  byfn.sh generate -c mychannel"
  byfn.sh up -c mychannel -s couchdb"
  byfn.sh up -c mychannel -s couchdb -i 1.4.0"
  byfn.sh up -l node"
  byfn.sh down -c mychannel"
  byfn.sh upgrade -c mychannel"

Taking all defaults:"
      byfn.sh generate"
      byfn.sh up"
      byfn.sh down"

如果選擇不提供標(biāo)志,則腳本將使用默認(rèn)值。

生成網(wǎng)絡(luò)工件

準(zhǔn)備好嘗試了嗎?好吧!執(zhí)行以下命令:

./byfn.sh generate

您將看到有關(guān)發(fā)生的情況的簡(jiǎn)短說(shuō)明,以及是/否命令行提示符。用a響應(yīng)y或按回車鍵執(zhí)行所描述的操作。

Generating certs and genesis block for channel 'mychannel' with CLI timeout of '10' seconds and CLI delay of '3' seconds
Continue? [Y/n] y
proceeding ...
/Users/xxx/dev/fabric-samples/bin/cryptogen

##########################################################
##### Generate certificates using cryptogen tool #########
##########################################################
org1.example.com
2017-06-12 21:01:37.334 EDT [bccsp] GetDefault -> WARN 001 Before using BCCSP, please call InitFactories(). Falling back to bootBCCSP.
...

/Users/xxx/dev/fabric-samples/bin/configtxgen
##########################################################
#########  Generating Orderer Genesis block ##############
##########################################################
2017-06-12 21:01:37.558 EDT [common/configtx/tool] main -> INFO 001 Loading configuration
2017-06-12 21:01:37.562 EDT [msp] getMspConfig -> INFO 002 intermediate certs folder not found at [/Users/xxx/dev/byfn/crypto-config/ordererOrganizations/example.com/msp/intermediatecerts]. Skipping.: [stat /Users/xxx/dev/byfn/crypto-config/ordererOrganizations/example.com/msp/intermediatecerts: no such file or directory]
...
2017-06-12 21:01:37.588 EDT [common/configtx/tool] doOutputBlock -> INFO 00b Generating genesis block
2017-06-12 21:01:37.590 EDT [common/configtx/tool] doOutputBlock -> INFO 00c Writing genesis block

#################################################################
### Generating channel configuration transaction 'channel.tx' ###
#################################################################
2017-06-12 21:01:37.634 EDT [common/configtx/tool] main -> INFO 001 Loading configuration
2017-06-12 21:01:37.644 EDT [common/configtx/tool] doOutputChannelCreateTx -> INFO 002 Generating new channel configtx
2017-06-12 21:01:37.645 EDT [common/configtx/tool] doOutputChannelCreateTx -> INFO 003 Writing new channel tx

#################################################################
#######    Generating anchor peer update for Org1MSP   ##########
#################################################################
2017-06-12 21:01:37.674 EDT [common/configtx/tool] main -> INFO 001 Loading configuration
2017-06-12 21:01:37.678 EDT [common/configtx/tool] doOutputAnchorPeersUpdate -> INFO 002 Generating anchor peer update
2017-06-12 21:01:37.679 EDT [common/configtx/tool] doOutputAnchorPeersUpdate -> INFO 003 Writing anchor peer update

#################################################################
#######    Generating anchor peer update for Org2MSP   ##########
#################################################################
2017-06-12 21:01:37.700 EDT [common/configtx/tool] main -> INFO 001 Loading configuration
2017-06-12 21:01:37.704 EDT [common/configtx/tool] doOutputAnchorPeersUpdate -> INFO 002 Generating anchor peer update
2017-06-12 21:01:37.704 EDT [common/configtx/tool] doOutputAnchorPeersUpdate -> INFO 003 Writing anchor peer update

第一步將為我們的各種網(wǎng)絡(luò)實(shí)體生成所有證書和密鑰,用于引導(dǎo)訂購(gòu)服務(wù),以及配置Channel所需的配置事務(wù)的集合 。genesis block

建立網(wǎng)絡(luò)

接下來(lái),您可以使用以下命令之一啟動(dòng)網(wǎng)絡(luò):

./byfn.sh up

上面的命令將編譯Golang鏈碼圖像并旋轉(zhuǎn)相應(yīng)的容器。Go是默認(rèn)的鏈碼語(yǔ)言,但是還支持Node.jsJava 鏈碼。如果您想使用節(jié)點(diǎn)鏈碼來(lái)完成本教程,請(qǐng)改用以下命令:

# we use the -l flag to specify the chaincode language
# forgoing the -l flag will default to Golang

./byfn.sh up -l node

注意

有關(guān)Node.js填充程序的更多信息,請(qǐng)參閱其 文檔。

注意

有關(guān)Java填充程序的更多信息,請(qǐng)參閱其 文檔。

使樣本使用Java chaincode運(yùn)行,您必須指定如下內(nèi)容:-l java

./byfn.sh up -l java

注意

不要同時(shí)運(yùn)行這兩個(gè)命令。除非您關(guān)閉并重新建立兩者之間的網(wǎng)絡(luò),否則只能嘗試一種語(yǔ)言。

除了支持多種鏈碼語(yǔ)言外,您還可以發(fā)出一個(gè)標(biāo)志,該標(biāo)志將顯示一個(gè)五節(jié)點(diǎn)的Raft訂購(gòu)服務(wù)或Kafka訂購(gòu)服務(wù),而不是一個(gè)節(jié)點(diǎn)的Solo訂購(gòu)服務(wù)。有關(guān)當(dāng)前支持的訂購(gòu)服務(wù)實(shí)現(xiàn)的更多信息,請(qǐng)查看The Ordering Service。

要使用Raft訂購(gòu)服務(wù)啟動(dòng)網(wǎng)絡(luò),請(qǐng)發(fā)出:

./byfn.sh up -o etcdraft

要使用Kafka訂購(gòu)服務(wù)建立網(wǎng)絡(luò),請(qǐng)發(fā)出:

./byfn.sh up -o kafka

再次提示您是否要繼續(xù)還是中止?;貞?yīng)一個(gè)y或點(diǎn)擊返回鍵:

Starting for channel 'mychannel' with CLI timeout of '10' seconds and CLI delay of '3' seconds
Continue? [Y/n]
proceeding ...
Creating network "net_byfn" with the default driver
Creating peer0.org1.example.com
Creating peer1.org1.example.com
Creating peer0.org2.example.com
Creating orderer.example.com
Creating peer1.org2.example.com
Creating cli

 ____    _____      _      ____    _____
/ ___|  |_   _|    / \    |  _ \  |_   _|
\___ \    | |     / _ \   | |_) |   | |
 ___) |   | |    / ___ \  |  _ <    | |
|____/    |_|   /_/   \_\ |_| \_\   |_|

Channel name : mychannel
Creating channel...

日志將從此處繼續(xù)。這將啟動(dòng)所有容器,然后驅(qū)動(dòng)一個(gè)完整的端到端應(yīng)用程序方案。成功完成后,它將在您的終端窗口中報(bào)告以下內(nèi)容:

Query Result: 90
2017-05-16 17:08:15.158 UTC [main] main -> INFO 008 Exiting.....
===================== Query successful on peer1.org2 on channel 'mychannel' =====================

===================== All GOOD, BYFN execution completed =====================

 _____   _   _   ____
| ____| | \ | | |  _ \
|  _|   |  \| | | | | |
| |___  | |\  | | |_| |
|_____| |_| \_| |____/

您可以滾動(dòng)瀏覽這些日志以查看各種事務(wù)。如果未得到此結(jié)果,請(qǐng)?zhí)痢?故障排除”部分,讓我們看看我們是否可以幫助您發(fā)現(xiàn)問(wèn)題所在。

中斷網(wǎng)絡(luò)

最后,讓我們將其全部介紹下來(lái),以便我們一次可以探索網(wǎng)絡(luò)設(shè)置。以下內(nèi)容將殺死您的容器,刪除加密材料和四個(gè)工件,并從Docker注冊(cè)表中刪除鏈碼映像:

./byfn.sh down

再次,您將被提示繼續(xù),用a響應(yīng)y或按回車鍵:

Stopping with channel 'mychannel' and CLI timeout of '10'
Continue? [Y/n] y
proceeding ...
WARNING: The CHANNEL_NAME variable is not set. Defaulting to a blank string.
WARNING: The TIMEOUT variable is not set. Defaulting to a blank string.
Removing network net_byfn
468aaa6201ed
...
Untagged: dev-peer1.org2.example.com-mycc-1.0:latest
Deleted: sha256:ed3230614e64e1c83e510c0c282e982d2b06d148b1c498bbdcc429e2b2531e91
...

如果您想了解更多有關(guān)底層工具和引導(dǎo)機(jī)制的信息,請(qǐng)繼續(xù)閱讀。在接下來(lái)的幾節(jié)中,我們將逐步介紹構(gòu)建一個(gè)功能齊全的Hyperledger Fabric網(wǎng)絡(luò)的各個(gè)步驟和要求。

注意

下面概述的手動(dòng)步驟假定FABRIC_LOGGING_SPECcli容器被設(shè)置為DEBUG。您可以通過(guò)修改目錄中的docker-compose-cli.yaml文件來(lái)進(jìn)行設(shè)置first-network。例如

cli:
  container_name: cli
  image: hyperledger/fabric-tools:$IMAGE_TAG
  tty: true
  stdin_open: true
  environment:
    - GOPATH=/opt/gopath
    - CORE_VM_ENDPOINT=unix:///host/var/run/docker.sock
    - FABRIC_LOGGING_SPEC=DEBUG
    #- FABRIC_LOGGING_SPEC=INFO

加密發(fā)生器

我們將使用該cryptogen工具為我們的各種網(wǎng)絡(luò)實(shí)體生成加密材料(x509證書和簽名密鑰)。這些證書代表身份,它們?cè)试S在我們的實(shí)體進(jìn)行通信和交易時(shí)進(jìn)行簽名/驗(yàn)證身份驗(yàn)證。

它是如何工作的?

Cryptogen使用一個(gè)文件- crypto-config.yaml包含網(wǎng)絡(luò)拓?fù)?,并允許我們?yōu)榻M織和屬于這些組織的組件生成一組證書和密鑰。每個(gè)組織都有一個(gè)唯一的根證書(ca-cert),它將特定組件(對(duì)等和訂購(gòu)者)綁定到該組織。通過(guò)為每個(gè)組織分配唯一的CA證書,我們正在模仿一個(gè)典型的網(wǎng)絡(luò),參與的成員將使用其自己的證書頒發(fā)機(jī)構(gòu)。Hyperledger Fabric中的事務(wù)和通信由實(shí)體的私鑰(keystore)簽名,然后通過(guò)公鑰()進(jìn)行驗(yàn)證signcerts。

您會(huì)count在此文件中注意到一個(gè)變量。我們使用它來(lái)指定每個(gè)組織的對(duì)等點(diǎn)數(shù);在我們的案例中,每個(gè)單位有兩個(gè)同級(jí)。我們現(xiàn)在不會(huì)深入研究x.509證書和公鑰基礎(chǔ)結(jié)構(gòu)的細(xì)節(jié) 。如果您有興趣,可以自行研究這些主題。

運(yùn)行該cryptogen工具后,生成的證書和密鑰將保存到名為的文件夾中crypto-config。請(qǐng)注意,該crypto-config.yaml 文件列出了五個(gè)與訂購(gòu)者組織相關(guān)的訂購(gòu)者。盡管該 cryptogen工具將為所有五個(gè)訂購(gòu)者創(chuàng)建證書,除非使用了Raft或Kafka訂購(gòu)服務(wù),否則這些訂購(gòu)者中只有一個(gè)將用于Solo訂購(gòu)服務(wù)實(shí)現(xiàn)中并用于創(chuàng)建系統(tǒng)頻道和mychannel。

配置事務(wù)生成器

configtxgen工具用于創(chuàng)建四個(gè)配置工件:

  • 訂購(gòu)者,genesis block
  • 通道,configuration transaction
  • 和兩個(gè)-每個(gè)對(duì)等組織一個(gè)。anchor peer transactions

有關(guān)此工具功能的完整說(shuō)明,請(qǐng)參見configtxgen。

訂購(gòu)者模塊是訂購(gòu)服務(wù)的創(chuàng)世紀(jì)模塊,并且在頻道創(chuàng)建時(shí)將頻道配置事務(wù)文件廣播到訂購(gòu)者。顧名思義,錨點(diǎn)對(duì)等事務(wù)指定此通道上的每個(gè)組織的錨點(diǎn)對(duì)等體。

它是如何工作的?

Configtxgen使用文件-- configtx.yaml包含示例網(wǎng)絡(luò)的定義。有三個(gè)成員-一個(gè)訂購(gòu)者組織(OrdererOrg)和兩個(gè)對(duì)等組織(Org1Org2),每個(gè)成員都管理和維護(hù)兩個(gè)對(duì)等節(jié)點(diǎn)。該文件還指定了一個(gè)財(cái)團(tuán)- SampleConsortium由我們的兩個(gè)對(duì)等組織組成。請(qǐng)?zhí)貏e注意此文件底部的“配置文件”部分。您會(huì)注意到我們有幾個(gè)唯一的配置文件。一些值得注意的地方:

  • TwoOrgsOrdererGenesis:生成獨(dú)奏訂購(gòu)服務(wù)的創(chuàng)始?jí)K。
  • SampleMultiNodeEtcdRaft:生成筏訂購(gòu)服務(wù)的創(chuàng)始?jí)K。僅在發(fā)出-o標(biāo)志并指定時(shí)使用etcdraft
  • SampleDevModeKafka:為Kafka訂購(gòu)服務(wù)生成創(chuàng)世塊。僅在發(fā)出-o標(biāo)志并指定時(shí)使用kafka
  • TwoOrgsChannel:為我們的頻道生成創(chuàng)世塊mychannel。

這些標(biāo)題很重要,因?yàn)樵趧?chuàng)建工件時(shí),我們會(huì)將它們作為參數(shù)傳遞。

注意

注意,我們SampleConsortium是在系統(tǒng)級(jí)配置文件中定義的,然后由我們的通道級(jí)配置文件引用。渠道存在于聯(lián)盟的權(quán)限范圍內(nèi),所有聯(lián)盟都必須在整個(gè)網(wǎng)絡(luò)范圍內(nèi)定義。

該文件還包含兩個(gè)值得注意的附加規(guī)范。首先,我們?yōu)槊總€(gè)對(duì)等組織(peer0.org1.example.compeer0.org2.example.com)指定錨點(diǎn)對(duì)等體。其次,我們指向每個(gè)成員的MSP目錄的位置,從而允許我們將每個(gè)組織的根證書存儲(chǔ)在訂購(gòu)者創(chuàng)始?jí)K中。這是一個(gè)關(guān)鍵的概念?,F(xiàn)在,與訂購(gòu)服務(wù)通信的任何網(wǎng)絡(luò)實(shí)體都可以驗(yàn)證其數(shù)字簽名。

運(yùn)行工具

您可以使用configtxgencryptogen命令手動(dòng)生成證書/密鑰和各種配置工件?;蛘撸梢試L試改編byfn.sh腳本以實(shí)現(xiàn)目標(biāo)。

手動(dòng)生成工件

您可以generateCerts在byfn.sh腳本中引用該函數(shù),以獲取生成用于crypto-config.yaml文件中定義的網(wǎng)絡(luò)配置的證書所需的命令。但是,為方便起見,我們還將在此處提供參考。

首先,讓我們運(yùn)行該cryptogen工具。我們的二進(jìn)制文件在bin 目錄中,因此我們需要提供工具所在的相對(duì)路徑。

../bin/cryptogen generate --config=./crypto-config.yaml

您應(yīng)該在終端中看到以下內(nèi)容:

org1.example.com
org2.example.com

證書和密鑰(即MSP資料)將輸出到目錄crypto-config-位于目錄根first-network目錄下。

接下來(lái),我們需要告訴該configtxgen工具在哪里尋找configtx.yaml需要提取的 文件。我們將在當(dāng)前的工作目錄中告訴它:

export FABRIC_CFG_PATH=$PWD

然后,我們將調(diào)用該configtxgen工具來(lái)創(chuàng)建訂購(gòu)者創(chuàng)始?jí)K:

../bin/configtxgen -profile TwoOrgsOrdererGenesis -channelID byfn-sys-channel -outputBlock ./channel-artifacts/genesis.block

要輸出筏訂購(gòu)服務(wù)的創(chuàng)始?jí)K,此命令應(yīng)為:

../bin/configtxgen -profile SampleMultiNodeEtcdRaft -channelID byfn-sys-channel -outputBlock ./channel-artifacts/genesis.block

請(qǐng)注意SampleMultiNodeEtcdRaft此處使用的配置文件。

要輸出Kafka訂購(gòu)服務(wù)的創(chuàng)世塊,請(qǐng)發(fā)出:

../bin/configtxgen -profile SampleDevModeKafka -channelID byfn-sys-channel -outputBlock ./channel-artifacts/genesis.block

如果您未使用Raft或Kafka,則應(yīng)看到類似于以下內(nèi)容的輸出:

2017-10-26 19:21:56.301 EDT [common/tools/configtxgen] main -> INFO 001 Loading configuration
2017-10-26 19:21:56.309 EDT [common/tools/configtxgen] doOutputBlock -> INFO 002 Generating genesis block
2017-10-26 19:21:56.309 EDT [common/tools/configtxgen] doOutputBlock -> INFO 003 Writing genesis block

注意

訂購(gòu)者的創(chuàng)世塊和我們將要?jiǎng)?chuàng)建的后續(xù)工件將輸出到channel-artifacts該項(xiàng)目根目錄下的目錄中。上面命令中的<cite style="box-sizing: border-box;">channelID</cite>是系統(tǒng)通道的名稱。

創(chuàng)建渠道配置交易

接下來(lái),我們需要?jiǎng)?chuàng)建通道事務(wù)構(gòu)件。確保替換$CHANNEL_NAME或設(shè)置CHANNEL_NAME為可在以下說(shuō)明中使用的環(huán)境變量:

# The channel.tx artifact contains the definitions for our sample channel

export CHANNEL_NAME=mychannel  && ../bin/configtxgen -profile TwoOrgsChannel -outputCreateChannelTx ./channel-artifacts/channel.tx -channelID $CHANNEL_NAME

請(qǐng)注意,如果您使用的是Raft或Kafka訂購(gòu)服務(wù),則不必對(duì)通道發(fā)出特殊命令。該TwoOrgsChannel配置文件將使用您在創(chuàng)建網(wǎng)絡(luò)的創(chuàng)世紀(jì)模塊時(shí)指定的訂購(gòu)服務(wù)配置。

如果您不使用Raft或Kafka訂購(gòu)服務(wù),則應(yīng)在終端中看到類似于以下內(nèi)容的輸出:

2017-10-26 19:24:05.324 EDT [common/tools/configtxgen] main -> INFO 001 Loading configuration
2017-10-26 19:24:05.329 EDT [common/tools/configtxgen] doOutputChannelCreateTx -> INFO 002 Generating new channel configtx
2017-10-26 19:24:05.329 EDT [common/tools/configtxgen] doOutputChannelCreateTx -> INFO 003 Writing new channel tx

接下來(lái),我們將在正在構(gòu)建的通道上為Org1定義錨點(diǎn)。同樣,請(qǐng)確保$CHANNEL_NAME為以下命令替換或設(shè)置環(huán)境變量。終端輸出將模擬通道事務(wù)工件的輸出:

../bin/configtxgen -profile TwoOrgsChannel -outputAnchorPeersUpdate ./channel-artifacts/Org1MSPanchors.tx -channelID $CHANNEL_NAME -asOrg Org1MSP

現(xiàn)在,我們將在同一通道上為Org2定義錨點(diǎn):

../bin/configtxgen -profile TwoOrgsChannel -outputAnchorPeersUpdate ./channel-artifacts/Org2MSPanchors.tx -channelID $CHANNEL_NAME -asOrg Org2MSP

啟動(dòng)網(wǎng)絡(luò)

注意

如果您byfn.sh以前運(yùn)行了上面的示例,請(qǐng)確保在繼續(xù)操作之前關(guān)閉了測(cè)試網(wǎng)絡(luò)(請(qǐng)參閱 關(guān)閉網(wǎng)絡(luò))。

我們將利用腳本來(lái)啟動(dòng)我們的網(wǎng)絡(luò)。docker-compose文件引用了我們先前下載的圖像,并使用我們先前生成的引導(dǎo)了訂購(gòu)程序genesis.block。

我們希望手動(dòng)檢查命令,以顯示每個(gè)調(diào)用的語(yǔ)法和功能。

首先,讓我們開始我們的網(wǎng)絡(luò):

docker-compose -f docker-compose-cli.yaml up -d

如果要查看網(wǎng)絡(luò)的實(shí)時(shí)日志,請(qǐng)不要提供該-d標(biāo)志。如果讓日志流傳輸,則需要打開第二個(gè)終端以執(zhí)行CLI調(diào)用。

創(chuàng)建并加入頻道

回想一下,我們使用上面configtxgen創(chuàng)建渠道配置交易”部分中的 工具創(chuàng)建了渠道配置交易。您可以使用configtx.yaml傳遞給configtxgen工具的相同或不同的配置文件,重復(fù)該過(guò)程以創(chuàng)建其他渠道配置事務(wù)。然后,您可以重復(fù)本節(jié)中定義的過(guò)程以在網(wǎng)絡(luò)中建立其他通道。

我們將使用以下命令輸入CLI容器:docker exec

docker exec -it cli bash

如果成功,您應(yīng)該看到以下內(nèi)容:

root@0d78bb69300d:/opt/gopath/src/github.com/hyperledger/fabric/peer#

為了使以下CLI命令起作用,我們需要在命令前添加以下四個(gè)環(huán)境變量。這些for peer0.org1.example.com的變量 被烘焙到CLI容器中,因此我們可以在不傳遞它們的情況下進(jìn)行操作。但是,如果要將呼叫發(fā)送給其他對(duì)等方或訂購(gòu)者,請(qǐng)?jiān)谶M(jìn)行任何CLI呼叫時(shí)覆蓋環(huán)境變量,如以下示例所示:

# Environment variables for PEER0

CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp
CORE_PEER_ADDRESS=peer0.org1.example.com:7051
CORE_PEER_LOCALMSPID="Org1MSP"
CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt

接下來(lái),作為創(chuàng)建通道請(qǐng)求的一部分,我們將把在“ 創(chuàng)建通道配置事務(wù)”部分(稱為channel.tx)中創(chuàng)建的生成的通道配置事務(wù)工件傳遞給訂購(gòu)者。

我們用-c標(biāo)志指定通道名稱,并用標(biāo)志指定通道配置事務(wù)-f。在這種情況下為channel.tx,但是您可以使用其他名稱掛載自己的配置事務(wù)。再次,我們將CHANNEL_NAME在CLI容器中設(shè)置環(huán)境變量,以便我們不必顯式傳遞此參數(shù)。頻道名稱必須全部為小寫字母,少于250個(gè)字符,并且與正則表達(dá)式匹配 [a-z][a-z0-9.-]*。

export CHANNEL_NAME=mychannel

# the channel.tx file is mounted in the channel-artifacts directory within your CLI container
# as a result, we pass the full path for the file
# we also pass the path for the orderer ca-cert in order to verify the TLS handshake
# be sure to export or replace the $CHANNEL_NAME variable appropriately

peer channel create -o orderer.example.com:7050 -c $CHANNEL_NAME -f ./channel-artifacts/channel.tx --tls --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem

注意

請(qǐng)注意--cafile,我們作為此命令的一部分進(jìn)行了傳遞。這是訂購(gòu)者根證書的本地路徑,使我們可以驗(yàn)證TLS握手。

此命令返回一個(gè)創(chuàng)世塊- <CHANNEL_NAME.block>我們將使用它來(lái)加入頻道。它包含在中指定的配置信息。channel.tx 如果您未對(duì)默認(rèn)通道名稱進(jìn)行任何修改,則該命令將返回標(biāo)題為的原型mychannel.block。

注意

這些手動(dòng)命令的其余部分將保留在CLI容器中。當(dāng)定位除以外的對(duì)等對(duì)象時(shí),您還必須記住在所有命令前加上相應(yīng)的環(huán)境變量 peer0.org1.example.com。

現(xiàn)在讓我們加入peer0.org1.example.com頻道。

# By default, this joins ``peer0.org1.example.com`` only
# the <CHANNEL_NAME.block> was returned by the previous command
# if you have not modified the channel name, you will join with mychannel.block
# if you have created a different channel name, then pass in the appropriately named block

 peer channel join -b mychannel.block

您可以通過(guò)在上面的“ 創(chuàng)建和加入頻道” 部分中使用的四個(gè)環(huán)境變量進(jìn)行適當(dāng)?shù)母?,使其他?duì)等節(jié)點(diǎn)加入頻道。

與其加入每個(gè)對(duì)等點(diǎn),不如簡(jiǎn)單地加入,peer0.org2.example.com以便我們可以正確地更新頻道中的錨點(diǎn)對(duì)等點(diǎn)定義。由于我們將覆蓋烘焙到CLI容器中的默認(rèn)環(huán)境變量,因此該完整命令如下:

``
CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp CORE_PEER_ADDRESS=peer0.org2.example.com:9051 CORE_PEER_LOCALMSPID="Org2MSP" 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 peer channel join -b mychannel.block


注意

在v1.4.1之前,docker網(wǎng)絡(luò)中的所有對(duì)等點(diǎn)都使用port `7051`。如果使用v1.4.1之前的版本的fabric-samples,請(qǐng)將`CORE_PEER_ADDRESS`本教程中所有出現(xiàn)的都修改為使用port `7051`。

另外,您可以選擇單獨(dú)設(shè)置這些環(huán)境變量,而不是傳入整個(gè)字符串。設(shè)置好之后,您只需再次發(fā)出命令,CLI容器將代表。`peer channel join``peer0.org2.example.com`

### 更新錨點(diǎn)

以下命令是通道更新,它們將傳播到通道的定義。本質(zhì)上,我們?cè)谕ǖ赖膭?chuàng)世塊之上添加了其他配置信息。請(qǐng)注意,我們不是在修改創(chuàng)世塊,而只是將增量添加到將定義錨點(diǎn)對(duì)等點(diǎn)的鏈中。

更新通道定義以將Org1的錨點(diǎn)對(duì)等定義為`peer0.org1.example.com`:

peer channel update -o orderer.example.com:7050 -c $CHANNEL_NAME -f ./channel-artifacts/Org1MSPanchors.tx --tls --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem


現(xiàn)在更新通道定義,將Org2的錨點(diǎn)對(duì)等定義為`peer0.org2.example.com`。與Org2對(duì)等方的命令相同,我們需要在此調(diào)用之前加上適當(dāng)?shù)沫h(huán)境變量。`peer channel join`

CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp CORE_PEER_ADDRESS=peer0.org2.example.com:9051 CORE_PEER_LOCALMSPID="Org2MSP" 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 peer channel update -o orderer.example.com:7050 -c $CHANNEL_NAME -f ./channel-artifacts/Org2MSPanchors.tx --tls --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem


### 安裝并實(shí)例化Chaincode

注意

我們將利用一個(gè)簡(jiǎn)單的現(xiàn)有鏈碼。要了解如何編寫自己的鏈碼,請(qǐng)參閱《[開發(fā)人員鏈碼》](https://hyperledger-fabric.readthedocs.io/en/release-1.4/chaincode4ade.html)教程。

應(yīng)用程序通過(guò)進(jìn)行與區(qū)塊鏈分類賬的交互`chaincode`。因此,我們需要在將執(zhí)行并認(rèn)可我們交易的每個(gè)對(duì)等方上安裝鏈碼,然后在通道上實(shí)例化鏈碼。

首先,將示例Go,Node.js或Java chaincode安裝到Org1中的peer0節(jié)點(diǎn)上。這些命令將指定的源代碼樣式放置到我們對(duì)等方的文件系統(tǒng)上。

注意

每個(gè)鏈碼名稱和版本只能安裝一個(gè)版本的源代碼。源代碼在鏈代碼名稱和版本的上下文中存在于對(duì)等方的文件系統(tǒng)上;它與語(yǔ)言無(wú)關(guān)。同樣,實(shí)例化的鏈碼容器將反映對(duì)等方上已安裝的任何語(yǔ)言。

**golang**

this installs the Go chaincode. For go chaincode -p takes the relative path from $GOPATH/src

peer chaincode install -n mycc -v 1.0 -p github.com/chaincode/chaincode_example02/go/


**Node.js**

this installs the Node.js chaincode

make note of the -l flag to indicate "node" chaincode

for node chaincode -p takes the absolute path to the node.js chaincode

peer chaincode install -n mycc -v 1.0 -l node -p /opt/gopath/src/github.com/chaincode/chaincode_example02/node/


**Java**

make note of the -l flag to indicate "java" chaincode

for java chaincode -p takes the absolute path to the java chaincode

peer chaincode install -n mycc -v 1.0 -l java -p /opt/gopath/src/github.com/chaincode/chaincode_example02/java/


當(dāng)我們實(shí)例化通道上的鏈碼時(shí),將設(shè)置背書策略以要求來(lái)自O(shè)rg1和Org2中的對(duì)等方的背書。因此,我們還需要在Org2的對(duì)等節(jié)點(diǎn)上安裝chaincode。

修改以下四個(gè)環(huán)境變量以對(duì)Org2中的peer0發(fā)出安裝命令:

Environment variables for PEER0 in Org2

CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp
CORE_PEER_ADDRESS=peer0.org2.example.com:9051
CORE_PEER_LOCALMSPID="Org2MSP"
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


現(xiàn)在,將示例Go,Node.js或Java鏈碼安裝到Org2中的peer0上。這些命令將指定的源代碼樣式放置到我們對(duì)等方的文件系統(tǒng)上。

**Golang**

this installs the Go chaincode. For go chaincode -p takes the relative path from $GOPATH/src

peer chaincode install -n mycc -v 1.0 -p github.com/chaincode/chaincode_example02/go/


**Node.js**

this installs the Node.js chaincode

make note of the -l flag to indicate "node" chaincode

for node chaincode -p takes the absolute path to the node.js chaincode

peer chaincode install -n mycc -v 1.0 -l node -p /opt/gopath/src/github.com/chaincode/chaincode_example02/node/


**Java**

make note of the -l flag to indicate "java" chaincode

for java chaincode -p takes the absolute path to the java chaincode

peer chaincode install -n mycc -v 1.0 -l java -p /opt/gopath/src/github.com/chaincode/chaincode_example02/java/


接下來(lái),實(shí)例化通道上的鏈碼。這將初始化通道上的鏈碼,為鏈碼設(shè)置背書策略,并為目標(biāo)對(duì)等方啟動(dòng)鏈碼容器。注意`-P` 論點(diǎn)。這是我們的政策,其中我們針對(duì)要驗(yàn)證的鏈碼指定了交易所需的背書級(jí)別。

在下面的命令中,您會(huì)注意到我們將策略指定為 。這意味著我們需要來(lái)自O(shè)rg1 **和** Org2 的對(duì)等方的“背書” (即兩次背書)。如果將語(yǔ)法更改為,則只需要一個(gè)背書即可。`-P "AND ('Org1MSP.peer','Org2MSP.peer')"``OR`

**Golang**

be sure to replace the $CHANNEL_NAME environment variable if you have not exported it

if you did not install your chaincode with a name of mycc, then modify that argument as well

peer chaincode instantiate -o orderer.example.com:7050 --tls --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C $CHANNEL_NAME -n mycc -v 1.0 -c '{"Args":["init","a", "100", "b","200"]}' -P "AND ('Org1MSP.peer','Org2MSP.peer')"


**Node.js**

注意

Node.js鏈代碼的實(shí)例化大約需要一分鐘。該命令未掛起;而是在編譯映像時(shí)安裝了fabric-shim層。

be sure to replace the $CHANNEL_NAME environment variable if you have not exported it

if you did not install your chaincode with a name of mycc, then modify that argument as well

notice that we must pass the -l flag after the chaincode name to identify the language

peer chaincode instantiate -o orderer.example.com:7050 --tls --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C $CHANNEL_NAME -n mycc -l node -v 1.0 -c '{"Args":["init","a", "100", "b","200"]}' -P "AND ('Org1MSP.peer','Org2MSP.peer')"


**Java**

注意

請(qǐng)注意,Java鏈代碼實(shí)例化可能會(huì)花費(fèi)一些時(shí)間,因?yàn)樗鼤?huì)在Java環(huán)境中編譯鏈代碼并下載docker容器。

peer chaincode instantiate -o orderer.example.com:7050 --tls --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C $CHANNEL_NAME -n mycc -l java -v 1.0 -c '{"Args":["init","a", "100", "b","200"]}' -P "AND ('Org1MSP.peer','Org2MSP.peer')"


有關(guān) 政策實(shí)施的更多詳細(xì)信息,請(qǐng)參閱[背書政策](http://hyperledger-fabric.readthedocs.io/en/latest/endorsement-policies.html)文檔。

如果希望其他對(duì)等方與分類帳進(jìn)行交互,則需要將它們加入通道,并將鏈碼源的相同名稱,版本和語(yǔ)言安裝到適當(dāng)?shù)膶?duì)等方的文件系統(tǒng)上。一旦每個(gè)對(duì)等方嘗試與該特定鏈?zhǔn)酱a進(jìn)行交互,就會(huì)為每個(gè)對(duì)等者啟動(dòng)一個(gè)鏈?zhǔn)酱a容器。同樣,請(qǐng)注意Node.js圖像的編譯速度較慢。

一旦鏈碼已在通道上實(shí)例化,我們就可以放棄該`l` 標(biāo)志。我們只需要輸入通道標(biāo)識(shí)符和鏈碼的名稱即可。

### 詢問(wèn)

讓我們查詢值`a`以確保正確地實(shí)例化了鏈碼并填充了狀態(tài)數(shù)據(jù)庫(kù)。查詢的語(yǔ)法如下:

be sure to set the -C and -n flags appropriately

peer chaincode query -C $CHANNEL_NAME -n mycc -c '{"Args":["query","a"]}'


### 調(diào)用

現(xiàn)在讓我們`10`從`a`移至`b`。此事務(wù)將剪切一個(gè)新塊并更新狀態(tài)數(shù)據(jù)庫(kù)。調(diào)用的語(yǔ)法如下:

be sure to set the -C and -n flags appropriately

peer chaincode invoke -o orderer.example.com:7050 --tls true --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C $CHANNEL_NAME -n mycc --peerAddresses peer0.org1.example.com:7051 --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt --peerAddresses peer0.org2.example.com:9051 --tlsRootCertFiles /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt -c '{"Args":["invoke","a","b","10"]}'


### 詢問(wèn)

讓我們確認(rèn)先前的調(diào)用已正確執(zhí)行。我們`a`使用值初始化鍵,`100`并在`10`之前的調(diào)用中將其刪除。因此,針對(duì)的查詢`a`應(yīng)返回`90`。查詢的語(yǔ)法如下。

be sure to set the -C and -n flags appropriately

peer chaincode query -C $CHANNEL_NAME -n mycc -c '{"Args":["query","a"]}'


我們應(yīng)該看到以下內(nèi)容:

Query Result: 90


隨意重新開始并操作鍵值對(duì)和后續(xù)調(diào)用。

### 安裝

現(xiàn)在,我們將鏈碼安裝在第三個(gè)對(duì)等節(jié)點(diǎn)Org2中的peer1上。修改以下四個(gè)環(huán)境變量以對(duì)Org2中的peer1發(fā)出安裝命令:

Environment variables for PEER1 in Org2

CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp
CORE_PEER_ADDRESS=peer1.org2.example.com:10051
CORE_PEER_LOCALMSPID="Org2MSP"
CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer1.org2.example.com/tls/ca.crt


現(xiàn)在,將示例Go,Node.js或Java chaincode安裝到Org2中的peer1上。這些命令將指定的源代碼樣式放置到我們對(duì)等方的文件系統(tǒng)上。

**Golang**

this installs the Go chaincode. For go chaincode -p takes the relative path from $GOPATH/src

peer chaincode install -n mycc -v 1.0 -p github.com/chaincode/chaincode_example02/go/


**Node.js**

this installs the Node.js chaincode

make note of the -l flag to indicate "node" chaincode

for node chaincode -p takes the absolute path to the node.js chaincode

peer chaincode install -n mycc -v 1.0 -l node -p /opt/gopath/src/github.com/chaincode/chaincode_example02/node/


**Java**

make note of the -l flag to indicate "java" chaincode

for java chaincode -p takes the absolute path to the java chaincode

peer chaincode install -n mycc -v 1.0 -l java -p /opt/gopath/src/github.com/chaincode/chaincode_example02/java/


### 詢問(wèn)

讓我們確認(rèn)我們可以向Org2中的Peer1發(fā)出查詢。我們`a`使用值初始化鍵,`100`并在`10`之前的調(diào)用中將其刪除。因此,針對(duì)的查詢`a`仍應(yīng)返回`90`。

Org2中的peer1必須首先加入通道,然后它才能響應(yīng)查詢??梢酝ㄟ^(guò)發(fā)出以下命令來(lái)加入通道:

CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp CORE_PEER_ADDRESS=peer1.org2.example.com:10051 CORE_PEER_LOCALMSPID="Org2MSP" CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer1.org2.example.com/tls/ca.crt peer channel join -b mychannel.block


連接命令返回后,可以發(fā)出查詢。查詢的語(yǔ)法如下。

<pre style="box-sizing: border-box; font-family: Consolas, &quot;Andale Mono WT&quot;, &quot;Andale Mono&quot;, &quot;Lucida Console&quot;, &quot;Lucida Sans Typewriter&quot;, &quot;DejaVu Sans Mono&quot;, &quot;Bitstream Vera Sans Mono&quot;, &quot;Liberation Mono&quot;, &quot;Nimbus Mono L&quot;, Monaco, &quot;Courier New&quot;, Courier, monospace; font-size: 12px; white-space: pre; margin: 0px; padding: 12px; line-height: normal; display: block; overflow: auto; color: rgb(64, 64, 64);"># be sure to set the -C and -n flags appropriately

peer chaincode query -C $CHANNEL_NAME -n mycc -c '{"Args":["query","a"]}'

我們應(yīng)該看到以下內(nèi)容:

<pre style="box-sizing: border-box; font-family: Consolas, "Andale Mono WT", "Andale Mono", "Lucida Console", "Lucida Sans Typewriter", "DejaVu Sans Mono", "Bitstream Vera Sans Mono", "Liberation Mono", "Nimbus Mono L", Monaco, "Courier New", Courier, monospace; font-size: 12px; white-space: pre; margin: 0px; padding: 12px; line-height: normal; display: block; overflow: auto; color: rgb(64, 64, 64);">Query Result: 90
</pre>

隨意重新開始并操作鍵值對(duì)和后續(xù)調(diào)用。

幕后發(fā)生了什么?

注意

這些步驟描述了script.sh由'./byfn.sh up'運(yùn)行的情況 。使用清潔網(wǎng)絡(luò),并確保此命令處于活動(dòng)狀態(tài)。然后使用相同的docker-compose提示符再次啟動(dòng)網(wǎng)絡(luò)./byfn.sh down

  • 腳本-- script.sh在CLI容器中烘焙。該腳本createChannel根據(jù)提供的通道名稱驅(qū)動(dòng)命令,并使用channel.tx文件進(jìn)行通道配置。
  • 的輸出createChannel是一個(gè)創(chuàng)世塊-- <your_channel_name>.block存儲(chǔ)在對(duì)等方的文件系統(tǒng)上,并包含從channel.tx指定的通道配置。
  • joinChannel對(duì)所有四個(gè)對(duì)等設(shè)備執(zhí)行該命令,該命令將先前生成的創(chuàng)世塊作為輸入。此命令指示對(duì)等方加入<your_channel_name>并創(chuàng)建以開頭的鏈<your_channel_name>.block。
  • 現(xiàn)在,我們有一個(gè)由四個(gè)對(duì)等方和兩個(gè)組織組成的渠道。這是我們的TwoOrgsChannel個(gè)人資料。
  • peer0.org1.example.compeer1.org1.example.com屬于ORG1; peer0.org2.example.compeer1.org2.example.com屬于ORG2
  • 這些關(guān)系是通過(guò)定義的crypto-config.yaml,MSP路徑是在我們的docker compose中指定的。
  • 然后,更新Org1MSP(peer0.org1.example.com)和Org2MSP(peer0.org2.example.com)的錨點(diǎn)。為此,我們將Org1MSPanchors.txOrg2MSPanchors.tx工件以及渠道名稱一起傳遞給訂購(gòu)服務(wù)。
  • 一個(gè)chaincode - chaincode_example02 -安裝在peer0.org1.example.compeer0.org2.example.com
  • 然后將鏈碼“實(shí)例化”到mychannel。實(shí)例化將鏈碼添加到通道,啟動(dòng)目標(biāo)對(duì)等方的容器,并初始化與鏈碼關(guān)聯(lián)的鍵值對(duì)。此示例的初始值為[“ a”,“ 100”,“ b”,“ 200”]。這種“實(shí)例化”產(chǎn)生了一個(gè)名為“ dev-peer0.org2.example.com-mycc-1.0starting ”的容器。
  • 實(shí)例化還為背書策略傳遞了一個(gè)參數(shù)。該策略定義為 ,這意味著任何事務(wù)都必須由與Org1和Org2綁定的對(duì)等方認(rèn)可。-P "AND ('Org1MSP.peer','Org2MSP.peer')"
  • 向“ a”的值發(fā)出查詢peer0.org2.example.com。dev-peer0.org2.example.com-mycc-1.0 實(shí)例化鏈碼時(shí),已啟動(dòng)名為Org2 peer0的容器。返回查詢結(jié)果。沒有發(fā)生寫操作,因此對(duì)“ a”的查詢?nèi)詫⒎祷刂怠?100”。
  • 發(fā)送調(diào)用并將 “ 10”從“ a”移動(dòng)到“ b” peer0.org1.example.com并將peer0.org2.example.com其移動(dòng)
  • 查詢發(fā)送到peer0.org2.example.com“ a”的值。返回值90,正確反映了先前的交易,在該交易中,鍵“ a”的值被修改了10。
  • 鏈碼-chaincode_example02-安裝在peer1.org2.example.com
  • 查詢發(fā)送到peer1.org2.example.com“ a”的值。這將啟動(dòng)名為的第三個(gè)chaincode容器dev-peer1.org2.example.com-mycc-1.0。返回值90,正確反映了先前的交易,在該交易中,鍵“ a”的值被修改了10。

這說(shuō)明了什么?

必須在對(duì)等方上安裝Chaincode ,以使其能夠?qū)Ψ诸悗こ晒?zhí)行讀/寫操作。此外,直到init針對(duì)該鏈碼執(zhí)行了傳統(tǒng)的交易(讀/寫)(例如,查詢“ a”的值)后,方才啟動(dòng)鏈碼容器。事務(wù)導(dǎo)致容器啟動(dòng)。而且,通道中的所有對(duì)等方都維護(hù)分類賬的精確副本,該副本包括將區(qū)塊,不可變的順序記錄存儲(chǔ)在塊中的區(qū)塊鏈,以及維護(hù)當(dāng)前狀態(tài)快照的狀態(tài)數(shù)據(jù)庫(kù)。這包括未在其上安裝鏈碼的那些對(duì)等方(peer1.org1.example.com如上例所示)。最后,安裝鏈碼后即可訪問(wèn)它(例如peer1.org2.example.com 在上面的示例中),因?yàn)樗驯粚?shí)例化。

我如何看待這些交易?

檢查CLI Docker容器的日志。

<pre style="box-sizing: border-box; font-family: Consolas, "Andale Mono WT", "Andale Mono", "Lucida Console", "Lucida Sans Typewriter", "DejaVu Sans Mono", "Bitstream Vera Sans Mono", "Liberation Mono", "Nimbus Mono L", Monaco, "Courier New", Courier, monospace; font-size: 12px; white-space: pre; margin: 0px; padding: 12px; line-height: normal; display: block; overflow: auto; color: rgb(64, 64, 64);">docker logs -f cli
</pre>

您應(yīng)該看到以下輸出:

<pre style="box-sizing: border-box; font-family: Consolas, "Andale Mono WT", "Andale Mono", "Lucida Console", "Lucida Sans Typewriter", "DejaVu Sans Mono", "Bitstream Vera Sans Mono", "Liberation Mono", "Nimbus Mono L", Monaco, "Courier New", Courier, monospace; font-size: 12px; white-space: pre; margin: 0px; padding: 12px; line-height: normal; display: block; overflow: auto; color: rgb(64, 64, 64);">2017-05-16 17:08:01.366 UTC [msp] GetLocalMSP -> DEBU 004 Returning existing local MSP
2017-05-16 17:08:01.366 UTC [msp] GetDefaultSigningIdentity -> DEBU 005 Obtaining default signing identity
2017-05-16 17:08:01.366 UTC [msp/identity] Sign -> DEBU 006 Sign: plaintext: 0AB1070A6708031A0C08F1E3ECC80510...6D7963631A0A0A0571756572790A0161
2017-05-16 17:08:01.367 UTC [msp/identity] Sign -> DEBU 007 Sign: digest: E61DB37F4E8B0D32C9FE10E3936BA9B8CD278FAA1F3320B08712164248285C54
Query Result: 90
2017-05-16 17:08:15.158 UTC [main] main -> INFO 008 Exiting.....
===================== Query successful on peer1.org2 on channel 'mychannel' =====================

===================== All GOOD, BYFN execution completed =====================


| ____| | \ | | | _
| | | | | | | | |
| |
__ | |\ | | || |
|_____| |
| _| |____/
</pre>

您可以滾動(dòng)瀏覽這些日志以查看各種事務(wù)。

如何查看鏈碼日志?

檢查各個(gè)chaincode容器,以查看針對(duì)每個(gè)容器執(zhí)行的單獨(dú)事務(wù)。這是每個(gè)容器的合并輸出:

<pre style="box-sizing: border-box; font-family: Consolas, "Andale Mono WT", "Andale Mono", "Lucida Console", "Lucida Sans Typewriter", "DejaVu Sans Mono", "Bitstream Vera Sans Mono", "Liberation Mono", "Nimbus Mono L", Monaco, "Courier New", Courier, monospace; font-size: 12px; white-space: pre; margin: 0px; padding: 12px; line-height: normal; display: block; overflow: auto; color: rgb(64, 64, 64);">$ docker logs dev-peer0.org2.example.com-mycc-1.0
04:30:45.947 [BCCSP_FACTORY] DEBU : Initialize BCCSP [SW]
ex02 Init
Aval = 100, Bval = 200

$ docker logs dev-peer0.org1.example.com-mycc-1.0
04:31:10.569 [BCCSP_FACTORY] DEBU : Initialize BCCSP [SW]
ex02 Invoke
Query Response:{"Name":"a","Amount":"100"}
ex02 Invoke
Aval = 90, Bval = 210

$ docker logs dev-peer1.org2.example.com-mycc-1.0
04:31:30.420 [BCCSP_FACTORY] DEBU : Initialize BCCSP [SW]
ex02 Invoke
Query Response:{"Name":"a","Amount":"90"}
</pre>

了解Docker Compose拓?fù)?/h2>

BYFN示例向我們提供了兩種Docker Compose文件,這兩種文件都是從擴(kuò)展的docker-compose-base.yaml(位于base 文件夾中)。我們的第一個(gè)風(fēng)格,docker-compose-cli.yaml為我們提供了一個(gè)CLI容器以及一個(gè)訂購(gòu)者和四個(gè)對(duì)等方。我們將此文件用于此頁(yè)面上的全部說(shuō)明。

注意

本節(jié)的其余部分介紹了為SDK設(shè)計(jì)的docker-compose文件。 有關(guān)運(yùn)行這些測(cè)試的詳細(xì)信息,請(qǐng)參考Node SDK倉(cāng)庫(kù)。

第二種風(fēng)味docker-compose-e2e.yaml構(gòu)造為使用Node.js SDK運(yùn)行端到端測(cè)試。除了可以使用SDK之外,它的主要區(qū)別還在于,F(xiàn)abric-ca服務(wù)器具有容器。因此,我們能夠?qū)EST調(diào)用發(fā)送到組織CA,以進(jìn)行用戶注冊(cè)和注冊(cè)。

如果要在docker-compose-e2e.yaml不先運(yùn)行byfn.sh腳本的情況下使用,那么我們將需要進(jìn)行四個(gè)小修改。我們需要指向本組織CA的私鑰。您可以在crypto-config文件夾中找到這些值。例如,要找到Org1的私鑰,我們將遵循以下路徑- crypto-config/peerOrganizations/org1.example.com/ca/。私鑰是一個(gè)長(zhǎng)哈希值,后跟_sk。Org2的路徑為- crypto-config/peerOrganizations/org2.example.com/ca/。

docker-compose-e2e.yaml更新中,ca0和ca1的FABRIC_CA_SERVER_TLS_KEYFILE變量。您還需要編輯命令中提供的路徑以啟動(dòng)ca服務(wù)器。您為每個(gè)CA容器兩次提供相同的私鑰。

使用CouchDB

可以將狀態(tài)數(shù)據(jù)庫(kù)從默認(rèn)(goleveldb)切換到CouchDB。CouchDB可以使用相同的鏈碼功能,但是,還具有對(duì)鏈碼數(shù)據(jù)建模為JSON的狀態(tài)數(shù)據(jù)庫(kù)數(shù)據(jù)內(nèi)容執(zhí)行豐富和復(fù)雜查詢的功能。

要使用CouchDB代替默認(rèn)數(shù)據(jù)庫(kù)(goleveldb),請(qǐng)遵循前面概述的用于生成工件的過(guò)程,但同時(shí)也要啟動(dòng)網(wǎng)絡(luò)傳遞docker-compose-couch.yaml

docker-compose -f docker-compose-cli.yaml -f docker-compose-couch.yaml up -d

chaincode_example02現(xiàn)在應(yīng)該可以在下面使用CouchDB了。

注意

如果您選擇實(shí)現(xiàn)fabric-couchdb容器端口到主機(jī)端口的映射,請(qǐng)確保您了解安全隱患。在開發(fā)環(huán)境中端口的映射使CouchDB REST API可用,并允許通過(guò)CouchDB Web界面(Fauxton)可視化數(shù)據(jù)庫(kù)。生產(chǎn)環(huán)境可能會(huì)避免實(shí)施端口映射,以限制外部對(duì)CouchDB容器的訪問(wèn)。

您可以使用上述步驟針對(duì)CouchDB狀態(tài)數(shù)據(jù)庫(kù)使用chaincode_example02鏈碼,但是,為了行使CouchDB查詢功能,您將需要使用鏈數(shù)據(jù)編碼為JSON的鏈碼(例如,marbles02)。您可以在目錄中找到marbles02鏈碼 fabric/examples/chaincode/go

我們將按照上述createandjoin一節(jié)中所述的相同過(guò)程來(lái)創(chuàng)建和加入渠道 。將同伴加入頻道后,請(qǐng)執(zhí)行以下步驟與marbles02鏈碼進(jìn)行交互:

  • 在以下位置安裝并實(shí)例化鏈碼peer0.org1.example.com
# be sure to modify the $CHANNEL_NAME variable accordingly for the instantiate command

peer chaincode install -n marbles -v 1.0 -p github.com/chaincode/marbles02/go
peer chaincode instantiate -o orderer.example.com:7050 --tls --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C $CHANNEL_NAME -n marbles -v 1.0 -c '{"Args":["init"]}' -P "OR ('Org1MSP.peer','Org2MSP.peer')"
  • 創(chuàng)建一些大理石并將其移動(dòng):
# be sure to modify the $CHANNEL_NAME variable accordingly

peer chaincode invoke -o orderer.example.com:7050 --tls --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C $CHANNEL_NAME -n marbles -c '{"Args":["initMarble","marble1","blue","35","tom"]}'
peer chaincode invoke -o orderer.example.com:7050 --tls --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C $CHANNEL_NAME -n marbles -c '{"Args":["initMarble","marble2","red","50","tom"]}'
peer chaincode invoke -o orderer.example.com:7050 --tls --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C $CHANNEL_NAME -n marbles -c '{"Args":["initMarble","marble3","blue","70","tom"]}'
peer chaincode invoke -o orderer.example.com:7050 --tls --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C $CHANNEL_NAME -n marbles -c '{"Args":["transferMarble","marble2","jerry"]}'
peer chaincode invoke -o orderer.example.com:7050 --tls --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C $CHANNEL_NAME -n marbles -c '{"Args":["transferMarblesBasedOnColor","blue","jerry"]}'
peer chaincode invoke -o orderer.example.com:7050 --tls --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C $CHANNEL_NAME -n marbles -c '{"Args":["delete","marble1"]}'
  • 如果選擇在docker-compose中映射CouchDB端口,則現(xiàn)在可以通過(guò)打開瀏覽器并導(dǎo)航至以下URL,通過(guò)CouchDB Web界面(Fauxton)查看狀態(tài)數(shù)據(jù)庫(kù):

    http://localhost:5984/_utils

您應(yīng)該看到一個(gè)名為mychannel(或您唯一的頻道名稱)的數(shù)據(jù)庫(kù)以及其中的文檔。

注意

對(duì)于以下命令,請(qǐng)確保適當(dāng)?shù)馗? CHANNEL_NAME變量。

您可以從CLI運(yùn)行常規(guī)查詢(例如閱讀marble2):

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

輸出應(yīng)顯示以下內(nèi)容的詳細(xì)信息marble2

Query Result: {"color":"red","docType":"marble","name":"marble2","owner":"jerry","size":50}

您可以檢索特定大理石的歷史記錄-例如marble1

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

輸出應(yīng)顯示以下交易marble1

Query Result: [{"TxId":"1c3d3caf124c89f91a4c0f353723ac736c58155325f02890adebaa15e16e6464", "Value":{"docType":"marble","name":"marble1","color":"blue","size":35,"owner":"tom"}},{"TxId":"755d55c281889eaeebf405586f9e25d71d36eb3d35420af833a20a2f53a3eefd", "Value":{"docType":"marble","name":"marble1","color":"blue","size":35,"owner":"jerry"}},{"TxId":"819451032d813dde6247f85e56a89262555e04f14788ee33e28b232eef36d98f", "Value":}]

您還可以對(duì)數(shù)據(jù)內(nèi)容執(zhí)行豐富的查詢,例如按所有者查詢大理石字段jerry

peer chaincode query -C $CHANNEL_NAME -n marbles -c '{"Args":["queryMarblesByOwner","jerry"]}'

輸出應(yīng)顯示以下所有的兩個(gè)彈珠jerry

Query Result: [{"Key":"marble2", "Record":{"color":"red","docType":"marble","name":"marble2","owner":"jerry","size":50}},{"Key":"marble3", "Record":{"color":"blue","docType":"marble","name":"marble3","owner":"jerry","size":70}}]

為什么選擇CouchDB

CouchDB是一種NoSQL解決方案。它是一個(gè)面向文檔的數(shù)據(jù)庫(kù),其中文檔字段存儲(chǔ)為鍵值映射。字段可以是簡(jiǎn)單的鍵值對(duì),列表或映射。除了LevelDB支持的鍵/復(fù)合鍵/鍵范圍查詢外,CouchDB還支持完整的數(shù)據(jù)豐富查詢功能,例如針對(duì)整個(gè)區(qū)塊鏈數(shù)據(jù)的非鍵查詢,因?yàn)槠鋽?shù)據(jù)內(nèi)容以JSON格式存儲(chǔ),并且完全可查詢的。因此,CouchDB可以滿足LevelDB不支持的許多用例的鏈碼,審計(jì),報(bào)告要求。

CouchDB還可以增強(qiáng)區(qū)塊鏈中合規(guī)性和數(shù)據(jù)保護(hù)的安全性。因?yàn)樗軌蛲ㄟ^(guò)過(guò)濾和屏蔽事務(wù)中的各個(gè)屬性來(lái)實(shí)現(xiàn)字段級(jí)安全性,并且僅在需要時(shí)才授權(quán)只讀權(quán)限。

另外,CouchDB屬于CAP定理的AP類型(可用性和分區(qū)容差)。它使用帶有的主-主復(fù)制模型。在CouchDB文檔的“ 最終一致性”頁(yè)面上可以找到更多信息 。但是,在每個(gè)結(jié)構(gòu)同位體下,沒有數(shù)據(jù)庫(kù)副本,可以保證對(duì)數(shù)據(jù)庫(kù)的寫入是一致且持久的(不是)。Eventual ConsistencyEventual Consistency

CouchDB是第一個(gè)用于Fabric的外部可插入狀態(tài)數(shù)據(jù)庫(kù),并且可能并且應(yīng)該有其他外部數(shù)據(jù)庫(kù)選項(xiàng)。例如,IBM為其區(qū)塊鏈啟用關(guān)系數(shù)據(jù)庫(kù)。并且可能還需要CP類型(一致性和分區(qū)容差)數(shù)據(jù)庫(kù),以便在不保證應(yīng)用程序級(jí)別的情況下實(shí)現(xiàn)數(shù)據(jù)一致性。

關(guān)于數(shù)據(jù)持久性的說(shuō)明

如果需要在對(duì)等容器或CouchDB容器上保持?jǐn)?shù)據(jù)持久性,一種選擇是將docker-host中的目錄掛載到容器中的相關(guān)目錄中。例如,您可以在docker-compose-base.yaml文件的對(duì)等容器規(guī)范中添加以下兩行:

volumes:
 - /var/hyperledger/peer0:/var/hyperledger/production

對(duì)于CouchDB容器,您可以在CouchDB容器規(guī)范中添加以下兩行:

volumes:
 - /var/hyperledger/couchdb0:/opt/couchdb/data

故障排除

  • 始終重新啟動(dòng)網(wǎng)絡(luò)。使用以下命令刪除工件,加密,容器和鏈碼圖像:
./byfn.sh down
注意

你**會(huì)**看到錯(cuò)誤,如果你不刪除舊容器和圖像。
  • 如果您看到Docker錯(cuò)誤,請(qǐng)首先檢查您的Docker版本(Prerequisites),然后嘗試重新啟動(dòng)Docker進(jìn)程。Docker的問(wèn)題通常無(wú)法立即識(shí)別。例如,您可能會(huì)看到由于無(wú)法訪問(wèn)安裝在容器中的加密材料而導(dǎo)致的錯(cuò)誤。

    如果它們?nèi)匀淮嬖?,?qǐng)刪除您的圖像并從頭開始:

    docker rm -f $(docker ps -aq)
    docker rmi -f $(docker images -q)
  • 如果在創(chuàng)建,實(shí)例化,調(diào)用或查詢命令時(shí)看到錯(cuò)誤,請(qǐng)確保已正確更新了通道名稱和鏈碼名稱。提供的示例命令中包含占位符值。

  • 如果看到以下錯(cuò)誤:

Error: Error endorsing chaincode: rpc error: code = 2 desc = Error installing chaincode code mycc:1.0(chaincode /var/hyperledger/production/chaincodes/mycc.1.0 exits)
您可能具有先前運(yùn)行的鏈碼圖像(例如`dev-peer1.org2.example.com-mycc-1.0`或 `dev-peer0.org1.example.com-mycc-1.0`)。刪除它們,然后重試。
docker rmi -f $(docker images | grep peer[0-9]-peer[0-9] | awk '{print $3}')
  • 如果您看到類似以下內(nèi)容的內(nèi)容:
    Error connecting: rpc error: code = 14 desc = grpc: RPC failed fast due to transport failure
    Error: rpc error: code = 14 desc = grpc: RPC failed fast due to transport failure
確保針對(duì)重新標(biāo)記為“最新”的“ 1.0.0”圖像運(yùn)行網(wǎng)絡(luò)。
  • 如果看到以下錯(cuò)誤:
    [configtx/tool/localconfig] Load -> CRIT 002 Error reading configuration: Unsupported Config Type ""
    panic: Error reading configuration: Unsupported Config Type ""
然后,您沒有`FABRIC_CFG_PATH`正確設(shè)置環(huán)境變量。configtxgen工具需要此變量才能找到configtx.yaml。返回并執(zhí)行一個(gè),然后重新創(chuàng)建您的通道工件。`export FABRIC_CFG_PATH=$PWD`
  • 要清理網(wǎng)絡(luò),請(qǐng)使用以下down選項(xiàng):
./byfn.sh down
  • 如果看到錯(cuò)誤消息指出您仍然具有“活動(dòng)端點(diǎn)”,請(qǐng)修剪Docker網(wǎng)絡(luò)。這將清除以前的網(wǎng)絡(luò),并為您提供一個(gè)全新的環(huán)境:
docker network prune
您將看到以下消息:
   WARNING! This will remove all networks not used by at least one container.
    Are you sure you want to continue? [y/N]
選擇`y`。
  • 如果看到類似于以下內(nèi)容的錯(cuò)誤:
/bin/bash: ./scripts/script.sh: /bin/bash^M: bad interpreter: No such file or directory
確保有問(wèn)題的文件(在本示例中為**script.sh**)以Unix格式編碼。這很可能是由于未在Git配置中將設(shè)置`core.autocrlf`為引起的 `false`(請(qǐng)參閱 [Windows Extras](https://hyperledger-fabric.readthedocs.io/en/release-1.4/prereqs.html#windows-extras))。有幾種解決方法。例如,如果您有權(quán)訪問(wèn)vim編輯器,請(qǐng)打開文件:
vim ./fabric-samples/first-network/scripts/script.sh
然后通過(guò)執(zhí)行以下vim命令來(lái)更改其格式:
:set ff=unix

注意

如果仍然看到錯(cuò)誤,請(qǐng)?jiān)?a target="_blank">Hyperledger Rocket Chat 或StackOverflow結(jié)構(gòu)問(wèn)題通道上 共享日志 。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容