黎躍春

孔壹學院、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]

修改其查詢塊內容 , 更改 queryAllCarsqueryCar 並將 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 中的 fcnargs, 添加一條新的數據

[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 應用與配置