上一章我們啟動了區(qū)塊鏈所需要的所有節(jié)點诽里,接下來我們將開始部署我們的區(qū)塊鏈。
創(chuàng)建Channel
之前丑勤,我們使用configtxgen工具生成了配置交易channel.tx稳强,我們將會傳遞這個配置交易到orderer作為創(chuàng)建channel請求的一部分,現(xiàn)在進(jìn)入cli節(jié)點容器:
docker exec -it cli /bin/bash
創(chuàng)建channel:
export CHANNEL_NAME=mychannel
peer channel create -o orderer0.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/orderer0.example.com/msp/tlscacerts/tlsca.example.com-cert.pem
輸出結(jié)果:
我理解此命令會在orderer創(chuàng)建channel间涵,并生成一個創(chuàng)世塊<channel-ID.block>仁热,也就是mychannel.block。該block可以用來加入channel時使用勾哩,它包含了channel.tx中的配置信息抗蠢。
注意,因為我們有3個orderer節(jié)點思劳,所以還需要對orderer1和orderer2節(jié)點用上面的命令創(chuàng)建channel迅矛。
加入Channel
上一步我們在orderer中根據(jù)channel.tx配置文件創(chuàng)建了我們的channel,接下來我們需要把每個peer節(jié)點加入到channel中:
peer channel join -b mychannel.block
2017-12-21 02:09:15.225 UTC [msp] GetLocalMSP -> DEBU 001 Returning existing local MSP
2017-12-21 02:09:15.225 UTC [msp] GetDefaultSigningIdentity -> DEBU 002 Obtaining default signing identity
2017-12-21 02:09:15.234 UTC [channelCmd] InitCmdFactory -> INFO 003 Endorser and orderer connections initialized
2017-12-21 02:09:15.235 UTC [msp/identity] Sign -> DEBU 004 Sign: plaintext: 0A9F070A5B08011A0B08CBAFECD10510...C6B619CDF6DA1A080A000A000A000A00
2017-12-21 02:09:15.235 UTC [msp/identity] Sign -> DEBU 005 Sign: digest: 796A612EDDAC69FAF3E174FA4EE08302E19FE0916BCD63688BB041B9B859C39E
2017-12-21 02:09:15.348 UTC [channelCmd] executeJoin -> INFO 006 Peer joined the channel!
2017-12-21 02:09:15.348 UTC [main] main -> INFO 007 Exiting.....
因為目前我們用的cli容器潜叛,環(huán)境變量指定的是peer0.org1節(jié)點秽褒,所以我們還需要修改環(huán)境變量,讓所有其他的peer節(jié)點容器都加入channel威兜,要注意销斟,切換到org2的時候?qū)?yīng)的所有證書環(huán)境變量都要換,不然會報證書驗證的錯誤:
export CORE_PEER_TLS_CERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer1.org1.example.com/tls/server.crt
export CORE_PEER_TLS_KEY_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer1.org1.example.com/tls/server.key
export 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
export CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp
export CORE_PEER_ADDRESS=peer1.org1.example.com:7051
peer channel join -b mychannel.block
export CORE_PEER_LOCALMSPID=Org2MSP
export CORE_PEER_TLS_CERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/server.crt
export CORE_PEER_TLS_KEY_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/server.key
export 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
export CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp
export CORE_PEER_ADDRESS=peer0.org2.example.com:7051
peer channel join -b mychannel.block
export CORE_PEER_ADDRESS=peer1.org2.example.com:7051
export CORE_PEER_TLS_CERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer1.org2.example.com/tls/server.crt
export CORE_PEER_TLS_KEY_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/peers/peer1.org2.example.com/tls/server.key
export 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
export CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp
export CORE_PEER_ADDRESS=peer1.org2.example.com:7051
peer channel join -b mychannel.block
現(xiàn)在椒舵,orderer節(jié)點已經(jīng)創(chuàng)建了對應(yīng)的channel票堵,并且所有的peer節(jié)點都加入了該channel。
記得再把環(huán)境變量全部切回org1~
export CORE_PEER_LOCALMSPID=Org1MSP
export CORE_PEER_TLS_CERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/server.crt
export CORE_PEER_TLS_KEY_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/server.key
export 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
export CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp
export CORE_PEER_ADDRESS=peer0.org1.example.com:7051
更新AnchorPeer
我們通過傳遞之前生產(chǎn)的Org1MSPanchor.tx和Org2MSPanchor.tx以及channel的名字到orderer來把channel信息更新到每個anchorPeer上:
export ORDERER_CA=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer0.example.com/msp/tlscacerts/tlsca.example.com-cert.pem
peer channel update -o orderer0.example.com:7050 -c $CHANNEL_NAME -f ./channel-artifacts/${CORE_PEER_LOCALMSPID}anchors.tx --tls $CORE_PEER_TLS_ENABLED --cafile $ORDERER_CA
像之前那樣切到org2的環(huán)境變量逮栅,然后再執(zhí)行一遍上面的代碼悴势,再把環(huán)境切回org1。
安裝chaincode
區(qū)塊鏈上唯一的業(yè)務(wù)邏輯就是chaincode了措伐,他是我們業(yè)務(wù)的核心部分特纤,想要在區(qū)塊鏈上運行我們自己的業(yè)務(wù),就需要把chaincode安裝到每個peer節(jié)點:
peer chaincode install -n mycc -v 1.0 -p github.com/chaincode/chaincode_example02/go/
mycc是鏈碼的名字侥加,1.0是版本號捧存,后面的是鏈碼文件夾所在路徑。
2017-12-21 06:09:42.465 UTC [msp] GetLocalMSP -> DEBU 001 Returning existing local MSP
2017-12-21 06:09:42.465 UTC [msp] GetDefaultSigningIdentity -> DEBU 002 Obtaining default signing identity
2017-12-21 06:09:42.465 UTC [chaincodeCmd] checkChaincodeCmdParams -> INFO 003 Using default escc
2017-12-21 06:09:42.465 UTC [chaincodeCmd] checkChaincodeCmdParams -> INFO 004 Using default vscc
2017-12-21 06:09:42.465 UTC [chaincodeCmd] getChaincodeSpec -> DEBU 005 java chaincode disabled
2017-12-21 06:09:42.515 UTC [golang-platform] getCodeFromFS -> DEBU 006 getCodeFromFS github.com/chaincode/chaincode_example02/go/
2017-12-21 06:09:42.912 UTC [golang-platform] func1 -> DEBU 007 Discarding GOROOT package fmt
2017-12-21 06:09:42.912 UTC [golang-platform] func1 -> DEBU 008 Discarding provided package github.com/hyperledger/fabric/core/chaincode/shim
2017-12-21 06:09:42.912 UTC [golang-platform] func1 -> DEBU 009 Discarding provided package github.com/hyperledger/fabric/protos/peer
2017-12-21 06:09:42.912 UTC [golang-platform] func1 -> DEBU 00a Discarding GOROOT package strconv
2017-12-21 06:09:42.915 UTC [golang-platform] GetDeploymentPayload -> DEBU 00b done
2017-12-21 06:09:42.921 UTC [msp/identity] Sign -> DEBU 00c Sign: plaintext: 0AA0070A5C08031A0C08A6A0EDD10510...F619FF0E0000FFFFACD4020D001C0000
2017-12-21 06:09:42.921 UTC [msp/identity] Sign -> DEBU 00d Sign: digest: F65DC46F817A94C31FC270CB0B7C1ECDEA662B5B421C0F383A4FED0D9B4BBC0E
2017-12-21 06:09:42.927 UTC [chaincodeCmd] install -> DEBU 00e Installed remotely response:<status:200 payload:"OK" >
2017-12-21 06:09:42.927 UTC [main] main -> INFO 00f Exiting.....
接下來修改環(huán)境變量在其他所有Peer節(jié)點都安裝上該鏈碼。
實例化chaincode
接下來昔穴,我們需要在channel上實例化chaincode镰官,我們只需要在一個peer節(jié)點上實例化channel即可:
peer chaincode instantiate -o orderer0.example.com:7050 --tls $CORE_PEER_TLS_ENABLED --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer0.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.member','Org2MSP.member')"
這里-c是實例化的參數(shù),-P是指定背書策略吗货,示例中的策略是Org1和Org2任何一個member節(jié)點驗證過就可以通過泳唠。
2017-12-21 08:11:34.074 UTC [msp] GetLocalMSP -> DEBU 001 Returning existing local MSP
2017-12-21 08:11:34.075 UTC [msp] GetDefaultSigningIdentity -> DEBU 002 Obtaining default signing identity
2017-12-21 08:11:34.085 UTC [chaincodeCmd] checkChaincodeCmdParams -> INFO 003 Using default escc
2017-12-21 08:11:34.086 UTC [chaincodeCmd] checkChaincodeCmdParams -> INFO 004 Using default vscc
2017-12-21 08:11:34.087 UTC [chaincodeCmd] getChaincodeSpec -> DEBU 005 java chaincode disabled
2017-12-21 08:11:34.088 UTC [msp/identity] Sign -> DEBU 006 Sign: plaintext: 0AAA070A6608031A0B08B6D9EDD10510...324D53500A04657363630A0476736363
2017-12-21 08:11:34.088 UTC [msp/identity] Sign -> DEBU 007 Sign: digest: 97DBB3BDAD5AEC4690D45965199DA60ED7134CFF13B4F272C50980DEDBF4987A
2017-12-21 08:11:34.905 UTC [msp/identity] Sign -> DEBU 008 Sign: plaintext: 0AAA070A6608031A0B08B6D9EDD10510...BE5D7377C426346015BE844429A8593E
2017-12-21 08:11:34.905 UTC [msp/identity] Sign -> DEBU 009 Sign: digest: EA1AACD22982F05403BFBF5FBC088B332EF409D3B3C6C5BFA0CFBE8B42CD10B1
該操作會在docker新創(chuàng)建一個容器:dev-peer0.org1.example.com-mycc-1.0,以后對于我們在鏈上的操作宙搬,如果是那個節(jié)點第一次訪問笨腥,都將創(chuàng)建一個自己的新容器。
查詢Query
現(xiàn)在我們可以在區(qū)塊鏈操作一些業(yè)務(wù)了勇垛,比如查詢:
peer chaincode query -C $CHANNEL_NAME -n mycc -c '{"Args":["query","a"]}'
2017-12-21 08:36:27.925 UTC [msp] GetLocalMSP -> DEBU 001 Returning existing local MSP
2017-12-21 08:36:27.925 UTC [msp] GetDefaultSigningIdentity -> DEBU 002 Obtaining default signing identity
2017-12-21 08:36:27.925 UTC [chaincodeCmd] checkChaincodeCmdParams -> INFO 003 Using default escc
2017-12-21 08:36:27.926 UTC [chaincodeCmd] checkChaincodeCmdParams -> INFO 004 Using default vscc
2017-12-21 08:36:27.926 UTC [chaincodeCmd] getChaincodeSpec -> DEBU 005 java chaincode disabled
2017-12-21 08:36:27.927 UTC [msp/identity] Sign -> DEBU 006 Sign: plaintext: 0AAB070A6708031A0C088BE5EDD10510...6D7963631A0A0A0571756572790A0161
2017-12-21 08:36:27.927 UTC [msp/identity] Sign -> DEBU 007 Sign: digest: 9A8CC8B5A4EAAB6027E7365335CAFEA0E2B5B16BBBC8618AD7833EE4615ACED3
Query Result: 100
2017-12-21 08:36:27.959 UTC [main] main -> INFO 008 Exiting.....
參數(shù)和方法名是chaincode中定義的脖母,Query Result: 100是返回的結(jié)果。
同理闲孤,我們可以連接到任何peer節(jié)點查詢谆级,得到相同的結(jié)果。
調(diào)用Invoke
調(diào)用和查詢有點區(qū)別讼积,查詢不需要訪問orderer節(jié)點和其他peer節(jié)點哨苛,只需要查詢當(dāng)前peer結(jié)點賬本中的信息即可返回給客戶端,不需要修改賬本币砂,效率很高。但調(diào)用是需要修改賬本數(shù)據(jù)的玻侥,所以需要其他節(jié)點的驗證决摧,以及orderer節(jié)點的共識入鏈,性能會低一些:
peer chaincode invoke -o orderer0.example.com:7050 --tls $CORE_PEER_TLS_ENABLED --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer0.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C $CHANNEL_NAME -n mycc -c '{"Args":["invoke","a","b","10"]}'
2017-12-21 08:42:21.721 UTC [msp] GetLocalMSP -> DEBU 001 Returning existing local MSP
2017-12-21 08:42:21.721 UTC [msp] GetDefaultSigningIdentity -> DEBU 002 Obtaining default signing identity
2017-12-21 08:42:21.731 UTC [chaincodeCmd] checkChaincodeCmdParams -> INFO 003 Using default escc
2017-12-21 08:42:21.731 UTC [chaincodeCmd] checkChaincodeCmdParams -> INFO 004 Using default vscc
2017-12-21 08:42:21.731 UTC [chaincodeCmd] getChaincodeSpec -> DEBU 005 java chaincode disabled
2017-12-21 08:42:21.732 UTC [msp/identity] Sign -> DEBU 006 Sign: plaintext: 0AAB070A6708031A0C08EDE7EDD10510...696E766F6B650A01610A01620A023130
2017-12-21 08:42:21.732 UTC [msp/identity] Sign -> DEBU 007 Sign: digest: 4294413C4D0C3EF5F5FA1926E148847AADD9B92FA8CB5748ED97F22265820307
2017-12-21 08:42:21.787 UTC [msp/identity] Sign -> DEBU 008 Sign: plaintext: 0AAB070A6708031A0C08EDE7EDD10510...1C2479651CD96F9DEA3357AF48E207AE
2017-12-21 08:42:21.787 UTC [msp/identity] Sign -> DEBU 009 Sign: digest: 8BB4476D2D9C834890EB10420952A76C8FA6EAD91F11D567334CC25EF9DCA232
2017-12-21 08:42:21.789 UTC [chaincodeCmd] chaincodeInvokeOrQuery -> DEBU 00a ESCC invoke result: version:1 response:<status:200 message:"OK" > payload:"\n \250v(\333+\220m@R\260\026\254\215YH\334\010\353\233\261\202\034\0261\263r\201\251\215\035i\345\022Y\nE\022\024\n\004lscc\022\014\n\n\n\004mycc\022\002\010\003\022-\n\004mycc\022%\n\007\n\001a\022\002\010\003\n\007\n\001b\022\002\010\003\032\007\n\001a\032\00290\032\010\n\001b\032\003210\032\003\010\310\001\"\013\022\004mycc\032\0031.0" endorsement:<endorser:"\n\007Org1MSP\022\226\006-----BEGIN CERTIFICATE-----\nMIICGTCCAb+gAwIBAgIQXkV92Ig2qOYq2S0nig6T/TAKBggqhkjOPQQDAjBzMQsw\nCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZy\nYW5jaXNjbzEZMBcGA1UEChMQb3JnMS5leGFtcGxlLmNvbTEcMBoGA1UEAxMTY2Eu\nb3JnMS5leGFtcGxlLmNvbTAeFw0xNzEyMjEwMTQ5MzZaFw0yNzEyMTkwMTQ5MzZa\nMFsxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1T\nYW4gRnJhbmNpc2NvMR8wHQYDVQQDExZwZWVyMC5vcmcxLmV4YW1wbGUuY29tMFkw\nEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEowmXLpFPfiapHxmLRGC7e8Zukihyy+7U\nijn4ABLmePpbWGX7ERXhUHdpadASg9odrmgGoR7xWBlW4CXJu4cHv6NNMEswDgYD\nVR0PAQH/BAQDAgeAMAwGA1UdEwEB/wQCMAAwKwYDVR0jBCQwIoAgXSePwrfpRDhL\no5UBOAVFhLcezHsWM4Az60x4rK8EgG0wCgYIKoZIzj0EAwIDSAAwRQIhANc4vuVc\nhjs4h5V1d7ldR4UGzLzWvjwF9ziXp70YLTnCAiB/729Keu+G2MPdN6/5Nwtlv/FE\nTnbO05IpwkI7FKXrqA==\n-----END CERTIFICATE-----\n" signature:"0E\002!\000\221\205\360\246\257_\316\231\244,\007\013\226YSS\336Z\352U\375\343?h\306\253\017\250\317\237\177\370\002 g\221\361\303Bh]i:\351\\tc\000\021:\034$ye\034\331o\235\3523W\257H\342\007\256" >
2017-12-21 08:42:21.789 UTC [chaincodeCmd] chaincodeInvokeOrQuery -> INFO 00b Chaincode invoke successful. result: status:200
2017-12-21 08:42:21.790 UTC [main] main -> INFO 00c Exiting.....
通過下面的命令凑兰,能查到對應(yīng)操作的日志:
$ docker logs dev-peer0.org1.example.com-mycc-1.0
ex02 Init
Aval = 100, Bval = 200
ex02 Invoke
Query Response:{"Name":"a","Amount":"100"}
ex02 Invoke
Aval = 90, Bval = 210
總結(jié)
為了在賬本上成功的執(zhí)行讀寫操作掌桩,chaincode必須安裝在peer上。另外姑食,chaincode容器直到實例化或者傳統(tǒng)交易-讀寫執(zhí)行的時候(例:查詢a賬戶的值)波岛,chaincode容器才會啟動。channel中的每個節(jié)點都維護(hù)了賬本的完全復(fù)制音半,存儲了不可改變的则拷、序列化的記錄區(qū)塊以及state database用于保存當(dāng)前的fabric狀態(tài)。即便是那些在最初沒有安裝chaincode的節(jié)點曹鸠,在安裝chaincode之后煌茬,也會自動同步賬本。