黎躍春
孔壹學院、ChainDesk 創始人兼 CEO
如果您有任何關於區塊鏈的問題,可以加入區塊鏈技術交流 QQ 羣 729666975 (進羣無需添加驗證信息,直接點擊下一步,等待管理員通過即可),我們會爲您一一解答。
從零到壹學習超級賬本理論加實戰爲一個系列,一共 23 講,包括超級賬本簡介、搭建環境、啓動網絡、測試鏈碼、區塊鏈應用開發等。今天我們將爲大家介紹從零到壹學習超級賬本理論加實戰第十講:node 測試。話不多說,馬上開啓我們的超級賬本理論加實戰學習之旅。
課程學習,添加莉莉微信 (kongyixueyuan) 獲取。
孔壹學院
關閉網絡
$ sudo ./byfn.sh -m down
進入到 fabric-samples/fabcar 目錄中
[code]
$ cd ../fabcar/
$ ls
[/code]
如果是完整的環境 , 目錄中應該包含如下文件 :
enrollAdmin.js invoke.js package.json query.js registerUser.js startFabric.sh
移除所有處於活動中的 Docker 容器
[code]
$ sudo docker rm -f $(docker ps -aq)
[/code]
docker rm : 刪除當前指定的 Docker 容器
docker rm -f $(docker ps -aq)
-f: 強制刪除
查看 Docker
[code]
$ sudo docker ps
[/code]
清除所有的網絡緩存 :
[code]
$ sudo docker network prune
[/code]
刪除鏈碼圖像 (鏈碼鏡像)
刪除 fabcar 智能合約的底層鏈碼圖像。如果您是第一次運行此項目可以不執行 (系統上不會有此鏈接代碼圖像)
[code]
$ sudo docker rmi dev-peer0.org1.example.com-fabcar-1.0-5c906e402ed29f20260ae42283216aa75549c571e2e380f3615826365d8269ba
[/code]
刪除指定的 Docker 鏡像文件
docker rmi image_id
安裝客戶端
安裝應用程序的 Fabric 依賴關係
[code]
$ npm install
[/code]
下載最好使用穩定的 VPN
npm install: 根據 package.json 讀取依賴的信息並安裝
如果未安裝 Node 則先按如下步驟安裝 Node 及 npm
安裝 nvm
[code]
$ sudo apt update $ curl -o-https://raw.githubusercontent.com/creationix/nvm/v0.33.10/install.sh | bash $ export NVM_DIR=\"$HOME/.nvm\" $ [ -s \"$NVM_DIR/nvm.sh\" ] && \\. \"$NVM_DIR/nvm.sh\"[/code]
安裝 Node
[code]
$ nvm install v8.11.1
[/code]
檢查 Node 版本
[code]
$ node -v
[/code]
輸出 :
v8.11.1
檢查 npm 版本
[code]
$ npm -v
[/code]
輸出 :
5.6.0
啓動網絡
[code]
$ sudo ./startFabric.sh
[/code]
該命令將啓動各種 Fabric 實體,並啓動用 Golang 編寫的鏈式代碼的智能合約容器
如出現以下錯誤
[code]
ERROR: manifest for hyperledger/fabric-ca:latest not found
[/code]
則說明環境中缺少 fabric-ca 鏡像
[code]
下載鏡像 $ sudo docker pull hyperledger/fabric-ca:x86_64-1.1.0-preview 將其標記爲最新 $ sudo docker tag hyperledger/fabric-ca:x86_64-1.1.0-preview hyperledger/fabric-ca:latest
檢查 $ sudo docker images 重新啓動 $ sudo ./startFabric.sh
[/code]
可選執行 (流式處理 CA 日誌 , 打開新的終端並執行如下命令)
[code]
$ sudo docker logs -f ca.example.com
[/code]
註冊管理員用戶
[code]
$ node enrollAdmin.js
[/code]
命令執行後輸出如下內容 :
[code]
Successfully enrolled admin user \"admin\" Assigned the admin user to the fabric client ::{\"name\":\"admin\",\"mspid\":\"Org1MSP\",\"roles\":null,\"affiliation\":\"\",\"enrollmentSecret\":\"\",\"enrollment\":{\"signingIdentity\":\"dc412dcc161b5732737e98e77fda03433b55408d79b10195f0ff150fc995924a\",\"identity\":{\"certificate\":\"-----BEGIN CERTIFICATE-----\\nMIICATCCAaigAwIBAgIUMjxyVKytJHiYigb+usxuVlmeI8kwCgYIKoZIzj0EAwIw\\nczELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNh\\nbiBGcmFuY2lzY28xGTAXBgNVBAoTEG9yZzEuZXhhbXBsZS5jb20xHDAaBgNVBAMT\\nE2NhLm9yZzEuZXhhbXBsZS5jb20wHhcNMTgwNDI2MDcyNzAwWhcNMTkwNDI2MDcz\\nMjAwWjAhMQ8wDQYDVQQLEwZjbGllbnQxDjAMBgNVBAMTBWFkbWluMFkwEwYHKoZI\\nzj0CAQYIKoZIzj0DAQcDQgAEszinoLQrvnKVYl9FUT8ebxT2jIz5lKCk5olL1cox\\n/JchmLPG8Ew1roM2TgG64rvT1nrl1EvMwmD8oEOMgmGqwKNsMGowDgYDVR0PAQH/\\nBAQDAgeAMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFNG9kJBZBDSOwFxVHTDByNOl\\nMvDSMCsGA1UdIwQkMCKAIEI5qg3NdtruuLoM2nAYUdFFBNMarRst3dusalc2Xkl8\\nMAoGCCqGSM49 BAMCA0cAMEQCIA1Ugh8NW3 tS0GkuUrURdwQrSnFkdWTQhJ1/GvRd\\nJbeTAiBGdDpHu/6 mZG8dpguA0EaqSHrWJBQra4Vj1Fm9F1+zNg==\\n-----END CERTIFICATE-----\\n\"}}}
[/code]
成功執行後會調用證書籤名請求(CSR),並最終將 eCert 和密鑰材料輸出到此文件夾中 ./hfc-key-store
,
應用程序將在創建用戶或加載身份對象時查找此位置
註冊 user1 用戶
[code]
$ node registerUser.js
[/code]
user1
該命令執行後調用 CSR 並將密鑰和 eCert 輸出到 ./hfc-key-store
子目錄中
執行命令後輸出如下 :
[code]
Successfully loaded admin from persistence Successfully registered user1 - secret:mrOjTeyeUmWY Successfully enrolled member user \"user1\" User1 was successfully registered and enrolled and is ready to intreact with the fabric network
[/code]
查詢分類帳
[code]
$ node query.js
[/code]
命令執行後輸出如下
[code]
Successfully loaded user1 from persistence Query has completed, checking results Response is [{\"Key\":\"CAR0\", \"Record\"{\"colour\":\"blue\",\"make\":\"Toyota\",\"model\":\"Prius\",\"owner\":\"Tomoko\"}}, {\"Key\":\"CAR1\", \"Record\":{\"colour\":\"red\",\"make\":\"Ford\",\"model\":\"Mustang\",\"owner\":\"Brad\"}},{\"Key\":\"CAR2\", \"Record\":{\"colour\":\"green\",\"make\":\"Hyundai\",\"model\":\"Tucson\",\"owner\":\"Jin Soo\"}},{\"Key\":\"CAR3\", \"Record\":{\"colour\":\"yellow\",\"make\":\"Volkswagen\",\"model\":\"Passat\",\"owner\":\"Max\"}},{\"Key\":\"CAR4\", \"Record\":{\"colour\":\"black\",\"make\":\"Tesla\",\"model\":\"S\",\"owner\":\"Adriana\"}},{\"Key\":\"CAR5\", \"Record\":{\"colour\":\"purple\",\"make\":\"Peugeot\",\"model\":\"205\",\"owner\":\"Michel\"}},{\"Key\":\"CAR6\", \"Record\": {\"colour\":\"white\",\"make\":\"Chery\",\"model\":\"S22L\",\"owner\":\"Aarav\"}},{\"Key\":\"CAR7\", \"Record\":{\"colour\":\"violet\",\"make\":\"Fiat\",\"model\":\"Punto\",\"owner\":\"Pari\"}},{\"Key\":\"CAR8\", \"Record\":{\"colour\":\"indigo\",\"make\":\"Tata\",\"model\":\"Nano\",\"owner\":\"Valeria\"}},{\"Key\":\"CAR9\", \"Record\":{\"colour\":\"brown\",\"make\":\"Holden\",\"model\":\"Barina\",\"owner\":\"Shotaro\"}}]
[/code]
由 Adriana 擁有的黑色特斯拉 Model S,由 Brad 擁有的紅色 Ford Mustang,由 Pari 擁有的紫色 Fiat Punto 等等。
分類賬是基於 K-V 的,在上面的信息中,Key 爲 CAR0 至 CAR9
打開 query.js
[code]
$ cat query.js
[/code]
發現應用程序的初始部分定義了某些變量,例如通道名稱,證書存儲位置和網絡端點
[code]
var channel = fabric_client.newChannel(\'mychannel\'); var peer = fabric_client.newPeer(\'grpc://localhost:7051\'); channel.addPeer(peer); var member_user = null; var store_path = path.join(__dirname, \'hfc-key-store\'); console.log(\'Store path:\'+store_path); var tx_id = null;
[/code]
query.js 文件有如下代碼使用第二個身份 user1
作爲此應用程序的簽署實體。指定 user1
爲簽名者
fabric_client.getUserContext(\'user1\', true);
這是實現查詢功能的語句塊: \’queryCar\’ \’CAR4\’
[code]
// queryCar chaincode function - requires 1 argument, ex: args: [\'CAR4\'], // queryAllCars chaincode function - requires no arguments , ex: args: [\'\'], const request = { //targets : --- letting this default to the peers assigned to the channel chaincodeId: \'fabcar\', fcn: \'queryAllCars\', args: [\'\'] };
[/code]
當應用程序運行時,它會調用對等 fabcar
體上的鏈式代碼,運行其中的 queryAllCars
函數 , 且不傳遞任何參數 .
使用編輯器打開 query.js
[code]
$ vim query.js
[/code]
修改其查詢塊內容 , 更改 queryAllCars
爲 queryCar
並將 CAR4
作爲特定 Key 爲參數傳遞來執行此操作
[code]
const request = { //targets : --- letting this default to the peers assigned to the channel chaincodeId: \'fabcar\', fcn: \'queryCar\', args: [\'CAR4\'] };
[/code]
保存退出後運行 :
[code]
$ node query.js
[/code]
執行後返回如下
[code]
Successfully loaded user1 from persistence Query has completed, checking results Response is {\"colour\":\"black\",\"make\":\"Tesla\",\"model\":\"S\",\"owner\":\"Adriana\"}
[/code]
使用該 queryCar
功能,我們可以查詢任何關鍵字(例如 CAR0
)並獲取與該車相對應的任何品牌,型號,顏色和所有者
更新分類帳
修改 invoke.js
, 找到 var request
中的 fcn
與 args
, 添加一條新的數據
[code]
$ vim invoke.js
[/code]
[code]
var request = { //targets: let default to the peer assigned to the client chaincodeId: \'fabcar\', fcn: \'createCar\', args: [\'CAR10\',\'Chevy\',\'Volt\',\'Red\',\'Nick\'], chainId: \'mychannel\', txId: tx_id };
[/code]
保存退出後執行
[code]
$ node invoke.js
[/code]
執行成功 , 輸出如下
[code]
Successfully loaded user1 from persistence Assigning transaction_id: 801d0636b9aa94cc7782af21ec2a10ebb12f929bd722afcee1f2b7b923485c82 Transaction proposal was good Successfully sent Proposal and received ProposalResponse: Status - 200, message - \"OK\" The transaction has been committed on peer localhost:7053 Send transaction promise and event listener promise have completed Successfully sent transaction to the orderer. Successfully committed the change to the ledger by the peer
[/code]
返回 query.js
並將參數由 CAR4
更改爲 CAR10
[code]
$ vim query.js
[/code]
[code]
const request = { //targets : --- letting this default to the peers assigned to the channel chaincodeId: \'fabcar\', fcn: \'queryCar\', args: [\'CAR10\'] };
[/code]
查詢 :
[code]
node query.js
[/code]
輸出內容如下 :
[code]
Successfully loaded user1 from persistence Query has completed, checking results Response is {\"colour\":\"Red\",\"make\":\"Chevy\",\"model\":\"Volt\",\"owner\":\"Nick\"}
[/code]
修改 invoke.js
, 修改 CAR10 的擁有者爲 Dave
[code]
$ vim invoke.js
[/code]
[code]
var request = { //targets: let default to the peer assigned to the client chaincodeId: \'fabcar\', fcn: \'changeCarOwner\', args: [\'CAR10\',\'Dave\'], chainId: \'mychannel\', txId: tx_id };
[/code]
保存退出並執行
[code]
$ node invoke.js $ node query.js
[/code]
運行輸出結果 :
[code]
Successfully loaded user1 from persistence Query has completed, checking results Response is {\"colour\":\"Red\",\"make\":\"Chevy\",\"model\":\"Volt\",\"owner\":\"Dave\"}
[/code]
問題 :
在執行 node invoke.js 命令後出現如下錯誤
[code]
Store path:$HOME/hyfa/fabric-samples/fabcar/hfc-key-store Successfully loaded user1 from persistence Assigning transaction_id: f80947242014765a46a17d797b45c8ed9a5db5cc936a57c731219d9e25646051 Transaction proposal was good Successfully sent Proposal and received ProposalResponse: Status - 200, message - \"OK\" Failed to invoke successfully :: TypeError: Cannot read property \'getConnectivityState\' of undefined $HOME/hyfa/fabric-samples/fabcar/node_modules/fabric-client/lib/EventHub.js:308 if(self._stream) state = self._stream.call.channel_.getConnectivityState(); ^ TypeError: Cannot read property \'getConnectivityState\' of undefined at ClientDuplexStream. ($HOME/hyfa/fabric-samples/fabcar/node_modules/fabric-client/lib/EventHub.js:308:56) at emitOne (events.js:116:13) at ClientDuplexStream.emit (events.js:211:7) at addChunk (_stream_readable.js:263:12) at readableAddChunk (_stream_readable.js:250:11) at ClientDuplexStream.Readable.push (_stream_readable.js:208:10) at Object.onReceiveMessage ($HOME/hyfa/fabric-samples/fabcar/node_modules/grpc/hide/client_interceptors.js:1302:19) at InterceptingListener.recvMessageWithContext ($HOME/hyfa/fabric-samples/fabcar/node_modules/grpc/hide/client_interceptors.js:629:19) at $HOME/hyfa/fabric-samples/fabcar/node_modules/grpc/hide/client_interceptors.js:728:14
[/code]
此問題可以無視 , 不會影響到後繼查詢命令node query.js
的執行
課程學習
添加莉莉老師微信 kongyixueyuan
不要錯過
**
課程學習方式**
系列閱讀
yuedu
從零到壹學習超級賬本理論加實戰第一講:超級賬本簡介
從零到壹學習超級賬本理論加實戰第二講:搭建環境
從零到壹學習超級賬本理論加實戰第三講:啓動網絡 (自動)
從零到壹學習超級賬本理論加實戰第四講:啓動網絡 (手動)
從零到壹學習超級賬本理論加實戰第五講:測試鏈碼
從零到壹學習超級賬本理論加實戰第六講:鏈碼概念與使用
從零到壹學習超級賬本理論加實戰第七講:使用多通道
從零到壹學習超級賬本理論加實戰第八講:configtxlator 轉換配置 / 添加 Org 組織到 channel
從零到壹學習超級賬本理論加實戰第九講:Fabric CA 應用與配置