本文參考:http://hyperledger-fabric.readthedocs.io/en/latest/build_network.html
這里我們學習建立第一個Hyperledger Fabric network,包括兩個organization(每個包括2個peer節點),以及一個“solo”的ordering service。
前提條件:安裝docker、docker compose、go環境、npm、node.js,下載並安裝好了Hyberledger Fabric Samples。
安裝Hyberledger Fabric Samples簡介:
- 建立一個目錄
mkdir hyberledger-fabric
cd hyberledger-fabric
- 克隆一個倉庫
git clone https://github.com/hyperledger/fabric-samples.git
- 下載特定的二進制文件
curl -sSL https://raw.githubusercontent.com/hyperledger/fabric/master/scripts/bootstrap-1.0.0-rc1.sh | bash
上述命令會下載自動化部署腳本,同時也會下載平台特定使用的二進制文件cryptogen,configtxgen,configtxlator, 以及peer,把他們放到上述倉庫的bin目錄下
接下來把bin目錄加入到PATH環境變量中
vi /etc/profile
打開profile然后把下面語句添加進去即可
export PATH=/home/parallels/hyberledger-fabric/bin:$PATH
1.嘗試run first-network
cd fabric-samples/first-network
這里提供了一個腳本,byfn.sh,我們可以查看其的使用方法
如果你沒有指定channel的名稱,則該腳本則會使用默認的channel名稱(mychannel)
CLI的超時參數(-t flag)可以選擇,如果不選擇,那么CLI容器將在腳本結束后退出。
2.生成network artifacts
執行如下命令:
./byfn.sh -m generate
遇到需要選擇的地方選擇y,會看到如下日志
這一步生成了network entity所需要的certificates以及keys,genesis block用於獲取用於配置channel的ordering service以及transaction配置的集合。
3.啟動network
接下來輸入以下命令啟動network,回復y
./byfn.sh -m up
可以看到如下輸出結果
./byfn.sh -m up Starting with channel 'mychannel' and CLI timeout of '10000' Continue (y/n)?y proceeding ... Creating network "net_byfn" with the default driver Creating peer0.org1.example.com Creating peer1.org1.example.com Creating peer0.org2.example.com Creating orderer.example.com Creating peer1.org2.example.com Creating cli ____ _____ _ ____ _____ / ___| |_ _| / \ | _ \ |_ _| \___ \ | | / _ \ | |_) | | | ___) | | | / ___ \ | _ < | | |____/ |_| /_/ \_\ |_| \_\ |_| Channel name : mychannel Creating channel...
日志從這里開始,這將啟動所有的容器,形成這個完整的P2P的應用場景。
啟動成功后會打印如下日志:
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 PEER3 on channel 'mychannel' is successful ===================== ===================== All GOOD, BYFN execution completed ===================== _____ _ _ ____ | ____| | \ | | | _ \ | _| | \| | | | | | | |___ | |\ | | |_| | |_____| |_| \_| |____/
通過上述日志能夠看到不同的transaction。
4.關閉network
輸入如下命令
./byfn.sh -m down
能夠看到輸出日志如下:
./byfn.sh -m down Stopping with channel 'mychannel' and CLI timeout of '10000' Continue (y/n)?y proceeding ... WARNING: The CHANNEL_NAME variable is not set. Defaulting to a blank string. WARNING: The TIMEOUT variable is not set. Defaulting to a blank string. Removing network net_byfn 468aaa6201ed ... Untagged: dev-peer1.org2.example.com-mycc-1.0:latest Deleted: sha256:ed3230614e64e1c83e510c0c282e982d2b06d148b1c498bbdcc429e2b2531e91 ...
如果您想了解有關底層工具和引導機制的更多信息,請繼續閱讀。 在接下來的章節中,我們將介紹構建功能齊全的Hyperledger Fabric網絡的各種步驟和要求。
5.Crypto生成器
我們使用crytogen工具給我們不同的network entity生成加密證書(X509 certs)。這些證書代表了身份,當我們的entity在進行通信以及transact的時候進行簽名與驗證身份。
Cryptogen有一個配置文件crypto-config.yaml,包括了網絡拓撲,同時允許我們給organization以及component(隸屬於organization)生成一個證書與私鑰的集合。每一個organization被分配一個唯一的根證書(綁定了隸屬於Org的具體的component,包括peers與orderers)。通過給每個organization分配一個唯一的CA證書,我們正在模仿一個典型的網絡,參與的成員將使用自己的證書頒發機構頒發的證書。Hyperledger Fabric的transaction與通信均被entity的私鑰(keystore)進行簽名,截止被公鑰進行驗證(signcerts)。
這個配置文件中有一個計數(count)的變量,我們使用其定義organization中peer的數量,在本例中我們定義每一個Org有兩個peer。這里不會深入討論X.509證書以及公鑰框架。
在run這個工具之前,我們回顧一下crypto-config.yaml,請注意在ordererOrgs頭下面的“Name”, “Domain” 以及 “Specs”這三個參數。
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
network entity的命名規則約定如下:“{{.Hostname}}.{{.Domain}}”。因此,使用我們的ordering node作為參考,我們能看到一個名稱為 - orderer.example.com的ordering node,該node與Orderer的MSP ID關聯。 您還可以參考會員 Membership Service Providers (MSP)文檔,以便更深入地了解MSP。
我們運行cryptogen工具之后,生成的證書與秘鑰將會保存到crypto-config文件夾中。
6.配置transaction生成器
configtxgen tool用於創建如下配置項:
genesis block:是一個配置block用於初始化blockchain網絡以及channel的,同樣可以作為鏈上的第一個block
- orderer
genesis block
, - channel
channel configuration transaction
- 兩個anchor peer transactions,其中每一個對應一個peer org
如何使用該工具請查看, Channel Configuration (configtxgen)
orderer block是ordering service的genesis block,channel transaction file在channel創建時廣播給orderer。anchor peer transactions在channel定義了一個Org Anchor Peer。
Configtxgen有一個配置文件configtx.yaml,包括了sample network的定義。現有3個成員:一個Orderer Org以及兩個Peer Orgs(Org1 Org2,每個包括2個peer節點)。這個文件定義了一個聯合consortium,包括兩個Peer Org。注意該文件的頂部profile section。你會發現有兩個唯一的headers。一個用作orderer Genesis block - TwoOrgsOrdererGenesis
-,一個用作channel - TwoOrgsChannel。
后續我們在來看這些headers。
注意:sampleConsortium被定義在system-level profile中,接下來被channel-level profile引用。Channels存在在consortium的范圍內,所有的consortium都在network的范圍內。
這個配置文件包括了兩個附加的定義。一個就是每個Peer Org(peer0.org1.example.com
& peer0.org2.example.com
)的anchor節點,另外一個就是指向每個成員的MSP目錄的位置,基於此,我們可以將每個Org的根證書存放在orderer Genesis block中,這是一個很重要的概念。現在任意network entity與ordering service通信時就能對起數字簽名進行驗證。
7.運行tool
可以通過configtxgen
and cryptogen手動生成證書/密鑰以及各項配置文件。同樣,可以參考byfn.sh腳本實現。
接下來我們嘗試手動生成。
可以參考byfn.sh腳本中的generateCerts函數用來生成證書(這些證書被定義在crypto-config.yaml中的網絡配置所使用)所需要的命令。為了方便起見,我們提供一個參考如下。
首先,先跑起來cryptogen工具,我們的二進制文件都在bin目錄下,因此我們需要cd到tool所在的目錄下.
../bin/cryptogen generate --config=./crypto-config.yaml
接下來,我們會告訴configtxgen工具去哪找到需要調用的configtx.yaml文件。
首先,我們需要設置一個環境變量,用於告知configtxgen根據去哪找configtx.yaml配置文件。接下來,我們調用configtxgen工具創建orderer Genesis block
export FABRIC_CFG_PATH=$PWD
../bin/configtxgen -profile TwoOrgsOrdererGenesis -outputBlock ./channel-artifacts/genesis.block
接着,我們創建channel transaction artifact(channel.tx)。然后,確保替換$CHANNEL_NAME(這里我用zeychannel替換的)或設置環境變量,語句如下:
export CHANNEL_NAME=mychannel # this file contains the definitions for our sample channel ../bin/configtxgen -profile TwoOrgsChannel -outputCreateChannelTx ./channel-artifacts/channel.tx -channelID $CHANNEL_NAME
接着,我們在我們正在創建的channel上定義Org1的anchor節點。然后,確保替換$CHANNEL_NAME(這里我用zeychannel替換的)或設置環境變量,語句如下:
../bin/configtxgen -profile TwoOrgsChannel -outputAnchorPeersUpdate ./channel-artifacts/Org1MSPanchors.tx -channelID $CHANNEL_NAME -asOrg Org1MSP
然后,我們在相同的channel上定義Org2的anchor節點。
../bin/configtxgen -profile TwoOrgsChannel -outputAnchorPeersUpdate ./channel-artifacts/Org2MSPanchors.tx -channelID $CHANNEL_NAME -asOrg Org2MSP
8.啟動network
我們利用docker-compose腳本來啟動我們的network。docker-compose文件引用了我們之前下載的鏡像,並使用前面生成的genesis block來引導orderer。
working_dir: /opt/gopath/src/github.com/hyperledger/fabric/peer # command: /bin/bash -c './scripts/script.sh ${CHANNEL_NAME}; sleep $TIMEOUT' volumes
如果沒有注釋掉上面的命令的話,在network啟動的時候,其將執行所有的CLI命令,具體請見 What’s happening behind the scenes?節。我們需要分析每一步的功能及句法,因此我們一步步執行命令。
timeout的變量適合使用較高的數值,默認是60s。
啟動network,注意$CHANNEL_NAME,<pick_a_value>自己設定
CHANNEL_NAME=$CHANNEL_NAME TIMEOUT=<pick_a_value> docker-compose -f docker-compose-cli.yaml up -d
如果想看到實時日志,則不要加-d標示。如果需要日志流,則需要打開第二個終端進行操作。
9.環境變量
對於以下針對peer0.org1.example.com的CLI命令,我們需要使用以下給出的四個環境變量來介紹我們的命令。這些peer0.org1.example.com變量都被包含在CLI容器里,因此我們可以不用傳遞的操作它們。然而!,如果你想發送calls到其他peers或者orderer,你需要根據情況提供這些變量。打開docker-compose-base.yaml並查看具體的路徑信息,
# 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
10.創建並進入Channel
接下來進入到剛創建的CLI容器里面,
docker exec -it cli bash
如果成功則能看到如下信息
請回憶下我們使用configtxgen工具生成channel配置artifact-channel.tx。我們將把artifact作為創建channel的請求的一部分發送給orderer。
注意到在接下來的命令中我們發送了-- cafile作為命令的一部分。這個是orderer證書的本地路徑,使得我們可以驗證TLS握手。
我們使用-c flag 標注出我們的channel名稱,用-f flag標注出我們的channel 配置transaction。在本例中是channel.tx,然而你可以使用不同的名稱用於掛載配置transaction。使用下面創建channel的語句的時候注意channel-name。
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 replace the $CHANNEL_NAME variable appropriately peer channel create -o orderer.example.com:7050 -c $CHANNEL_NAME -f ./channel-artifacts/channel.tx --tls $CORE_PEER_TLS_ENABLED --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem
上述命令返回了一個genesis block- <channel-ID.block>
-我們可以通過這個id進入到channel。它包含channel.tx中指定的配置信息,創建成功后有如下輸出:
接下來的操作都需要在CLI容器中進行,在操作peer0.org1.example.com之外的peer時,需要記得相關環境變量的命令。
接下來我們把peer0.org1.example.com加入到channel中去,channel-ID.block是之前生成的,這里我的是zeychannel.block。
# By default, this joins ``peer0.org1.example.com`` only # the <channel-ID>.block was returned by the previous command peer channel join -b <channel-ID.block>
以下是成功的顯示
你可把其他的peer加入到該channel上,但是需要設置上述的四個環境變量。
11.安裝並實例化chaincode
我們這里只是使用已經存在的chaincode。
application通過chaincode與blockchain ledger進行交互。我們把chaincode安裝到execute與endorse我們transaction的peer上,接下來在channel上初始化chaincode。
首先,安裝sample go代碼到4個peer之一的peer上。以下命令把chaincode的源代碼放到了peer節點的文件系統上。
peer chaincode install -n zeychaincode -v 1.0 -p github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example02
安裝成功打印如下日志
接下來,在channel上實例化chaincode。這將在channel上初始化chaincode,同時設置chaincode的endorsement的策略,然后在目標peer上啟動chaincode容器。請注意-P參數,我們通過設置這個參數,來指定transaction的endorsement的需求level,用於驗證chaincode。
在下面的命令,我們定義了endorsement策略為-P "OR ('Org0MSP.member','Org1MSP.member')"。這表示我們需要隸屬於Org1或者Org2的peer進行“endorsement”(也就是說,只有一個endorsement)。如果把or改為and則說明我們需要兩個endorsement。
# be sure to replace the $CHANNEL_NAME environment variable # 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 $CORE_PEER_TLS_ENABLED --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 zeychannel -n zeychaincode -v 1.0 -c '{"Args":["init","a", "100", "b","200"]}' -P "OR ('Org1MSP.member','Org2MSP.member')"
請在 endorsement policies中查看更詳細的策略說明。
12.查詢
首先查詢a的值,確保chaincode已經正常的實例化,同時確保state DB已經被填充
# be sure to set the -C and -n flags appropriately peer chaincode query -C zeychannel -n zeychaincode -c '{"Args":["query","a"]}'
13.調用
讓我們從a賬戶轉移10個到b賬戶,這個命令將會創建新的block同時更新state DB。
# be sure to set the -C and -n flags appropriately peer chaincode invoke -o orderer.example.com:7050 --tls $CORE_PEER_TLS_ENABLED --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 zeychannel -n zeychaincode -c '{"Args":["invoke","a","b","10"]}'
然后查詢
# be sure to set the -C and -n flags appropriately peer chaincode query -C zeychannel -n zeychaincode -c '{"Args":["query","a"]}'
14.上述調用過程解析
- script.sh腳本在CLI容器內部執行,該腳本執行了createChannel命令,提供了channel名稱,同時使用channel.tx進行channel配置
- createChannel的輸出是一個genesis block,使用channel名稱命名的block,例如zeychannel.block,該block在peers的文件系統上存儲(個人理解就在chain上作為一個block存儲的),該block包括channel.tx指定的channel配置信息。
- 加入channel的命令對所有4個peer進行執行,把之前生成的genesis block作為輸入。這個join命令使得peers加入到了zeychannel(我自己創建的)里面,同時創建了一個以zeychannel.block作為開始的chain。
- 接着,我們擁有了由4個peer,兩個organization組成的channel。這都在我們
TwoOrgsChannel
profile.里面。 peer0.org1.example.com
與peer1.org1.example.com
隸屬於 Org1;peer0.org2.example.com 以及
peer1.org2.example.com
隸屬於 Org2。這些關系在crypto-config.yaml中定義,同時在我們的docker compose中指定了MSP的路徑。- Org1MSP (
peer0.org1.example.com
) 以及 Org2MSP (peer0.org2.example.com
)的anchor節點接下來被更新了。我們基於建立的channel把Org1MSPanchors.tx
與Org2MSPanchors.tx
的artifacts,發送給orderering service,以實現上述的更新。 - chaincode_example02被安裝在了
peer0.org1.example.com
與peer0.org2.example.com
- 接着chaincode在peer0.org2.example.com被實例化。實例化把chaincode加到channel上,並啟動目標peer的容器,接着初始化chaincode有關的鍵-值對( [“a”,”100” “b”,”200”])。實例化的過程導致了dev-peer0.org2.example.com-zeychaincode-1.0的啟動。
- 實例化需要有endorsement策略的參數,這里設置為-P "OR ('Org1MSP.member','Org2MSP.member')",表示任意transaction必須被Org1 或者 Org2的一個peer進行endorsed。
- 接下來把對“a”的查詢發送給peer0.org1.example.com,即在peer0.org1.example.com查詢a的值。chaincode之前已經安裝在了peer0.org1.example.com上,因此這個查詢將會針對Org1 peer0 啟動一個容器(dev-peer0.org1.example.com-zeychaincode-1.0),然后查詢結果得到返回,沒有任何寫的操作發生,因此返回值是100
- 接着調用請求發送給peer0.org1.example.com,把10個從a轉移到b。
- 然后chaincode在peer1.org2.example.com進行安裝。
- 然后一個查詢a的余額的請求發送到peer1.org2.example.com。這個啟動了第三個chaincode容器(dev-peer1.org2.example.com-mycc-1.0),90被返回。正確的反應了上述transaction,a的值被改為了10。