Hyperledger Fabric(二) 官方教程:構(gòu)建第一個網(wǎng)絡(luò)

前言

官方英文:Building Your First Network

中文:構(gòu)建第一個fabric網(wǎng)絡(luò)

感謝中文翻譯闹击!不然這么長的英文以及各種名詞解釋實(shí)在頭疼咳促。有一些和官方英文不一樣的地方我已經(jīng)按官方英文進(jìn)行了補(bǔ)充和修正慧耍,并且盡量簡化了語言履因,因?yàn)橛行┓g過來有點(diǎn)拗口。如果希望看完整及原汁原味的文檔馒铃,推薦看官方英文文檔蟹腾。

本文基于Mac OS以及Hyperledger Fabric 1.1.0痕惋。

Building Your First Network

構(gòu)建你的第一個網(wǎng)絡(luò)(BYFN)場景提供了由兩個組織組成的示例Hyperledger Fabric網(wǎng)絡(luò),每個組織持有2個peer節(jié)點(diǎn)娃殖,以及一個“solo”排序服務(wù)值戳。

1.1. 安裝預(yù)置環(huán)境

在我們開始之前,如果你還沒有這樣做炉爆,你可能需要檢查一下在你開發(fā)區(qū)塊鏈應(yīng)用程序或者Hyperledger Fabric的平臺上是否已經(jīng)安裝了預(yù)置環(huán)境堕虹。

你還需要下載并安裝Hyperledger Fabric Samples。你會注意到fabric-samples文件夾中包含了許多示例芬首。我們將使用first-network這個例子「袄蹋現(xiàn)在讓我們打開這個子目錄。

cd fabric-samples/first-network

注意:本文檔中提供的命令必須運(yùn)行在fabric-samples的子目錄fabric-network中郁稍。如果你選擇從其他位置運(yùn)行命令赦政,提供的一些腳本將無法找到對應(yīng)的二進(jìn)制。

1.2. 想要現(xiàn)在運(yùn)行嗎耀怜?

我們提供一個完全注釋的腳本byfn.sh恢着,利用這些Docker鏡像可以快速引導(dǎo)一個由4個代表2個不同組織的peer節(jié)點(diǎn)以及一個排序服務(wù)節(jié)點(diǎn)的Hyperledger fabric網(wǎng)絡(luò)。它還將啟動一個容器來運(yùn)行一個將peer節(jié)點(diǎn)加入channel封寞、部署實(shí)例化鏈碼服務(wù)以及驅(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名稱,則腳本將使用默認(rèn)名稱mychannel狈究。CLI超時參數(shù)(用-t標(biāo)志指定)是一個可選值;如果你選擇不設(shè)置它碗淌,那么CLI容器將會在腳本執(zhí)行完之后退出。

1.3. 生成網(wǎng)絡(luò)

準(zhǔn)備好了嗎抖锥?好吧亿眠!執(zhí)行以下命令。

yuyangdeMacBook-Pro:~ yuyang$ cd /Users/yuyang/fabric-sample/fabric-samples/first-network 
yuyangdeMacBook-Pro:first-network yuyang$ ./byfn.sh -m generate

命令行會提示將會發(fā)生什么磅废。當(dāng)提示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)絡(luò)實(shí)體的所有證書和密鑰拯勉,genesis block用于引導(dǎo)排序服務(wù)竟趾,以及配置Channel所需要的一組交易配置集合。

1.4. 啟動網(wǎng)絡(luò)

接下來宫峦,你可以使用以下命令來啟動整個網(wǎng)絡(luò)岔帽。

./byfn.sh -m up

上面的指令會編譯Golang智能合約鏡像并且啟動對應(yīng)的容器。Go語言是默認(rèn)的鏈碼語言导绷,當(dāng)然這里也支持 Node.js智能合約犀勒。如果你希望以node形式的智能合約完成教程,可以將剛才的指令替換為:

# 使用 -l 標(biāo)志指定智能合約語言
# 不指定默認(rèn)使用Golang

./byfn.sh -m up -l node

點(diǎn)擊 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ū)動一個端到端的應(yīng)用場景褂萧。成功以后押桃,在終端窗口中會報(bào)告以下內(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)絡(luò)

最后锡足,讓我們把它全部停下來,這樣我們可以一步一步地探索網(wǎng)絡(luò)設(shè)置壳坪。以下操作將關(guān)閉你的容器舶得,移除加密材料和4個配置信息,并且從Docker倉庫刪除智能合約鏡像爽蝴。你將再一次被提示是否繼續(xù)沐批,回答y或者鍵入回車:

yuyangdeMacBook-Pro:first-network yuyang$ ./byfn.sh -m down

如果你想了解關(guān)于底層工具和引導(dǎo)材料相關(guān)的更多信息,請繼續(xù)閱讀蝎亚。在接下來的章節(jié)中九孩,我們將瀏覽構(gòu)建功能齊全的Hyperledger fabric網(wǎng)絡(luò)的各種要求和步驟。

在上面的步驟中发框,默認(rèn)的cli容器日志輸出等級CORE_LOGGING_LEVELINFO躺彬。你可以在first-network目錄中的docker-compose-cli.yaml文件中進(jìn)行修改。

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)絡(luò)實(shí)體的加密材料(x509證書)梅惯。這些證書是身份的代表宪拥,它們允許在我們的網(wǎng)絡(luò)實(shí)體進(jìn)行交流和交易時進(jìn)行簽名/驗(yàn)證身份驗(yàn)證。

Fabric中有兩種類型的公私鑰和證書铣减,一種是給節(jié)點(diǎn)之前通訊安全而準(zhǔn)備的TLS證書她君,另一種是用戶登錄和權(quán)限控制的用戶證書。這些證書本來應(yīng)該是由CA來頒發(fā)葫哗,但是我們這里是測試環(huán)境缔刹,并沒有啟用CA節(jié)點(diǎn),所以Fabric幫我們提供了一個工具:cryptogen劣针。

1.6.1. 它是如何工作的校镐?

Cryptogen使用crypto-config.yaml,并允許我們?yōu)榻M織和屬于這些組織的組件生成一組證書和密鑰酿秸。每個組織都配置了唯一的根證書(ca-cert),它將特定組件(peers和orders)綁定到該組織灭翔。通過為每一個組織分配唯一的CA證書,我們正在模仿一個典型的網(wǎng)絡(luò),這個網(wǎng)絡(luò)中的成員將使用自己的證書頒發(fā)機(jī)構(gòu)肝箱。Hyperledger Fabric中的交易和通信是通過存儲在keystore中的實(shí)體的私鑰簽名哄褒,然后通過公鑰手段進(jìn)行驗(yàn)證(signcerts)。

你將注意到在這個文件里有一個count變量煌张。我們將使用它來指定每個組織中peer的數(shù)量;在我們的例子中呐赡,每個組織有兩個peer。我們現(xiàn)在不會深入研究x.509證書和公鑰基礎(chǔ)設(shè)施的細(xì)節(jié)骏融。如果你有興趣链嘀,你可以在自己的時間細(xì)讀這些主題。

在運(yùn)行該工具之前档玻,讓我們快速瀏覽一下這段代碼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)絡(luò)實(shí)體的命名約定如下:”{{.Hostname}}.{{.Domain}}”误趴。所以使用我們的排序節(jié)點(diǎn)作為參考點(diǎn)霹琼,它與Order的MSP ID相關(guān)聯(lián)。該文件包含了有關(guān)定義和語法的大量文檔凉当。你還可以參考Membership Service Providers(MSP)枣申,以便更深入地了解MSP。

我們運(yùn)行cryptogen工具看杭,生成的證書和密鑰將被保存到名為crypto-config的文件夾中忠藤。

1.7. 配置工作說明

configtxgen tool用于創(chuàng)建4個配置工作:

  • order的genesis block 創(chuàng)世區(qū)塊

  • channel的channel configuration transaction

  • 以及兩個anchor peer transactions一個對應(yīng)一個Peer組織

有關(guān)此工具的完整說明,請參閱Channel Configuration(configtxgen)楼雹。

order block是一個ordering service的創(chuàng)世區(qū)塊模孩,channel transaction配置文件在Channel創(chuàng)建的時侯廣播給order。anchor peer transactions烘豹,正如名稱所示瓜贾,指定了每個組織在此channel上的錨節(jié)點(diǎn)。

1.7.1. 它是如何工作的携悯?

Configtxgen使用一個包含示例網(wǎng)絡(luò)的configtx.yaml文件祭芦。有3個成員-一個排序服務(wù)組織OrdererOrg以及兩個節(jié)點(diǎn)組織(Org1&Org2),每個組織管理和持有2個peer節(jié)點(diǎn)。該文件還指定了一個SampleConsortium的聯(lián)盟憔鬼,由上述2個節(jié)點(diǎn)組織構(gòu)成龟劲。 請?zhí)貏e注意此文件頂部的”Profiles”部分。你會注意到我們有兩個獨(dú)特的標(biāo)題轴或。一個是orderer的創(chuàng)世區(qū)塊-TwoOrgsOrdererGenesis-另一個是針對channel的TwoOrgsChannel昌跌。

這些標(biāo)題很重要,因?yàn)樵谖覀儎?chuàng)建我們的工作的時侯它們將作為傳遞的參數(shù)照雁。

注意:請注意我們的SampleConsortium在系統(tǒng)級別的配置文件中定義蚕愤,然后由channel級別配置文件引用。

此文件還包含兩個值得注意的附加規(guī)格。首先萍诱,我們?yōu)槊總€組織指定了錨點(diǎn)節(jié)點(diǎn)(peer0.org1.example.compeer0.org2.example.com)悬嗓。其次,我們?yōu)槊總€成員指定MSP文件夾裕坊,用來存儲每個組織在orderer genesis block中指定的根證書包竹。這是一個關(guān)鍵的概念。現(xiàn)在任意和ordering service通信的網(wǎng)絡(luò)實(shí)體都可以對其數(shù)字簽名進(jìn)行驗(yàn)證籍凝。

這個文件里面配置了由2個Org參與的Orderer共識配置TwoOrgsOrdererGenesis周瞎,以及由2個Org參與的Channel配置:TwoOrgsChannel。Orderer可以設(shè)置共識的算法是Solo還是Kafka饵蒂,以及共識時區(qū)塊大小声诸,超時時間等,我們使用默認(rèn)值即可苹享,不用更改双絮。而Peer節(jié)點(diǎn)的配置包含了MSP的配置,錨節(jié)點(diǎn)的配置得问。如果我們有更多的Org,或者有更多的Channel软免,那么就可以根據(jù)模板進(jìn)行對應(yīng)的修改宫纬。

1.8. 生成公私鑰證書和創(chuàng)世區(qū)塊

你可以用configtxgencryptogen命令來手動生成證書/密鑰和各種配置文件「嘞簦或者漓骚,你可以嘗試使用byfn.sh腳本來完成你的目標(biāo)。

1.8.1. 手動生成

必要的話榛泛,你可以參考byfn.sh腳本中的generateCerts函數(shù)去生成相關(guān)定義在crypto-config.yaml文件中用于你的網(wǎng)絡(luò)配置的相關(guān)證書蝌蹂。然而,為了方便起見曹锨,我們也將在此提供參考孤个。

首先,我們來運(yùn)行cryptogen這個工具沛简。我們的二進(jìn)制文件在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文件。我們將告訴它在我們當(dāng)前的工作目錄獲取捧灰。

我們需要設(shè)置一個環(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放置在當(dāng)前目錄下的channel-artifacts文件夾中。

1.8.2. 創(chuàng)建channel transaction配置

接下來炭庙,我們需要創(chuàng)建channel transaction配置跪另。請確保替換$CHANNEL_NAME或者將CHANNEL_NAME設(shè)置為整個說明中可以使用的環(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放置在當(dāng)前目錄下的channel-artifacts文件夾中辑奈。

接下來刺下,我們將在正在構(gòu)建的通道上定義Org1anchor peer。請?jiān)俅未_認(rèn)$CHANNEL_NAME已被替換或者為以下命令設(shè)置了環(huán)境變量:

yuyangdeMacBook-Pro:first-network yuyang$ ../bin/configtxgen -profile TwoOrgsChannel -outputAnchorPeersUpdate ./channel-artifacts/Org1MSPanchors.tx -channelID $CHANNEL_NAME -asOrg Org1MSP

現(xiàn)在零渐,我們將在同一個通道定義Org2anchor peer

yuyangdeMacBook-Pro:first-network yuyang$ ../bin/configtxgen -profile TwoOrgsChannel -outputAnchorPeersUpdate ./channel-artifacts/Org2MSPanchors.tx -channelID $CHANNEL_NAME -asOrg Org2MSP

注意:剛才的指令會將生成的文件Org1MSPanchors.txOrg2MSPanchors.tx放置在當(dāng)前目錄下的channel-artifacts文件夾中擦盾。

1.9. 啟動網(wǎng)絡(luò)

我們將利用docker-compose腳本來啟動我們的區(qū)塊鏈網(wǎng)絡(luò)嘲驾。docker-compose文件會利用我們之前下載的鏡像,并用以前生成的genesis.block來引導(dǎo)orderer迹卢。

我們想手動執(zhí)行命令辽故,以便說明每個調(diào)用的語法和功能。

首先啟動你的網(wǎng)絡(luò):

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 ... 

如果要實(shí)時查看你的區(qū)塊鏈網(wǎng)絡(luò)的日志腐碱,請不要提供-d標(biāo)志誊垢。如果你需要日志流,你需要打開第二個終端來執(zhí)行CLI命令症见。

CLI容器處于空閑狀態(tài)時只會會停留1000秒喂走。你可以使用以下命令再次啟動它:

docker start cli

1.9.1. 環(huán)境變量

下面是peer0.org1.example.com的環(huán)境變量。每當(dāng)在CLI命令中需要執(zhí)行節(jié)點(diǎn)操作時谋作,都要確認(rèn)當(dāng)前處于哪個節(jié)點(diǎn)下芋肠。如果要切換至peer0.org1節(jié)點(diǎn),就需要將其環(huán)境變量復(fù)制到命令行中執(zhí)行遵蚜。同理帖池,如果切換到其他節(jié)點(diǎn),需要對應(yīng)的修改環(huán)境變量吭净。后面會進(jìn)行實(shí)際操作睡汹。

# 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配置 寂殉。你可以重復(fù)使用相同或不同的configtx.yaml文件囚巴,在你的網(wǎng)絡(luò)創(chuàng)建其他的信道。

我們將使用docker exec命令進(jìn)入CLI容器:

yuyangdeMacBook-Pro:first-network yuyang$ docker exec -it cli bash

如果成功不撑,你將看到下列信息:

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

我們使用-c標(biāo)志指定channel的名字文兢,-f標(biāo)志指定channel配置文件。在這個例子中它是channel.tx焕檬,當(dāng)然你也可以使用不同的名稱姆坚,掛載你自己的channel配置。再一次实愚,我們將在CLI容器里設(shè)置了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)ヲ?yàn)證TLS握手维苔。

此命令返回一個創(chuàng)世區(qū)塊-<channel-ID.block>-我們將使用它加入信道。它包含了channel.tx中的配置信息懂昂。如果你沒有修改過channel.tx文件中默認(rèn)的通道名稱介时,上面的命令會返回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.....沸柔,是直接退出了。因?yàn)槲铱吹墓俜轿臋n和網(wǎng)上其他人寫的示例都是返回了區(qū)塊信息铲敛,所以我以為我這里出問題了褐澎,然后想了很多辦法查了很多資料,重來了很多次都不行伐蒋。接著我發(fā)現(xiàn)之前官方寫的腳本byfn.sh運(yùn)行是沒有問題的工三,所以我試著再次運(yùn)行,發(fā)現(xiàn)它在創(chuàng)建channel的時候也是INFO 003 Exiting.....先鱼,應(yīng)該是成功了的俭正。如果有朋友有更好的解釋,麻煩留言告知型型,謝謝段审!

另外這里有一個方法可以查看容器啟動后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é)點(diǎn)加入信道。

加入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é)點(diǎn)

由于我們在剛才的步驟中最后加入的節(jié)點(diǎn)是peer1.org2抑淫,所以執(zhí)行完成后我們的命令行現(xiàn)在處于peer1.org2下绷落。而現(xiàn)在我們需要為Org1設(shè)置錨節(jié)點(diǎn)peer0.org1,所以命令行需要先切回到peer0.org1

設(shè)置當(dāng)前操作節(jié)點(diǎn)為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é)點(diǎn)為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設(shè)置錨節(jié)點(diǎn)peer0.org2

設(shè)置當(dāng)前操作節(jié)點(diǎn)為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é)點(diǎn)為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. 安裝和實(shí)例化鏈碼

我們將利用一個現(xiàn)有的簡單鏈碼始苇。要學(xué)習(xí)如何編寫自己的鏈碼砌烁,請參考鏈碼服務(wù)開發(fā)指南

應(yīng)用程序和區(qū)塊鏈賬本會通過chaincode相互影響。因此催式,我們需要在每個會執(zhí)行以及背書我們交易的peer節(jié)點(diǎn)安裝chaincode函喉,然后在Channel上實(shí)例化chaincode。

首先荣月,將Go或者Node.js示例代碼安裝到4個peer節(jié)點(diǎn)中的其中一個管呵。如果其他的節(jié)點(diǎn)也要安裝,需要執(zhí)行4此哺窄。這個命令將源代碼放到peer節(jié)點(diǎn)的文件系統(tǒng)中捐下。

你可以在每個節(jié)點(diǎn)上安裝任意一種語言的鏈碼账锹。并在稍后指定語言進(jìn)行初始化。

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é)點(diǎn):

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.....

安裝的過程其實(shí)就是對CLI中指定的代碼進(jìn)行編譯打包坷襟,并把打包好的文件發(fā)送到Peer奸柬,等待接下來的實(shí)例化。

接下來婴程,在channel上實(shí)例化chaincode廓奕。這將初始化channel上的鏈碼,設(shè)置鏈碼的背書策略档叔,為目標(biāo)peer節(jié)點(diǎn)啟動一個chaincode容器桌粉。注意-P參數(shù)。這是我們需要指定的當(dāng)這個chaincode的交易需要被驗(yàn)證的時侯的背書策略蹲蒲。

在下面的命令中番甩,你會注意到我們指定-P "OR ('Org0MSP.member','Org1MSP.member')"作為背書策略。這意味著我們需要Org1或者Org2組織中的其中一個的節(jié)點(diǎn)的背書即可(即只有一個背書)届搁。如果我們改變語法為AND那么我們就需要2個背書者缘薛。

有關(guān)更多背書策略的詳細(xì)信息請參考背書策略

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初始化鏈碼會慢點(diǎn)卡睦,因?yàn)闀热グ惭b相關(guān)鏡像宴胧。不過一旦在channel初始化過后,我們不再需要-l指定語言表锻,只要告訴channel對應(yīng)鏈碼的名稱即可恕齐。

實(shí)例化鏈上代碼主要是在Peer所在的機(jī)器上對前面安裝好的鏈上代碼進(jìn)行包裝,生成對應(yīng)Channel的Docker鏡像和Docker容器瞬逊。并且在實(shí)例化時我們可以指定背書策略显歧。

1.9.5. 查詢

讓我們查詢一下a的值,以確保鏈碼被正確實(shí)例化确镊,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)10b賬戶。這個交易將創(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. 查詢

讓我們確認(rèn)下我們之前的調(diào)用被正確地執(zhí)行了拷肌。我們初始化了a的值為100,在上一次調(diào)用的時侯轉(zhuǎn)移了10b旨巷。因此巨缘,查詢a應(yīng)該展示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é)點(diǎn)上查詢

前面的操作都是在org1下面做的采呐,那么處于同一個區(qū)塊鏈(同一個Channel下)的org2若锁,是否會看到org1的更改呢?我們試著給peer0.org2安裝鏈上代碼:

先切換到peer0.org2節(jié)點(diǎn):

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ū)嵗诵竿颍簿褪钦f對應(yīng)的區(qū)塊已經(jīng)生成了拴清,所以在org2不能再次初始化靶病。我們直接運(yùn)行查詢命令:

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.....

可以看到依然可以進(jìn)行查詢,且值都是同步的口予。

這里稍微比之前的查詢花費(fèi)的時間久點(diǎn)娄周,這是因?yàn)?code>peer0.org2也需要生成Docker鏡像,創(chuàng)建對應(yī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é)點(diǎn)的文件系統(tǒng)中同時包含了在channel.tx的信道配置舷礼。

  • joinChannel命令被4個peer節(jié)點(diǎn)執(zhí)行鹃彻,作為之前產(chǎn)生的genesis block的輸入。這個命令介紹了peer節(jié)點(diǎn)加入<your_channel_name>以及利用<your_channel_name>.block去創(chuàng)建一條鏈妻献。

  • 現(xiàn)在我們有了由4個peer節(jié)點(diǎn)以及2個組織構(gòu)成的信道蛛株。這是我們的TwoOrgsChannel配置文件。

  • peer0.org1.example.compeer1.org1.example.com屬于Org1;peer0.org2.example.compeer1.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.txOrg2MSPanchors.tx配置到排序服務(wù)來實(shí)現(xiàn)anchor peer的更新笋粟。

  • 一個鏈碼-chaincode_example02被安裝在peer0.org1.example.com。

  • 這個鏈碼在peer0.org1.example.com被實(shí)例化析蝴。實(shí)例化過程將鏈碼添加到信道上害捕,并啟動peer節(jié)點(diǎn)對應(yīng)的容器,并且初始化和鏈碼服務(wù)有關(guān)的鍵值對闷畸。示例的初始化的值是[”a“,”100“吨艇,”b“,”200“]腾啥。實(shí)例化的結(jié)果是一個名為dev-peer0.org1.example.com-mycc-1.0的容器啟動了。

  • 實(shí)例化過程同樣為背書策略傳遞相關(guān)參數(shù)冯吓。策略被定義為-P "OR ('Org1MSP.member','Org2MSP.member')"倘待,意思是任何交易必須被Org1或者Org2背書。

  • 一個針對a的查詢發(fā)往peer0.org1.example.com组贺。鏈碼服務(wù)已經(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. 這指明了什么?

為了能夠正確地在賬本上進(jìn)行讀寫操作羞芍,鏈碼服務(wù)必須被安裝在peer節(jié)點(diǎn)上哗戈。此外,每個peer節(jié)點(diǎn)的鏈碼服務(wù)的容器除了init或者傳統(tǒng)的交易-讀/寫-針對該鏈碼服務(wù)執(zhí)行(例如查詢a的值)荷科,在其他情況下不會啟動唯咬。交易導(dǎo)致容器的啟動。當(dāng)然步做,所有信道中的節(jié)點(diǎn)都持有以塊的形式順序存儲的不可變的賬本精確的備份副渴,以及狀態(tài)數(shù)據(jù)庫來保存前狀態(tài)的快照。這包括了沒有在其上安裝鏈碼服務(wù)的peer節(jié)點(diǎn)(例如peer1.org1.example.compeer1.org2.example.com)全度。最后煮剧,鏈碼在被安裝后將是可達(dá)狀態(tài),因?yàn)樗呀?jīng)被實(shí)例化了(例如peer0.org2.example.com)将鸵。

1.9.11. 我如何查詢這些交易勉盅?

檢查CLI容器的日志。

docker logs -f cli

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

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. 我如何查看鏈碼日志草娜?

檢查每個獨(dú)立的鏈碼服務(wù)容器來查看每個容器內(nèi)的分隔的交易。下面是每個鏈碼服務(wù)容器的日志的組合:

$ 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示例給我們提供了兩種風(fēng)格的Docker Compose文件痒筒,它們都繼承自docker-compose-base.yamlbase目錄下)宰闰。我們的第一種類型,docker-compose-cli.yaml給我們提供了一個CLI容器簿透,以及一個orderer容器移袍,四個peer容器。

注意:本節(jié)的剩余部分涵蓋了為SDK設(shè)計(jì)的docker-compose文件老充。有關(guān)運(yùn)行這些測試的詳細(xì)信息葡盗,請參閱Node SDK倉庫。

第二種風(fēng)格是docker-compose-e2e.yaml啡浊,被構(gòu)造為使用Node.js SDK來運(yùn)行端到端測試觅够。除了SDK的功能之外胶背,它主要的區(qū)別在于它有運(yùn)行fabric-ca服務(wù)的容器。因此喘先,我們能夠向組織的CA節(jié)點(diǎn)發(fā)送REST的請求用于注冊和登記钳吟。

如果你在沒有運(yùn)行byfn.sh腳本的情況下,想使用docker-compose-e2e.yaml苹祟,我們需要進(jìn)行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ù)庫可以從默認(rèn)的goleveldb切換到CouchDB。鏈碼功能同樣能使用CouchDB庄呈。但是蜕煌,CouchDB提供了額外的能力,可以根據(jù)JSON形式的鏈碼服務(wù)數(shù)據(jù)诬留,提供更加豐富以及復(fù)雜的查詢斜纪。

使用CouchDB代替默認(rèn)的數(shù)據(jù)庫(goleveldb),除了在啟動網(wǎng)絡(luò)的時侯傳遞docker-compose-couch.yaml之外文兑,請遵循前面提到的生成配置文件的過程:

使用CouchDB啟動網(wǎng)絡(luò):

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容器端口映射到主機(jī)端口盒刚,請確保你意識到了安全性的影響。在開發(fā)環(huán)境中映射端口可以使CouchDB REST API可用绿贞,并允許通過CouchDB Web界面(Fauxton)對數(shù)據(jù)庫進(jìn)行可視化因块。生產(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

進(jìn)入CLI容器:

yuyangdeMacBook-Pro:first-network yuyang$ docker exec -it cli bash

切換節(jié)點(diǎn)到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

設(shè)置下channel變量:

export CHANNEL_NAME=mychannel

實(shí)例化鏈碼:

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ù)進(jìn)行增刪改查:

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中運(yùn)行常規(guī)的查詢(例如讀取marble2):

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

marble2的輸出應(yīng)該顯示為如下:

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

輸出應(yīng)該在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"]}'

輸出應(yīng)該顯示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.

怕翻譯的不準(zhǔn)確,誤人子弟梢杭。下面的內(nèi)容是我在其他地方摘取的温兼,可以了解一下:

狀態(tài)數(shù)據(jù)庫包括LevelDB和CouchDB。LevelDB是嵌入在peer進(jìn)程中的默認(rèn)鍵/值狀態(tài)數(shù)據(jù)庫武契,CouchDB是一個可選的外部狀態(tài)數(shù)據(jù)庫募判。與LevelDB鍵/值存儲一樣,CouchDB可以存儲任何以chaincode建模的二進(jìn)制數(shù)據(jù)(CouchDB附件函數(shù)在內(nèi)部用于非json二進(jìn)制數(shù)據(jù))咒唆。但是届垫,當(dāng)chaincode值(例如,資產(chǎn))被建模為JSON數(shù)據(jù)時全释,作為JSON文檔存儲装处,CouchDB支持對chaincode數(shù)據(jù)進(jìn)行豐富的查詢。

LevelDB和CouchDB都支持核心chaincode操作浸船,例如獲取和設(shè)置一個鍵(資產(chǎn))妄迁,并根據(jù)鍵進(jìn)行查詢。鍵可以通過范圍查詢李命,可以對組合鍵進(jìn)行建模登淘,以支持針對多個參數(shù)的等價查詢。例如封字,作為所有者的組合鍵黔州,資產(chǎn)id可以用于查詢某個實(shí)體擁有的所有資產(chǎn)。這些基于key的查詢可以用于針對賬本的只讀查詢周叮,以及更新總賬的事務(wù)辩撑。

如果將資產(chǎn)建模為JSON并使用CouchDB,那么就可以使用chaincode中的CouchDB JSON查詢語言對chaincode數(shù)據(jù)值執(zhí)行復(fù)雜的富查詢仿耽,這些類型的查詢對于理解賬本上的內(nèi)容很有幫助合冀。對于這些類型的查詢,事務(wù)協(xié)議響應(yīng)通常對客戶端應(yīng)用程序有用项贺,但通常不會作為事務(wù)提交到排序服務(wù)君躺。事實(shí)上,也無法保證結(jié)果集在chaincode執(zhí)行與富查詢提交時間之間的穩(wěn)定性开缎,因此使用富查詢的結(jié)果去執(zhí)行最終的事務(wù)更新操作是不合適的棕叫,除非可以保證結(jié)果集在chaincode執(zhí)行時間與提交時間之間的穩(wěn)定性,或者可以處理在后續(xù)交易中的潛在變化奕删。例如俺泣,如果對Alice所擁有的所有資產(chǎn)執(zhí)行一個富查詢并將其傳輸給Bob,那么一個新的資產(chǎn)可能會被另一個事務(wù)分配給Alice,這是在chaincode執(zhí)行時間和提交時間之間的另一個事務(wù)伏钠,可能此過程中會錯過這個“虛值”横漏。

CouchDB作為一個獨(dú)立的數(shù)據(jù)庫進(jìn)程與peer一起運(yùn)行,因此在設(shè)置熟掂、管理和操作方面有額外的考慮缎浇。我們可以考慮從默認(rèn)的嵌入式LevelDB開始,如果需要額外的復(fù)雜的富查詢赴肚,可以轉(zhuǎn)移到CouchDB素跺。將chaincode資產(chǎn)數(shù)據(jù)建模為JSON是一種很好的做法,這樣我們就可以在將來執(zhí)行需要的復(fù)雜的富查詢誉券。

1.13. 關(guān)于數(shù)據(jù)持久化的提示

如果需要在peer容器或者CouchDB容器進(jìn)行數(shù)據(jù)持久化指厌,一種選擇是將docker容器內(nèi)相應(yīng)的目錄掛載到容器所在的宿主機(jī)的一個目錄中。例如横朋,你可以添加下列的兩行到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)絡(luò)是全新的。使用以下命令來移除之前生成的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)

你可能由于運(yùn)行了以前的鏈碼服務(wù)(例如dev-peer1.org2.example.com-mycc-1.0dev-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 ""

那么你沒有正確設(shè)置FABRIC_CFG_PATH環(huán)境變量决帖。configtxgen工具需要這個變量才能找到configtx.yaml厕九。返回并執(zhí)行export FABRIC_CFG_PATH=$PWD,然后重新創(chuàng)建channel配置地回。

  • 要清理網(wǎng)絡(luò)扁远,請使用down選項(xiàng):
./byfn.sh -m down

如果你看到一條指示你依然有“active endpoints”,執(zhí)行以下命令清理你的Docker網(wǎng)絡(luò)刻像。這將會清除你之前的網(wǎng)絡(luò)并且給你一個全新的環(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)境搭建的詳細(xì)過程
作者:深藍(lán)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市细睡,隨后出現(xiàn)的幾起案子谷羞,更是在濱河造成了極大的恐慌,老刑警劉巖溜徙,帶你破解...
    沈念sama閱讀 206,378評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件湃缎,死亡現(xiàn)場離奇詭異,居然都是意外死亡蠢壹,警方通過查閱死者的電腦和手機(jī)嗓违,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來图贸,“玉大人蹂季,你說我怎么就攤上這事冕广。” “怎么了乏盐?”我有些...
    開封第一講書人閱讀 152,702評論 0 342
  • 文/不壞的土叔 我叫張陵佳窑,是天一觀的道長。 經(jīng)常有香客問我父能,道長,這世上最難降的妖魔是什么净神? 我笑而不...
    開封第一講書人閱讀 55,259評論 1 279
  • 正文 為了忘掉前任何吝,我火速辦了婚禮,結(jié)果婚禮上鹃唯,老公的妹妹穿的比我還像新娘爱榕。我一直安慰自己,他們只是感情好坡慌,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,263評論 5 371
  • 文/花漫 我一把揭開白布黔酥。 她就那樣靜靜地躺著,像睡著了一般洪橘。 火紅的嫁衣襯著肌膚如雪跪者。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,036評論 1 285
  • 那天熄求,我揣著相機(jī)與錄音渣玲,去河邊找鬼。 笑死弟晚,一個胖子當(dāng)著我的面吹牛忘衍,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播卿城,決...
    沈念sama閱讀 38,349評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼枚钓,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了瑟押?” 一聲冷哼從身側(cè)響起搀捷,我...
    開封第一講書人閱讀 36,979評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎勉耀,沒想到半個月后指煎,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,469評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡便斥,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,938評論 2 323
  • 正文 我和宋清朗相戀三年至壤,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片枢纠。...
    茶點(diǎn)故事閱讀 38,059評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡像街,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情镰绎,我是刑警寧澤脓斩,帶...
    沈念sama閱讀 33,703評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站畴栖,受9級特大地震影響随静,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜吗讶,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,257評論 3 307
  • 文/蒙蒙 一燎猛、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧照皆,春花似錦重绷、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,262評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至瘟滨,卻和暖如春候醒,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背室奏。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工火焰, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人胧沫。 一個月前我還...
    沈念sama閱讀 45,501評論 2 354
  • 正文 我出身青樓昌简,卻偏偏與公主長得像,于是被迫代替她去往敵國和親绒怨。 傳聞我的和親對象是個殘疾皇子纯赎,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,792評論 2 345

推薦閱讀更多精彩內(nèi)容