建立您的第一個(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.js和Java 鏈碼。如果您想使用節(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_SPEC在cli容器被設(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ì)等組織(Org1&Org2),每個(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.com&peer0.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)行工具
您可以使用configtxgen和cryptogen命令手動(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, "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);"># 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.com而peer1.org1.example.com屬于ORG1;peer0.org2.example.com而peer1.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.tx和Org2MSPanchors.tx工件以及渠道名稱一起傳遞給訂購(gòu)服務(wù)。 - 一個(gè)chaincode - chaincode_example02 -安裝在
peer0.org1.example.com與peer0.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)題通道上 共享日志 。