前言
官方英文:Building Your First Network
感謝中文翻譯!不然這么長的英文以及各種名詞解釋實在頭疼。有一些和官方英文不一樣的地方我已經(jīng)按官方英文進行了補充和修正,并且盡量簡化了語言,因為有些翻譯過來有點拗口。如果希望看完整及原汁原味的文檔,推薦看官方英文文檔。
本文基于Mac OS以及Hyperledger Fabric 1.1.0。
Building Your First Network
構(gòu)建你的第一個網(wǎng)絡(BYFN)場景提供了由兩個組織組成的示例Hyperledger Fabric網(wǎng)絡,每個組織持有2個peer節(jié)點,以及一個“solo”排序服務。
1.1. 安裝預置環(huán)境
在我們開始之前,如果你還沒有這樣做,你可能需要檢查一下在你開發(fā)區(qū)塊鏈應用程序或者Hyperledger Fabric的平臺上是否已經(jīng)安裝了預置環(huán)境。
你還需要下載并安裝Hyperledger Fabric Samples。你會注意到fabric-samples文件夾中包含了許多示例。我們將使用first-network這個例子?,F(xiàn)在讓我們打開這個子目錄。
cd fabric-samples/first-network
注意:本文檔中提供的命令必須運行在
fabric-samples的子目錄fabric-network中。如果你選擇從其他位置運行命令,提供的一些腳本將無法找到對應的二進制。
1.2. 想要現(xiàn)在運行嗎?
我們提供一個完全注釋的腳本byfn.sh,利用這些Docker鏡像可以快速引導一個由4個代表2個不同組織的peer節(jié)點以及一個排序服務節(jié)點的Hyperledger fabric網(wǎng)絡。它還將啟動一個容器來運行一個將peer節(jié)點加入channel、部署實例化鏈碼服務以及驅(qū)動已經(jīng)部署的鏈碼執(zhí)行交易的腳本。
以下是該byfn.sh腳本的幫助文檔:
./byfn.sh --help
Usage:
byfn.sh up|down|restart|generate [-c <channel name>] [-t <timeout>] [-d <delay>] [-f <docker-compose-file>] [-s <dbtype>]
byfn.sh -h|--help (print this message)
-m <mode> - one of 'up', 'down', 'restart' or 'generate'
- '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
-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) or node
-a - don't ask for confirmation before proceeding
Typically, one would first generate the required certificates and
genesis block, then bring up the network. e.g.:
byfn.sh -m generate -c mychannel
byfn.sh -m up -c mychannel -s couchdb
如果你選擇不提供channel名稱,則腳本將使用默認名稱mychannel。CLI超時參數(shù)(用-t標志指定)是一個可選值;如果你選擇不設置它,那么CLI容器將會在腳本執(zhí)行完之后退出。
1.3. 生成網(wǎng)絡
準備好了嗎?好吧!執(zhí)行以下命令。
yuyangdeMacBook-Pro:~ yuyang$ cd /Users/yuyang/fabric-sample/fabric-samples/first-network
yuyangdeMacBook-Pro:first-network yuyang$ ./byfn.sh -m generate
命令行會提示將會發(fā)生什么。當提示yes/no時,輸入y或回車鍵來執(zhí)行描述的動作。
Generating certs and genesis block for with channel 'mychannel' and CLI timeout of '10' seconds and CLI delay of '3' seconds
Continue? [Y/n] y
proceeding ...
/Users/yuyang/fabric-sample/fabric-samples/first-network/../bin/cryptogen
##########################################################
##### Generate certificates using cryptogen tool #########
##########################################################
+ cryptogen generate --config=./crypto-config.yaml
org1.example.com
org2.example.com
+ set +x
/Users/yuyang/fabric-sample/fabric-samples/first-network/../bin/configtxgen
##########################################################
######### Generating Orderer Genesis block ##############
##########################################################
+ configtxgen -profile TwoOrgsOrdererGenesis -outputBlock ./channel-artifacts/genesis.block
2018-03-17 21:56:10.295 CST [common/tools/configtxgen] main -> INFO 001 Loading configuration
2018-03-17 21:56:10.307 CST [msp] getMspConfig -> INFO 002 Loading NodeOUs
2018-03-17 21:56:10.307 CST [msp] getMspConfig -> INFO 003 Loading NodeOUs
2018-03-17 21:56:10.307 CST [common/tools/configtxgen] doOutputBlock -> INFO 004 Generating genesis block
2018-03-17 21:56:10.308 CST [common/tools/configtxgen] doOutputBlock -> INFO 005 Writing genesis block
+ set +x
#################################################################
### Generating channel configuration transaction 'channel.tx' ###
#################################################################
+ configtxgen -profile TwoOrgsChannel -outputCreateChannelTx ./channel-artifacts/channel.tx -channelID mychannel
2018-03-17 21:56:10.328 CST [common/tools/configtxgen] main -> INFO 001 Loading configuration
2018-03-17 21:56:10.339 CST [common/tools/configtxgen] doOutputChannelCreateTx -> INFO 002 Generating new channel configtx
2018-03-17 21:56:10.340 CST [msp] getMspConfig -> INFO 003 Loading NodeOUs
2018-03-17 21:56:10.341 CST [msp] getMspConfig -> INFO 004 Loading NodeOUs
2018-03-17 21:56:10.366 CST [common/tools/configtxgen] doOutputChannelCreateTx -> INFO 005 Writing new channel tx
+ set +x
#################################################################
####### Generating anchor peer update for Org1MSP ##########
#################################################################
+ configtxgen -profile TwoOrgsChannel -outputAnchorPeersUpdate ./channel-artifacts/Org1MSPanchors.tx -channelID mychannel -asOrg Org1MSP
2018-03-17 21:56:10.385 CST [common/tools/configtxgen] main -> INFO 001 Loading configuration
2018-03-17 21:56:10.393 CST [common/tools/configtxgen] doOutputAnchorPeersUpdate -> INFO 002 Generating anchor peer update
2018-03-17 21:56:10.393 CST [common/tools/configtxgen] doOutputAnchorPeersUpdate -> INFO 003 Writing anchor peer update
+ set +x
#################################################################
####### Generating anchor peer update for Org2MSP ##########
#################################################################
+ configtxgen -profile TwoOrgsChannel -outputAnchorPeersUpdate ./channel-artifacts/Org2MSPanchors.tx -channelID mychannel -asOrg Org2MSP
2018-03-17 21:56:10.413 CST [common/tools/configtxgen] main -> INFO 001 Loading configuration
2018-03-17 21:56:10.421 CST [common/tools/configtxgen] doOutputAnchorPeersUpdate -> INFO 002 Generating anchor peer update
2018-03-17 21:56:10.421 CST [common/tools/configtxgen] doOutputAnchorPeersUpdate -> INFO 003 Writing anchor peer update
+ set +x
第一步生成我們各種網(wǎng)絡實體的所有證書和密鑰,genesis block用于引導排序服務,以及配置Channel所需要的一組交易配置集合。
1.4. 啟動網(wǎng)絡
接下來,你可以使用以下命令來啟動整個網(wǎng)絡。
./byfn.sh -m up
上面的指令會編譯Golang智能合約鏡像并且啟動對應的容器。Go語言是默認的鏈碼語言,當然這里也支持 Node.js智能合約。如果你希望以node形式的智能合約完成教程,可以將剛才的指令替換為:
# 使用 -l 標志指定智能合約語言
# 不指定默認使用Golang
./byfn.sh -m up -l node
點擊 Hyperledger Fabric Shim來查看更多關(guān)于使用node.js 編寫智能合約的API文檔。
再次提示是否繼續(xù),輸入y或者鍵入回車:
yuyangdeMacBook-Pro:first-network yuyang$ ./byfn.sh -m up
Starting with channel 'mychannel' and CLI timeout of '10' seconds and CLI delay of '3' seconds
Continue? [Y/n] y
proceeding ...
2018-03-17 14:10:17.541 UTC [main] main -> INFO 001 Exiting.....
LOCAL_VERSION=1.1.0-rc1
DOCKER_IMAGE_VERSION=1.1.0-rc1
Creating network "net_byfn" with the default driver
Creating volume "net_peer0.org2.example.com" with default driver
Creating volume "net_peer1.org2.example.com" with default driver
Creating volume "net_peer1.org1.example.com" with default driver
Creating volume "net_peer0.org1.example.com" with default driver
Creating peer1.org2.example.com ... done
Creating cli ... done
Creating peer0.org1.example.com ...
Creating orderer.example.com ...
Creating peer0.org2.example.com ...
Creating peer1.org2.example.com ...
Creating cli ...
____ _____ _ ____ _____
/ ___| |_ _| / \ | _ \ |_ _|
\___ \ | | / _ \ | |_) | | |
___) | | | / ___ \ | _ < | |
|____/ |_| /_/ \_\ |_| \_\ |_|
Build your first network (BYFN) end-to-end test
Channel name : mychannel
Creating channel...
日志將從這里繼續(xù)。然后啟動所有容器,驅(qū)動一個端到端的應用場景。成功以后,在終端窗口中會報告以下內(nèi)容:
Query Result: 90
2018-03-17 14:11:33.653 UTC [main] main -> INFO 003 Exiting.....
===================== Query on peer1.org2 on channel 'mychannel' is successful =====================
========= All GOOD, BYFN execution completed ===========
_____ _ _ ____
| ____| | \ | | | _ \
| _| | \| | | | | |
| |___ | |\ | | |_| |
|_____| |_| \_| |____/
你可以滾動這些日志去查看各種交易。如果你沒有獲得這個結(jié)果,請移步疑難解答部分Troubleshooting,看看我們是否可以幫助你發(fā)現(xiàn)問題。
1.5. 關(guān)閉網(wǎng)絡
最后,讓我們把它全部停下來,這樣我們可以一步一步地探索網(wǎng)絡設置。以下操作將關(guān)閉你的容器,移除加密材料和4個配置信息,并且從Docker倉庫刪除智能合約鏡像。你將再一次被提示是否繼續(xù),回答y或者鍵入回車:
yuyangdeMacBook-Pro:first-network yuyang$ ./byfn.sh -m down
如果你想了解關(guān)于底層工具和引導材料相關(guān)的更多信息,請繼續(xù)閱讀。在接下來的章節(jié)中,我們將瀏覽構(gòu)建功能齊全的Hyperledger fabric網(wǎng)絡的各種要求和步驟。
在上面的步驟中,默認的
cli容器日志輸出等級CORE_LOGGING_LEVEL是INFO。你可以在first-network目錄中的docker-compose-cli.yaml文件中進行修改。
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
#- CORE_LOGGING_LEVEL=DEBUG
- CORE_LOGGING_LEVEL=INFO
1.6. 加密原理
我們將使用cryptogen工具為我們生成各種網(wǎng)絡實體的加密材料(x509證書)。這些證書是身份的代表,它們允許在我們的網(wǎng)絡實體進行交流和交易時進行簽名/驗證身份驗證。
Fabric中有兩種類型的公私鑰和證書,一種是給節(jié)點之前通訊安全而準備的TLS證書,另一種是用戶登錄和權(quán)限控制的用戶證書。這些證書本來應該是由CA來頒發(fā),但是我們這里是測試環(huán)境,并沒有啟用CA節(jié)點,所以Fabric幫我們提供了一個工具:cryptogen。
1.6.1. 它是如何工作的?
Cryptogen使用crypto-config.yaml,并允許我們?yōu)榻M織和屬于這些組織的組件生成一組證書和密鑰。每個組織都配置了唯一的根證書(ca-cert),它將特定組件(peers和orders)綁定到該組織。通過為每一個組織分配唯一的CA證書,我們正在模仿一個典型的網(wǎng)絡,這個網(wǎng)絡中的成員將使用自己的證書頒發(fā)機構(gòu)。Hyperledger Fabric中的交易和通信是通過存儲在keystore中的實體的私鑰簽名,然后通過公鑰手段進行驗證(signcerts)。
你將注意到在這個文件里有一個count變量。我們將使用它來指定每個組織中peer的數(shù)量;在我們的例子中,每個組織有兩個peer。我們現(xiàn)在不會深入研究x.509證書和公鑰基礎設施的細節(jié)。如果你有興趣,你可以在自己的時間細讀這些主題。
在運行該工具之前,讓我們快速瀏覽一下這段代碼crypto-config.yaml。特別注意在OrdererOrgs頭下的Name,Domain和Specs參數(shù):
OrdererOrgs:
# ---------------------------------------------------------------------------
# Orderer
# ---------------------------------------------------------------------------
- Name: Orderer
Domain: example.com
# ---------------------------------------------------------------------------
# "Specs" - See PeerOrgs below for complete description
# ---------------------------------------------------------------------------
Specs:
- Hostname: orderer
# ---------------------------------------------------------------------------
# "PeerOrgs" - Definition of organizations managing peer nodes
# ---------------------------------------------------------------------------
PeerOrgs:
# ---------------------------------------------------------------------------
# Org1
# ---------------------------------------------------------------------------
- Name: Org1
Domain: org1.example.com
EnableNodeOUs: true
網(wǎng)絡實體的命名約定如下:”{{.Hostname}}.{{.Domain}}”。所以使用我們的排序節(jié)點作為參考點,它與Order的MSP ID相關(guān)聯(lián)。該文件包含了有關(guān)定義和語法的大量文檔。你還可以參考Membership Service Providers(MSP),以便更深入地了解MSP。
我們運行cryptogen工具,生成的證書和密鑰將被保存到名為crypto-config的文件夾中。
1.7. 配置工作說明
configtxgen tool用于創(chuàng)建4個配置工作:
order的
genesis block創(chuàng)世區(qū)塊channel的
channel configuration transaction以及兩個
anchor peer transactions一個對應一個Peer組織
有關(guān)此工具的完整說明,請參閱Channel Configuration(configtxgen)。
order block是一個ordering service的創(chuàng)世區(qū)塊,channel transaction配置文件在Channel創(chuàng)建的時侯廣播給order。anchor peer transactions,正如名稱所示,指定了每個組織在此channel上的錨節(jié)點。
1.7.1. 它是如何工作的?
Configtxgen使用一個包含示例網(wǎng)絡的configtx.yaml文件。有3個成員-一個排序服務組織OrdererOrg以及兩個節(jié)點組織(Org1&Org2),每個組織管理和持有2個peer節(jié)點。該文件還指定了一個SampleConsortium的聯(lián)盟,由上述2個節(jié)點組織構(gòu)成。 請?zhí)貏e注意此文件頂部的”Profiles”部分。你會注意到我們有兩個獨特的標題。一個是orderer的創(chuàng)世區(qū)塊-TwoOrgsOrdererGenesis-另一個是針對channel的TwoOrgsChannel。
這些標題很重要,因為在我們創(chuàng)建我們的工作的時侯它們將作為傳遞的參數(shù)。
注意:請注意我們的
SampleConsortium在系統(tǒng)級別的配置文件中定義,然后由channel級別配置文件引用。
此文件還包含兩個值得注意的附加規(guī)格。首先,我們?yōu)槊總€組織指定了錨點節(jié)點(peer0.org1.example.com和peer0.org2.example.com)。其次,我們?yōu)槊總€成員指定MSP文件夾,用來存儲每個組織在orderer genesis block中指定的根證書。這是一個關(guān)鍵的概念?,F(xiàn)在任意和ordering service通信的網(wǎng)絡實體都可以對其數(shù)字簽名進行驗證。
這個文件里面配置了由2個Org參與的Orderer共識配置TwoOrgsOrdererGenesis,以及由2個Org參與的Channel配置:TwoOrgsChannel。Orderer可以設置共識的算法是Solo還是Kafka,以及共識時區(qū)塊大小,超時時間等,我們使用默認值即可,不用更改。而Peer節(jié)點的配置包含了MSP的配置,錨節(jié)點的配置。如果我們有更多的Org,或者有更多的Channel,那么就可以根據(jù)模板進行對應的修改。
1.8. 生成公私鑰證書和創(chuàng)世區(qū)塊
你可以用configtxgen和cryptogen命令來手動生成證書/密鑰和各種配置文件。或者,你可以嘗試使用byfn.sh腳本來完成你的目標。
1.8.1. 手動生成
必要的話,你可以參考byfn.sh腳本中的generateCerts函數(shù)去生成相關(guān)定義在crypto-config.yaml文件中用于你的網(wǎng)絡配置的相關(guān)證書。然而,為了方便起見,我們也將在此提供參考。
首先,我們來運行cryptogen這個工具。我們的二進制文件在bin目錄中,所以我們需要提供工具所在的相對路徑。
yuyangdeMacBook-Pro:first-network yuyang$ ../bin/cryptogen generate --config=./crypto-config.yaml
你會看到以下內(nèi)容出現(xiàn)在命令行中:
org1.example.com
org2.example.com
證書和秘鑰(也就是MSP材料)會生成在位于first-network文件夾下的crypto-config文件夾中。
接下來,我們需要告訴configtxgen工具去哪里獲取configtx.yaml文件。我們將告訴它在我們當前的工作目錄獲取。
我們需要設置一個環(huán)境變量來告訴configtxgen哪里去尋找configtx.yaml。
yuyangdeMacBook-Pro:first-network yuyang$ export FABRIC_CFG_PATH=$PWD
然后,我們將調(diào)用configtxgen工具去創(chuàng)建orderer genesis block:
yuyangdeMacBook-Pro:first-network yuyang$ ../bin/configtxgen -profile TwoOrgsOrdererGenesis -outputBlock ./channel-artifacts/genesis.block
你會看到以下內(nèi)容出現(xiàn)在命令行中:
2018-03-18 12:31:44.111 CST [common/tools/configtxgen] main -> INFO 001 Loading configuration
2018-03-18 12:31:44.123 CST [msp] getMspConfig -> INFO 002 Loading NodeOUs
2018-03-18 12:31:44.123 CST [msp] getMspConfig -> INFO 003 Loading NodeOUs
2018-03-18 12:31:44.123 CST [common/tools/configtxgen] doOutputBlock -> INFO 004 Generating genesis block
2018-03-18 12:31:44.124 CST [common/tools/configtxgen] doOutputBlock -> INFO 005 Writing genesis block
注意:剛才的指令會將生成的文件
genesis.block放置在當前目錄下的channel-artifacts文件夾中。
1.8.2. 創(chuàng)建channel transaction配置
接下來,我們需要創(chuàng)建channel transaction配置。請確保替換$CHANNEL_NAME或者將CHANNEL_NAME設置為整個說明中可以使用的環(huán)境變量:
yuyangdeMacBook-Pro:first-network yuyang$ export CHANNEL_NAME=mychannel && ../bin/configtxgen -profile TwoOrgsChannel -outputCreateChannelTx ./channel-artifacts/channel.tx -channelID $CHANNEL_NAME
你會看到以下內(nèi)容出現(xiàn)在命令行中:
2018-03-18 12:42:33.661 CST [common/tools/configtxgen] main -> INFO 001 Loading configuration
2018-03-18 12:42:33.669 CST [common/tools/configtxgen] doOutputChannelCreateTx -> INFO 002 Generating new channel configtx
2018-03-18 12:42:33.669 CST [msp] getMspConfig -> INFO 003 Loading NodeOUs
2018-03-18 12:42:33.670 CST [msp] getMspConfig -> INFO 004 Loading NodeOUs
2018-03-18 12:42:33.702 CST [common/tools/configtxgen] doOutputChannelCreateTx -> INFO 005 Writing new channel tx
注意:剛才的指令會將生成的文件
channel.tx放置在當前目錄下的channel-artifacts文件夾中。
接下來,我們將在正在構(gòu)建的通道上定義Org1的anchor peer。請再次確認$CHANNEL_NAME已被替換或者為以下命令設置了環(huán)境變量:
yuyangdeMacBook-Pro:first-network yuyang$ ../bin/configtxgen -profile TwoOrgsChannel -outputAnchorPeersUpdate ./channel-artifacts/Org1MSPanchors.tx -channelID $CHANNEL_NAME -asOrg Org1MSP
現(xiàn)在,我們將在同一個通道定義Org2的anchor peer:
yuyangdeMacBook-Pro:first-network yuyang$ ../bin/configtxgen -profile TwoOrgsChannel -outputAnchorPeersUpdate ./channel-artifacts/Org2MSPanchors.tx -channelID $CHANNEL_NAME -asOrg Org2MSP
注意:剛才的指令會將生成的文件
Org1MSPanchors.tx和Org2MSPanchors.tx放置在當前目錄下的channel-artifacts文件夾中。
1.9. 啟動網(wǎng)絡
我們將利用docker-compose腳本來啟動我們的區(qū)塊鏈網(wǎng)絡。docker-compose文件會利用我們之前下載的鏡像,并用以前生成的genesis.block來引導orderer。
我們想手動執(zhí)行命令,以便說明每個調(diào)用的語法和功能。
首先啟動你的網(wǎng)絡:
yuyangdeMacBook-Pro:first-network yuyang$ docker-compose -f docker-compose-cli.yaml up -d
Creating network "net_byfn" with the default driver
Creating volume "net_peer0.org2.example.com" with default driver
Creating volume "net_peer1.org2.example.com" with default driver
Creating volume "net_peer1.org1.example.com" with default driver
Creating volume "net_peer0.org1.example.com" with default driver
Creating peer0.org2.example.com ... done
Creating cli ... done
Creating peer0.org1.example.com ...
Creating peer0.org2.example.com ...
Creating orderer.example.com ...
Creating peer1.org2.example.com ...
Creating cli ...
如果要實時查看你的區(qū)塊鏈網(wǎng)絡的日志,請不要提供-d標志。如果你需要日志流,你需要打開第二個終端來執(zhí)行CLI命令。
CLI容器處于空閑狀態(tài)時只會會停留1000秒。你可以使用以下命令再次啟動它:
docker start cli
1.9.1. 環(huán)境變量
下面是peer0.org1.example.com的環(huán)境變量。每當在CLI命令中需要執(zhí)行節(jié)點操作時,都要確認當前處于哪個節(jié)點下。如果要切換至peer0.org1節(jié)點,就需要將其環(huán)境變量復制到命令行中執(zhí)行。同理,如果切換到其他節(jié)點,需要對應的修改環(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
1.9.2. 創(chuàng)建&加入信道
回憶在之前的1.8.2. 創(chuàng)建channel transaction配置,我們使用configtxgen工具創(chuàng)建channel transaction配置 。你可以重復使用相同或不同的configtx.yaml文件,在你的網(wǎng)絡創(chuàng)建其他的信道。
我們將使用docker exec命令進入CLI容器:
yuyangdeMacBook-Pro:first-network yuyang$ docker exec -it cli bash
如果成功,你將看到下列信息:
root@cfbda07a993d:/opt/gopath/src/github.com/hyperledger/fabric/peer#
我們使用-c標志指定channel的名字,-f標志指定channel配置文件。在這個例子中它是channel.tx,當然你也可以使用不同的名稱,掛載你自己的channel配置。再一次,我們將在CLI容器里設置了CHANNEL_NAME環(huán)境變量,所以不需要明確傳遞這個參數(shù)。
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
注意:
-- cafile會作為命令的一部分。這是orderer的root cert的本地路徑,允許我們?nèi)ヲ炞CTLS握手。
此命令返回一個創(chuàng)世區(qū)塊-<channel-ID.block>-我們將使用它加入信道。它包含了channel.tx中的配置信息。如果你沒有修改過channel.tx文件中默認的通道名稱,上面的命令會返回mychannel.block。
2018-03-19 05:15:15.385 UTC [channelCmd] InitCmdFactory -> INFO 001 Endorser and orderer connections initialized
2018-03-19 05:15:15.419 UTC [channelCmd] InitCmdFactory -> INFO 002 Endorser and orderer connections initialized
2018-03-19 05:15:15.624 UTC [main] main -> INFO 003 Exiting.....
注意:這里我的返回信息并沒有區(qū)塊
mychannel.block,而是INFO 003 Exiting.....,是直接退出了。因為我看的官方文檔和網(wǎng)上其他人寫的示例都是返回了區(qū)塊信息,所以我以為我這里出問題了,然后想了很多辦法查了很多資料,重來了很多次都不行。接著我發(fā)現(xiàn)之前官方寫的腳本byfn.sh運行是沒有問題的,所以我試著再次運行,發(fā)現(xiàn)它在創(chuàng)建channel的時候也是INFO 003 Exiting.....,應該是成功了的。如果有朋友有更好的解釋,麻煩留言告知,謝謝!
另外這里有一個方法可以查看容器啟動后docker-compose -f docker-compose-cli.yaml up -d的狀態(tài):
yuyangdeMacBook-Pro:first-network yuyang$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
45b3f41ae42f hyperledger/fabric-tools:latest "/bin/bash" 20 seconds ago Up 21 seconds cli
26dadcb90749 hyperledger/fabric-peer:latest "peer node start" 22 seconds ago Up 22 seconds 0.0.0.0:7051->7051/tcp, 0.0.0.0:7053->7053/tcp peer0.org1.example.com
053b317fc840 hyperledger/fabric-peer:latest "peer node start" 22 seconds ago Up 22 seconds 0.0.0.0:8051->7051/tcp, 0.0.0.0:8053->7053/tcp peer1.org1.example.com
0622660b60cd hyperledger/fabric-peer:latest "peer node start" 22 seconds ago Up 23 seconds 0.0.0.0:10051->7051/tcp, 0.0.0.0:10053->7053/tcp peer1.org2.example.com
5b6d636ab4ed hyperledger/fabric-peer:latest "peer node start" 22 seconds ago Up 23 seconds 0.0.0.0:9051->7051/tcp, 0.0.0.0:9053->7053/tcp peer0.org2.example.com
9c4da795db8c hyperledger/fabric-orderer:latest "orderer" 22 seconds ago Up 23 seconds 0.0.0.0:7050->7050/tcp orderer.example.com
可以看到1Orderer+4Peer+1CLI都啟動了。
現(xiàn)在讓我們將peer0.org1加入頻道。
# By default, this joins ``peer0.org1.example.com`` only
# the <channel-ID.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
root@45b3f41ae42f:/opt/gopath/src/github.com/hyperledger/fabric/peer# peer channel join -b mychannel.block
2018-03-19 08:19:55.355 UTC [channelCmd] InitCmdFactory -> INFO 001 Endorser and orderer connections initialized
2018-03-19 08:19:55.477 UTC [channelCmd] executeJoin -> INFO 002 Successfully submitted proposal to join channel
2018-03-19 08:19:55.477 UTC [main] main -> INFO 003 Exiting.....
我們可以通過修改上面提到的四個環(huán)境變量來將其他的節(jié)點加入信道。
加入peer1.org1:
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=peer1.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/peer1.org1.example.com/tls/ca.crt
peer channel join -b mychannel.block
加入peer0.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:7051
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
加入peer1.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:7051
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
1.9.3. 更新錨節(jié)點
由于我們在剛才的步驟中最后加入的節(jié)點是peer1.org2,所以執(zhí)行完成后我們的命令行現(xiàn)在處于peer1.org2下。而現(xiàn)在我們需要為Org1設置錨節(jié)點peer0.org1,所以命令行需要先切回到peer0.org1:
設置當前操作節(jié)點為peer0.org1
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
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
然后更新Org1錨節(jié)點為peer0.org1:
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
2018-03-19 09:00:21.829 UTC [channelCmd] InitCmdFactory -> INFO 001 Endorser and orderer connections initialized
2018-03-19 09:00:21.846 UTC [channelCmd] update -> INFO 002 Successfully submitted channel update
2018-03-19 09:00:21.846 UTC [main] main -> INFO 003 Exiting.....
接下來為Org2設置錨節(jié)點peer0.org2
設置當前操作節(jié)點為peer0.org2
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
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:7051
然后更新Org2錨節(jié)點為peer0.org2:
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
2018-03-19 09:05:58.149 UTC [channelCmd] InitCmdFactory -> INFO 001 Endorser and orderer connections initialized
2018-03-19 09:05:58.164 UTC [channelCmd] update -> INFO 002 Successfully submitted channel update
2018-03-19 09:05:58.164 UTC [main] main -> INFO 003 Exiting.....
1.9.4. 安裝和實例化鏈碼
我們將利用一個現(xiàn)有的簡單鏈碼。要學習如何編寫自己的鏈碼,請參考鏈碼服務開發(fā)指南
應用程序和區(qū)塊鏈賬本會通過chaincode相互影響。因此,我們需要在每個會執(zhí)行以及背書我們交易的peer節(jié)點安裝chaincode,然后在Channel上實例化chaincode。
首先,將Go或者Node.js示例代碼安裝到4個peer節(jié)點中的其中一個。如果其他的節(jié)點也要安裝,需要執(zhí)行4此。這個命令將源代碼放到peer節(jié)點的文件系統(tǒng)中。
你可以在每個節(jié)點上安裝任意一種語言的鏈碼。并在稍后指定語言進行初始化。
Golang
# this installs the Go chaincode
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; we use this to specify the language
peer chaincode install -n mycc -v 1.0 -l node -p /opt/gopath/src/github.com/chaincode/chaincode_example02/node/
我們先切換到peer0.org1這個節(jié)點:
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
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
安裝指定的ChainCode并對其命名:
peer chaincode install -n mycc -v 1.0 -p github.com/chaincode/chaincode_example02/go/
2018-03-19 10:32:51.352 UTC [chaincodeCmd] checkChaincodeCmdParams -> INFO 001 Using default escc
2018-03-19 10:32:51.352 UTC [chaincodeCmd] checkChaincodeCmdParams -> INFO 002 Using default vscc
2018-03-19 10:32:51.532 UTC [main] main -> INFO 003 Exiting.....
安裝的過程其實就是對CLI中指定的代碼進行編譯打包,并把打包好的文件發(fā)送到Peer,等待接下來的實例化。
接下來,在channel上實例化chaincode。這將初始化channel上的鏈碼,設置鏈碼的背書策略,為目標peer節(jié)點啟動一個chaincode容器。注意-P參數(shù)。這是我們需要指定的當這個chaincode的交易需要被驗證的時侯的背書策略。
在下面的命令中,你會注意到我們指定-P "OR ('Org0MSP.member','Org1MSP.member')"作為背書策略。這意味著我們需要Org1或者Org2組織中的其中一個的節(jié)點的背書即可(即只有一個背書)。如果我們改變語法為AND那么我們就需要2個背書者。
有關(guān)更多背書策略的詳細信息請參考背書策略。
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 "OR ('Org1MSP.peer','Org2MSP.peer')"
Node.js
# 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 "OR ('Org1MSP.peer','Org2MSP.peer')"
初始化鏈碼:
2018-03-19 10:57:13.838 UTC [chaincodeCmd] checkChaincodeCmdParams -> INFO 001 Using default escc
2018-03-19 10:57:13.838 UTC [chaincodeCmd] checkChaincodeCmdParams -> INFO 002 Using default vscc
2018-03-19 10:57:24.179 UTC [main] main -> INFO 003 Exiting.....
可以使用以下命令查看peer0.org1日志:
docker logs -f peer0.org1.example.com
2018-03-19 10:57:13.847 UTC [golang-platform] GenerateDockerBuild -> INFO 036 building chaincode with ldflagsOpt: '-ldflags "-linkmode external -extldflags '-static'"'
2018-03-19 10:57:13.847 UTC [golang-platform] GenerateDockerBuild -> INFO 037 building chaincode with tags:
2018-03-19 10:57:26.196 UTC [cceventmgmt] HandleStateUpdates -> INFO 038 Channel [mychannel]: Handling LSCC state update for chaincode [mycc]
2018-03-19 10:57:26.202 UTC [kvledger] CommitWithPvtData -> INFO 039 Channel [mychannel]: Committed block [3] with 1 transaction(s)
使用docker ps命令可以發(fā)現(xiàn)新的容器dev-peer0.org1.example.com-mycc-1.0:
yuyangdeMacBook-Pro:first-network yuyang$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
d2fbe3a12558 dev-peer0.org1.example.com-mycc-1.0-384f11f484b9302df90b453200cfb25174305fce8f53f4e94d45ee3b6cab0ce9 "chaincode -peer.add…" 3 minutes ago Up 3 minutes dev-peer0.org1.example.com-mycc-1.0
45b3f41ae42f hyperledger/fabric-tools:latest "/bin/bash" 3 hours ago Up 3 hours cli
26dadcb90749 hyperledger/fabric-peer:latest "peer node start" 3 hours ago Up 3 hours 0.0.0.0:7051->7051/tcp, 0.0.0.0:7053->7053/tcp peer0.org1.example.com
053b317fc840 hyperledger/fabric-peer:latest "peer node start" 3 hours ago Up 3 hours 0.0.0.0:8051->7051/tcp, 0.0.0.0:8053->7053/tcp peer1.org1.example.com
0622660b60cd hyperledger/fabric-peer:latest "peer node start" 3 hours ago Up 3 hours 0.0.0.0:10051->7051/tcp, 0.0.0.0:10053->7053/tcp peer1.org2.example.com
5b6d636ab4ed hyperledger/fabric-peer:latest "peer node start" 3 hours ago Up 3 hours 0.0.0.0:9051->7051/tcp, 0.0.0.0:9053->7053/tcp peer0.org2.example.com
9c4da795db8c hyperledger/fabric-orderer:latest "orderer" 3 hours ago Up 3 hours 0.0.0.0:7050->7050/tcp orderer.example.com
使用node初始化鏈碼會慢點,因為會先去安裝相關(guān)鏡像。不過一旦在channel初始化過后,我們不再需要
-l指定語言,只要告訴channel對應鏈碼的名稱即可。
實例化鏈上代碼主要是在Peer所在的機器上對前面安裝好的鏈上代碼進行包裝,生成對應Channel的Docker鏡像和Docker容器。并且在實例化時我們可以指定背書策略。
1.9.5. 查詢
讓我們查詢一下a的值,以確保鏈碼被正確實例化,state DB被填充。查詢的語法如下:
# be sure to set the -C and -n flags appropriately
peer chaincode query -C $CHANNEL_NAME -n mycc -c '{"Args":["query","a"]}'
2018-03-19 13:05:36.337 UTC [chaincodeCmd] checkChaincodeCmdParams -> INFO 001 Using default escc
2018-03-19 13:05:36.337 UTC [chaincodeCmd] checkChaincodeCmdParams -> INFO 002 Using default vscc
Query Result: 100
2018-03-19 13:05:36.342 UTC [main] main -> INFO 003 Exiting.....
1.9.6. 發(fā)起交易
現(xiàn)在讓我們從a賬戶轉(zhuǎn)10到b賬戶。這個交易將創(chuàng)建一個新的區(qū)塊并更新state DB。調(diào)用語法如下:
# be sure to set the -C and -n flags appropriately
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 mycc -c '{"Args":["invoke","a","b","10"]}'
2018-03-19 13:08:24.534 UTC [chaincodeCmd] checkChaincodeCmdParams -> INFO 001 Using default escc
2018-03-19 13:08:24.534 UTC [chaincodeCmd] checkChaincodeCmdParams -> INFO 002 Using default vscc
2018-03-19 13:08:24.540 UTC [chaincodeCmd] chaincodeInvokeOrQuery -> INFO 003 Chaincode invoke successful. result: status:200
2018-03-19 13:08:24.541 UTC [main] main -> INFO 004 Exiting.....
1.9.7. 查詢
讓我們確認下我們之前的調(diào)用被正確地執(zhí)行了。我們初始化了a的值為100,在上一次調(diào)用的時侯轉(zhuǎn)移了10給b。因此,查詢a應該展示90。查詢的語法如下:
# be sure to set the -C and -n flags appropriately
peer chaincode query -C $CHANNEL_NAME -n mycc -c '{"Args":["query","a"]}'
2018-03-19 13:11:16.917 UTC [chaincodeCmd] checkChaincodeCmdParams -> INFO 001 Using default escc
2018-03-19 13:11:16.917 UTC [chaincodeCmd] checkChaincodeCmdParams -> INFO 002 Using default vscc
Query Result: 90
2018-03-19 13:11:16.923 UTC [main] main -> INFO 003 Exiting.....
1.9.8. 在另一個節(jié)點上查詢
前面的操作都是在org1下面做的,那么處于同一個區(qū)塊鏈(同一個Channel下)的org2,是否會看到org1的更改呢?我們試著給peer0.org2安裝鏈上代碼:
先切換到peer0.org2節(jié)點:
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
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:7051
安裝鏈碼:
peer chaincode install -n mycc -v 1.0 -p github.com/chaincode/chaincode_example02/go/
2018-03-19 13:16:41.437 UTC [chaincodeCmd] checkChaincodeCmdParams -> INFO 001 Using default escc
2018-03-19 13:16:41.437 UTC [chaincodeCmd] checkChaincodeCmdParams -> INFO 002 Using default vscc
2018-03-19 13:16:41.621 UTC [main] main -> INFO 003 Exiting.....
由于mycc已經(jīng)在前面org1的時候?qū)嵗?,也就是說對應的區(qū)塊已經(jīng)生成了,所以在org2不能再次初始化。我們直接運行查詢命令:
peer chaincode query -C $CHANNEL_NAME -n mycc -c '{"Args":["query","a"]}'
2018-03-19 13:18:57.513 UTC [chaincodeCmd] checkChaincodeCmdParams -> INFO 001 Using default escc
2018-03-19 13:18:57.513 UTC [chaincodeCmd] checkChaincodeCmdParams -> INFO 002 Using default vscc
Query Result: 90
2018-03-19 13:19:07.488 UTC [main] main -> INFO 003 Exiting.....
可以看到依然可以進行查詢,且值都是同步的。
這里稍微比之前的查詢花費的時間久點,這是因為
peer0.org2也需要生成Docker鏡像,創(chuàng)建對應的容器,才能通過容器返回結(jié)果。我們回到終端,執(zhí)行docker ps,可以看到又多了一個容器:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
927a7a89671d dev-peer0.org2.example.com-mycc-1.0-15b571b3ce849066b7ec74497da3b27e54e0df1345daff3951b94245ce09c42b "chaincode -peer.add…" 2 minutes ago Up 2 minutes dev-peer0.org2.example.com-mycc-1.0
d2fbe3a12558 dev-peer0.org1.example.com-mycc-1.0-384f11f484b9302df90b453200cfb25174305fce8f53f4e94d45ee3b6cab0ce9 "chaincode -peer.add…" 2 hours ago Up 2 hours dev-peer0.org1.example.com-mycc-1.0
45b3f41ae42f hyperledger/fabric-tools:latest "/bin/bash" 5 hours ago Up 5 hours cli
26dadcb90749 hyperledger/fabric-peer:latest "peer node start" 5 hours ago Up 5 hours 0.0.0.0:7051->7051/tcp, 0.0.0.0:7053->7053/tcp peer0.org1.example.com
053b317fc840 hyperledger/fabric-peer:latest "peer node start" 5 hours ago Up 5 hours 0.0.0.0:8051->7051/tcp, 0.0.0.0:8053->7053/tcp peer1.org1.example.com
0622660b60cd hyperledger/fabric-peer:latest "peer node start" 5 hours ago Up 5 hours 0.0.0.0:10051->7051/tcp, 0.0.0.0:10053->7053/tcp peer1.org2.example.com
5b6d636ab4ed hyperledger/fabric-peer:latest "peer node start" 5 hours ago Up 5 hours 0.0.0.0:9051->7051/tcp, 0.0.0.0:9053->7053/tcp peer0.org2.example.com
9c4da795db8c hyperledger/fabric-orderer:latest "orderer" 5 hours ago Up 5 hours 0.0.0.0:7050->7050/tcp orderer.example.com
1.9.9. 幕后發(fā)生了什么?
script.sh腳本被拷貝到CLI容器中。這個腳本驅(qū)動了使用提供的channel name以及信道配置的channel.tx文件的createChannel命令。createChannel命令的產(chǎn)出是一個創(chuàng)世區(qū)塊-<your_channel_name>.block-這個創(chuàng)世區(qū)塊被存儲在peer節(jié)點的文件系統(tǒng)中同時包含了在channel.tx的信道配置。joinChannel命令被4個peer節(jié)點執(zhí)行,作為之前產(chǎn)生的genesis block的輸入。這個命令介紹了peer節(jié)點加入<your_channel_name>以及利用<your_channel_name>.block去創(chuàng)建一條鏈。現(xiàn)在我們有了由4個
peer節(jié)點以及2個組織構(gòu)成的信道。這是我們的TwoOrgsChannel配置文件。peer0.org1.example.com和peer1.org1.example.com屬于Org1;peer0.org2.example.com和peer1.org2.example.com屬于Org2。這些關(guān)系是通過
crypto-config.yaml定義的,MSP路徑在docker-compose文件中被指定。Org1MSP(
peer0.org1.example.com)和Org2MSP(peer0.org2.example.com)的anchor peers將在后續(xù)被更新。我們通過攜帶channel的名字傳遞Org1MSPanchors.tx和Org2MSPanchors.tx配置到排序服務來實現(xiàn)anchor peer的更新。一個鏈碼-
chaincode_example02被安裝在peer0.org1.example.com。這個鏈碼在
peer0.org1.example.com被實例化。實例化過程將鏈碼添加到信道上,并啟動peer節(jié)點對應的容器,并且初始化和鏈碼服務有關(guān)的鍵值對。示例的初始化的值是[”a“,”100“,”b“,”200“]。實例化的結(jié)果是一個名為dev-peer0.org1.example.com-mycc-1.0的容器啟動了。實例化過程同樣為背書策略傳遞相關(guān)參數(shù)。策略被定義為-P "OR ('Org1MSP.member','Org2MSP.member')",意思是任何交易必須被Org1或者Org2背書。
一個針對
a的查詢發(fā)往peer0.org1.example.com。鏈碼服務已經(jīng)被安裝在了peer0.org1.example.com。查詢的結(jié)果也將被返回。沒有寫操作出現(xiàn),因此查詢的結(jié)果的值將為100。一次交易被發(fā)往peer0.org1.example.com,從a轉(zhuǎn)移10到b。
一個查詢請求被發(fā)往
peer0.org1.example.com用于查詢a的值。返回a的值為90,正確地反映了之前的交易,a的值被轉(zhuǎn)移了10。在
peer0.org2.example.com安裝鏈碼,用于查詢a的值。一個名為dev-peer0.org2.example.com-mycc-1.0的容器啟動了。返回a的值為90,正確地反映了之前的交易,a的值被轉(zhuǎn)移了10。
1.9.10. 這指明了什么?
為了能夠正確地在賬本上進行讀寫操作,鏈碼服務必須被安裝在peer節(jié)點上。此外,每個peer節(jié)點的鏈碼服務的容器除了init或者傳統(tǒng)的交易-讀/寫-針對該鏈碼服務執(zhí)行(例如查詢a的值),在其他情況下不會啟動。交易導致容器的啟動。當然,所有信道中的節(jié)點都持有以塊的形式順序存儲的不可變的賬本精確的備份,以及狀態(tài)數(shù)據(jù)庫來保存前狀態(tài)的快照。這包括了沒有在其上安裝鏈碼服務的peer節(jié)點(例如peer1.org1.example.com和peer1.org2.example.com)。最后,鏈碼在被安裝后將是可達狀態(tài),因為它已經(jīng)被實例化了(例如peer0.org2.example.com)。
1.9.11. 我如何查詢這些交易?
檢查CLI容器的日志。
docker logs -f cli
你應該看到以下輸出:
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 on peer1.org2 on channel 'mychannel' is successful =====================
===================== All GOOD, BYFN execution completed =====================
_____ _ _ ____
| ____| | \ | | | _ \
| _| | \| | | | | |
| |___ | |\ | | |_| |
|_____| |_| \_| |____/
你可以滾動這些日志來查看各種交易。
1.9.12. 我如何查看鏈碼日志?
檢查每個獨立的鏈碼服務容器來查看每個容器內(nèi)的分隔的交易。下面是每個鏈碼服務容器的日志的組合:
$ 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"}
1.10. 了解 Docker Compose 技術(shù)
BYFN示例給我們提供了兩種風格的Docker Compose文件,它們都繼承自docker-compose-base.yaml(base目錄下)。我們的第一種類型,docker-compose-cli.yaml給我們提供了一個CLI容器,以及一個orderer容器,四個peer容器。
注意:本節(jié)的剩余部分涵蓋了為SDK設計的docker-compose文件。有關(guān)運行這些測試的詳細信息,請參閱Node SDK倉庫。
第二種風格是docker-compose-e2e.yaml,被構(gòu)造為使用Node.js SDK來運行端到端測試。除了SDK的功能之外,它主要的區(qū)別在于它有運行fabric-ca服務的容器。因此,我們能夠向組織的CA節(jié)點發(fā)送REST的請求用于注冊和登記。
如果你在沒有運行byfn.sh腳本的情況下,想使用docker-compose-e2e.yaml,我們需要進行4個輕微的修改。我們需要指出本組織CA的私鑰。你可以在crypto-config文件夾中找到這些值。舉個例子,為了定位Org1的私鑰,我們將使用crypto-config/peerOrganizations/org1.example.com/ca/。Org2的路徑為crypto-config/peerOrganizations/org2.example.com/ca/。
在docker-compose-e2e.yaml里為ca0和ca1更新FABRIC_CA_SERVER_TLS_KEYFILE變量。你同樣需要編輯command中去啟動ca server的路徑。你為每個CA容器提供了2次同樣的私鑰。
1.11. 使用CouchDB
狀態(tài)數(shù)據(jù)庫可以從默認的goleveldb切換到CouchDB。鏈碼功能同樣能使用CouchDB。但是,CouchDB提供了額外的能力,可以根據(jù)JSON形式的鏈碼服務數(shù)據(jù),提供更加豐富以及復雜的查詢。
使用CouchDB代替默認的數(shù)據(jù)庫(goleveldb),除了在啟動網(wǎng)絡的時侯傳遞docker-compose-couch.yaml之外,請遵循前面提到的生成配置文件的過程:
使用CouchDB啟動網(wǎng)絡:
docker-compose -f docker-compose-cli.yaml -f docker-compose-couch.yaml up -d
Creating couchdb0 ... done
Creating couchdb3 ... done
Creating couchdb2 ... done
Creating couchdb1 ... done
aml -f docker-compose-couch.yaml up -d
Starting orderer.example.com ...
Creating couchdb3 ...
Creating couchdb2 ...
Creating couchdb0 ...
Starting orderer.example.com ... done
Recreating peer0.org1.example.com ...
Recreating peer1.org2.example.com ...
Recreating peer0.org2.example.com ... done
Recreating peer1.org1.example.com ... done
Recreating cli ... done
注意:如果你選擇將fabric-couchdb容器端口映射到主機端口,請確保你意識到了安全性的影響。在開發(fā)環(huán)境中映射端口可以使CouchDB REST API可用,并允許通過CouchDB Web界面(Fauxton)對數(shù)據(jù)庫進行可視化。生產(chǎn)環(huán)境將避免端口映射,以限制對CouchDB容器的外部訪問。
你可以使用上面列出的步驟使用CouchDB來執(zhí)行chaincode_example02,然而為了執(zhí)行CouchDB的查詢能力,你將需要使用被格式化為JSON的數(shù)據(jù)(例如marbles02)。你可以在fabric/examples/chaincode/go目錄中找到marbles02鏈碼。
使用docker ps查看容器,可以看到除了1Orderer+4Peer+1CLI啟動外,還啟動了四個couchdb:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
608e57b03072 hyperledger/fabric-tools:latest "/bin/bash" 14 minutes ago Up 14 minutes cli
2de36bd8f69a hyperledger/fabric-peer:latest "peer node start" 14 minutes ago Up 14 minutes 0.0.0.0:8051->7051/tcp, 0.0.0.0:8053->7053/tcp peer1.org1.example.com
4f849ff5a190 hyperledger/fabric-peer:latest "peer node start" 14 minutes ago Up 14 minutes 0.0.0.0:9051->7051/tcp, 0.0.0.0:9053->7053/tcp peer0.org2.example.com
de8fac9c70ab hyperledger/fabric-peer:latest "peer node start" 14 minutes ago Up 14 minutes 0.0.0.0:10051->7051/tcp, 0.0.0.0:10053->7053/tcp peer1.org2.example.com
92928b49f85f hyperledger/fabric-peer:latest "peer node start" 14 minutes ago Up 14 minutes 0.0.0.0:7051->7051/tcp, 0.0.0.0:7053->7053/tcp peer0.org1.example.com
cb9dd19c38a3 hyperledger/fabric-couchdb "tini -- /docker-ent…" 14 minutes ago Up 14 minutes 4369/tcp, 9100/tcp, 0.0.0.0:6984->5984/tcp couchdb1
c34ca64ffd3e hyperledger/fabric-couchdb "tini -- /docker-ent…" 14 minutes ago Up 14 minutes 4369/tcp, 9100/tcp, 0.0.0.0:8984->5984/tcp couchdb3
8a6b82e9b7a4 hyperledger/fabric-couchdb "tini -- /docker-ent…" 14 minutes ago Up 14 minutes 4369/tcp, 9100/tcp, 0.0.0.0:7984->5984/tcp couchdb2
03c634c23010 hyperledger/fabric-couchdb "tini -- /docker-ent…" 14 minutes ago Up 14 minutes 4369/tcp, 9100/tcp, 0.0.0.0:5984->5984/tcp couchdb0
9c4da795db8c hyperledger/fabric-orderer:latest "orderer" 21 hours ago Up 14 minutes 0.0.0.0:7050->7050/tcp orderer.example.com
進入CLI容器:
yuyangdeMacBook-Pro:first-network yuyang$ docker exec -it cli bash
切換節(jié)點到peer0.org1:
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
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
安裝marbles02鏈碼:
peer chaincode install -n marbles -v 1.0 -p github.com/chaincode/marbles02/go
設置下channel變量:
export CHANNEL_NAME=mychannel
實例化鏈碼:
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 ('Org0MSP.peer','Org1MSP.peer')"
2018-03-20 05:11:55.424 UTC [chaincodeCmd] checkChaincodeCmdParams -> INFO 001 Using default escc
2018-03-20 05:11:55.424 UTC [chaincodeCmd] checkChaincodeCmdParams -> INFO 002 Using default vscc
2018-03-20 05:12:06.480 UTC [main] main -> INFO 003 Exiting.....
再次查看容器,發(fā)現(xiàn)一個新的docker產(chǎn)生了:
dev-peer0.org1.example.com-marbles-1.0
對數(shù)據(jù)進行增刪改查:
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的端口,那么你可以通過CouchDB Web界面(Fauxton)通過打開瀏覽器輸入下列URL:http://localhost:5984/_utils查看數(shù)據(jù)的變化。

你可以CLI中運行常規(guī)的查詢(例如讀取marble2):
peer chaincode query -C $CHANNEL_NAME -n marbles -c '{"Args":["readMarble","marble2"]}'
marble2的輸出應該顯示為如下:
Query Result: {"color":"red","docType":"marble","name":"marble2","owner":"jerry","size":50}
你可以檢索特定marble的歷史記錄-例如marble1:
peer chaincode query -C $CHANNEL_NAME -n marbles -c '{"Args":["getHistoryForMarble","marble1"]}'
輸出應該在marble1的記錄:
Query Result: [{"TxId":"c2b0db43718f40c0d787ebfe298663c4db38257271fba851629aa12fda2d9c71", "Value":{"docType":"marble","name":"marble1","color":"blue","size":35,"owner":"tom"}, "Timestamp":"2018-03-20 05:30:40.843542497 +0000 UTC", "IsDelete":"false"},{"TxId":"ea869117344ca23a3ee2f768a26added28eb23f46e66a54e3e750224fda6caea", "Value":{"docType":"marble","name":"marble1","color":"blue","size":35,"owner":"jerry"}, "Timestamp":"2018-03-20 05:34:14.029638632 +0000 UTC", "IsDelete":"false"},{"TxId":"93242722cfb605a46df083ad3111b34415624d07b3234963dcd58ca47ebd87ef", "Value":null, "Timestamp":"2018-03-20 05:35:48.618124625 +0000 UTC", "IsDelete":"true"}]
你還可以對數(shù)據(jù)內(nèi)容執(zhí)行豐富的查詢,例如通過擁有者jerry查詢marble:
peer chaincode query -C $CHANNEL_NAME -n marbles -c '{"Args":["queryMarblesByOwner","jerry"]}'
輸出應該顯示2個屬于jerry的marble:
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}}]
1.12. 為何使用CouchDB
CouchDB is a kind of NoSQL solution. It is a document oriented database where document fields are stored as key-value mpas. Fields can be either a simple key/value pair, list, or map. In addition to keyed/composite-key/key-range queries which are supported by LevelDB, CouchDB also supports full data rich queries capability, such as non-key queries against the whole blockchain data, since its data content is stored in JSON format and fully queryable. Therefore, CouchDB can meet chaincode, auditing, reporting requirements for many use cases that not supported by LevelDB.
CouchDB can also enhance the security for compliance and data protection in the blockchain. As it is able to implement field-level security through the filtering and masking of individual attributes within a transaction, and only authorizing the read-only permission if needed.
In addition, CouchDB falls into the AP-type (Availability and Partition Tolerance) of the CAP theorem. It uses a master-master replication model with Eventual Consistency. More information can be found on the Eventual Consistency page of the CouchDB documentation. However, under each fabric peer, there is no database replicas, writes to database are guaranteed consistent and durable (not Eventual Consistency).
CouchDB is the first external pluggable state database for Fabric, and there could and should be other external database options. For example, IBM enables the relational database for its blockchain. And the CP-type (Consistency and Partition Tolerance) databases may also in need, so as to enable data consistency without application level guarantee.
怕翻譯的不準確,誤人子弟。下面的內(nèi)容是我在其他地方摘取的,可以了解一下:
狀態(tài)數(shù)據(jù)庫包括LevelDB和CouchDB。LevelDB是嵌入在peer進程中的默認鍵/值狀態(tài)數(shù)據(jù)庫,CouchDB是一個可選的外部狀態(tài)數(shù)據(jù)庫。與LevelDB鍵/值存儲一樣,CouchDB可以存儲任何以chaincode建模的二進制數(shù)據(jù)(CouchDB附件函數(shù)在內(nèi)部用于非json二進制數(shù)據(jù))。但是,當chaincode值(例如,資產(chǎn))被建模為JSON數(shù)據(jù)時,作為JSON文檔存儲,CouchDB支持對chaincode數(shù)據(jù)進行豐富的查詢。
LevelDB和CouchDB都支持核心chaincode操作,例如獲取和設置一個鍵(資產(chǎn)),并根據(jù)鍵進行查詢。鍵可以通過范圍查詢,可以對組合鍵進行建模,以支持針對多個參數(shù)的等價查詢。例如,作為所有者的組合鍵,資產(chǎn)id可以用于查詢某個實體擁有的所有資產(chǎn)。這些基于key的查詢可以用于針對賬本的只讀查詢,以及更新總賬的事務。
如果將資產(chǎn)建模為JSON并使用CouchDB,那么就可以使用chaincode中的CouchDB JSON查詢語言對chaincode數(shù)據(jù)值執(zhí)行復雜的富查詢,這些類型的查詢對于理解賬本上的內(nèi)容很有幫助。對于這些類型的查詢,事務協(xié)議響應通常對客戶端應用程序有用,但通常不會作為事務提交到排序服務。事實上,也無法保證結(jié)果集在chaincode執(zhí)行與富查詢提交時間之間的穩(wěn)定性,因此使用富查詢的結(jié)果去執(zhí)行最終的事務更新操作是不合適的,除非可以保證結(jié)果集在chaincode執(zhí)行時間與提交時間之間的穩(wěn)定性,或者可以處理在后續(xù)交易中的潛在變化。例如,如果對Alice所擁有的所有資產(chǎn)執(zhí)行一個富查詢并將其傳輸給Bob,那么一個新的資產(chǎn)可能會被另一個事務分配給Alice,這是在chaincode執(zhí)行時間和提交時間之間的另一個事務,可能此過程中會錯過這個“虛值”。
CouchDB作為一個獨立的數(shù)據(jù)庫進程與peer一起運行,因此在設置、管理和操作方面有額外的考慮。我們可以考慮從默認的嵌入式LevelDB開始,如果需要額外的復雜的富查詢,可以轉(zhuǎn)移到CouchDB。將chaincode資產(chǎn)數(shù)據(jù)建模為JSON是一種很好的做法,這樣我們就可以在將來執(zhí)行需要的復雜的富查詢。
1.13. 關(guān)于數(shù)據(jù)持久化的提示
如果需要在peer容器或者CouchDB容器進行數(shù)據(jù)持久化,一種選擇是將docker容器內(nèi)相應的目錄掛載到容器所在的宿主機的一個目錄中。例如,你可以添加下列的兩行到docker-compose-base.yaml文件中peer的約定中:
volumes:
- /var/hyperledger/peer0:/var/hyperledger/production
對于CouchDB容器,你可以在CouchDB的約定中添加兩行:
volumes:
- /var/hyperledger/couchdb0:/opt/couchdb/data
1.14. 故障排除
- 始終保持你的網(wǎng)絡是全新的。使用以下命令來移除之前生成的artifacts,crypto,containers以及chaincode images:
./byfn.sh -m down
- 如果提示以下錯誤:
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)
你可能由于運行了以前的鏈碼服務(例如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}')
- 如果提示以下錯誤:
[configtx/tool/localconfig] Load -> CRIT 002 Error reading configuration: Unsupported Config Type ""
panic: Error reading configuration: Unsupported Config Type ""
那么你沒有正確設置FABRIC_CFG_PATH環(huán)境變量。configtxgen工具需要這個變量才能找到configtx.yaml。返回并執(zhí)行export FABRIC_CFG_PATH=$PWD,然后重新創(chuàng)建channel配置。
- 要清理網(wǎng)絡,請使用
down選項:
./byfn.sh -m down
如果你看到一條指示你依然有“active endpoints”,執(zhí)行以下命令清理你的Docker網(wǎng)絡。這將會清除你之前的網(wǎng)絡并且給你一個全新的環(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。
參考
原文:深入理解Fabric環(huán)境搭建的詳細過程
作者:深藍