日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Hyperledger Fabric 1.0 实战开发系列 第四课 搭建node.js服务器

發布時間:2025/3/15 编程问答 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Hyperledger Fabric 1.0 实战开发系列 第四课 搭建node.js服务器 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

接下來我要做的是用fabric sdk來做出應用程序,代替CLI與整個區塊鏈網絡交互。并且實現一個http API,向社區提供一個簡單的接口,使社區輕松的與區塊鏈交互。

官方雖然提供了Node.JS,Java,Go(最近剛出了python)等多種語言的SDK,但是很多SDK還不成熟和完善,有的甚至文檔都沒有。我使用Node.js的原因有二。1.官方例子使用的是Node.js SDK 2.因為Node.js實現一個http服務器是非常簡單的。

我們可以選擇將node.js安裝在本地,或者將node應用部署在docker。需要注意的是fabric目前不支持node7.x版本,需要6.9.x或更高版本和NPM。

一、下載nodejs

1.下載node.js,由于node服務器在國外 所以需要翻墻下載,在Terminal中輸入以下命令:

wget?https://nodejs.org/download/release/v6.10.0/node-v6.10.0-linux-x64.tar.gz

2、下載下來的tar文件上傳到服務器并且解壓,然后通過建立軟連接變為全局;

1)上傳服務器可以是自己任意路徑,目前我的放置路徑為 /usr/local

2)解壓上傳(解壓后的文件我這邊將名字改為了nodejs,這個地方自己隨意,只要在建立軟連接的時候寫正確就可以)

? ? ① tar -xvf ? node-v6.10.0-linux-x64.tar.xz ??

? ? ② mv?node-v6.10.0-linux-x64 ?nodejs?

? ? ③確認一下nodejs下bin目錄是否有node 和npm文件,如果有執行軟連接,如果沒有重新下載執行上邊步驟;

3)建立軟連接,變為全局

?

? ?①ln -s /usr/local/nodejs/bin/npm /usr/local/bin/?

?

? ?②ln -s /usr/local/nodejs/bin/node /usr/local/bin/

?

4)最后一步檢驗nodejs是否已變為全局

?

? ?在Linux命令行node -v 命令會顯示nodejs版本,如圖所示為大功告成

二.創建node.js程序

1.編寫package.json并下載依賴模塊

我們首先在當前用戶的根目錄建立一個nodeTest的文件夾,用于存放我們關于node的相關項目文件,然后在其中新建一個包配置文件,package.json mkdir ~/nodeTest cd ~/nodeTest vi package.json 在這個文件中,我們可以定義很多項目相關的屬性,這篇博客詳細的介紹了每個屬性有什么用,大家可以參考:http://www.cnblogs.com/tzyy/p/5193811.html 總之,最后我們在package.json中放入了以下內容:
{ "name": "nodeTest", "version": "1.0.0", "description": "Hyperledger Fabric Node SDK Test Application", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "dependencies": { "fabric-ca-client": "^1.0.0", "fabric-client": "^1.0.0" }, "author": "Devin Zeng", "license": "Apache-2.0", "keywords": [ "Hyperledger", "Fabric", "Test", "Application" ] }

最主要的就是dependencies,這里我們放了Fabric CA Client和Fabric Node SDK的Client,雖然本示例中沒用到CA Client,但是以后會用到,所以先放在這里了。

編輯保存好該文件后,我們就可以運行npm install命令來下載所有相關的依賴模塊,但是由于npm服務器在國外,所以下載可能會很慢,感謝淘寶為我們提供了國內的npm鏡像,使得安裝npm模塊快很多。運行的命令是: npm install --registry=https://registry.npm.taobao.org 運行完畢后我們查看一下nodeTest目錄,可以看到多了一個node_modules文件夾。這里就是使用剛才的命令下載下來的所有依賴包。

2.編寫對Fabric的Query方法

下面我們新建一個query.js文件,開始我們的Fabric Node SDK編碼工作。由于代碼比較長,所以我就不分步講了,直接在代碼中增加注釋,將完整代碼貼出來:


'use strict';var hfc = require('fabric-client'); var path = require('path'); var sdkUtils = require('fabric-client/lib/utils') var fs = require('fs'); var options = { user_id: 'Admin@org1.example.com', msp_id:'Org1MSP', channel_id: 'mychannel', chaincode_id: 'mycc', network_url: 'grpcs://localhost:7051',//因為啟用了TLS,所以是grpcs,如果沒有啟用TLS,那么就是grpc privateKeyFolder:'/home/studyzy/go/src/github.com/hyperledger/fabric/examples/e2e_cli/crypto-config/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp/keystore', signedCert:'/home/studyzy/go/src/github.com/hyperledger/fabric/examples/e2e_cli/crypto-config/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp/signcerts/Admin@org1.example.com-cert.pem', tls_cacerts:'/home/studyzy/go/src/github.com/hyperledger/fabric/examples/e2e_cli/crypto-config/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt', server_hostname: "peer0.org1.example.com" };var channel = {}; var client = null; const getKeyFilesInDir = (dir) => { //該函數用于找到keystore目錄下的私鑰文件的路徑 var files = fs.readdirSync(dir) var keyFiles = [] files.forEach((file_name) => { let filePath = path.join(dir, file_name) if (file_name.endsWith('_sk')) { keyFiles.push(filePath) } }) return keyFiles } Promise.resolve().then(() => { console.log("Load privateKey and signedCert"); client = new hfc(); var createUserOpt = { username: options.user_id, mspid: options.msp_id, cryptoContent: { privateKey: getKeyFilesInDir(options.privateKeyFolder)[0], signedCert: options.signedCert } } //以上代碼指定了當前用戶的私鑰,證書等基本信息 return sdkUtils.newKeyValueStore({ path: "/tmp/fabric-client-stateStore/" }).then((store) => { client.setStateStore(store) return client.createUser(createUserOpt) }) }).then((user) => { channel = client.newChannel(options.channel_id); let data = fs.readFileSync(options.tls_cacerts); let peer = client.newPeer(options.network_url, { pem: Buffer.from(data).toString(), 'ssl-target-name-override': options.server_hostname } ); peer.setName("peer0"); //因為啟用了TLS,所以上面的代碼就是指定TLS的CA證書 channel.addPeer(peer); return; }).then(() => { console.log("Make query"); var transaction_id = client.newTransactionID(); console.log("Assigning transaction_id: ", transaction_id._transaction_id); //構造查詢request參數 const request = { chaincodeId: options.chaincode_id, txId: transaction_id, fcn: 'query', args: ['a'] }; return channel.queryByChaincode(request); }).then((query_responses) => { console.log("returned from query"); if (!query_responses.length) { console.log("No payloads were returned from query"); } else { console.log("Query result count = ", query_responses.length) } if (query_responses[0] instanceof Error) { console.error("error from query = ", query_responses[0]); } console.log("Response is ", query_responses[0].toString());//打印返回的結果 }).catch((err) => { console.error("Caught Error", err); });

編寫完代碼,我們想要測試一下我們的代碼是否靠譜,直接運行

node query.js

即可,我們可以看到,a賬戶的余額是90元。

studyzy@ubuntu1:~/nodeTest$ node query.js Load privateKey and signedCert Make query Assigning transaction_id: ee3ac35d40d8510813546a2216ad9c0d91213b8e1bba9b7fe19cfeff3014e38a returned from query Query result count = 1 Response is 90

為什么a賬戶是90?因為我們跑e2e_cli的Fabric網絡時,系統會自動安裝Example02的ChainCode,然后自動跑查詢,轉賬等操作。

3.編寫對Fabric的Invoke方法

相比較于Query方法,Invoke方法要復雜的多,主要是因為Invoke需要和Orderer通信,而且發起了Transaction之后,還要設置EventHub來接收消息。下面貼出invoke.js的全部內容,對于比較重要的部分我進行了注釋:


'use strict';var hfc = require('fabric-client'); var path = require('path'); var util = require('util'); var sdkUtils = require('fabric-client/lib/utils') const fs = require('fs'); var options = { user_id: 'Admin@org1.example.com', msp_id:'Org1MSP', channel_id: 'mychannel', chaincode_id: 'mycc', peer_url: 'grpcs://localhost:7051',//因為啟用了TLS,所以是grpcs,如果沒有啟用TLS,那么就是grpc event_url: 'grpcs://localhost:7053',//因為啟用了TLS,所以是grpcs,如果沒有啟用TLS,那么就是grpc orderer_url: 'grpcs://localhost:7050',//因為啟用了TLS,所以是grpcs,如果沒有啟用TLS,那么就是grpc privateKeyFolder:'/home/studyzy/go/src/github.com/hyperledger/fabric/examples/e2e_cli/crypto-config/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp/keystore', signedCert:'/home/studyzy/go/src/github.com/hyperledger/fabric/examples/e2e_cli/crypto-config/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp/signcerts/Admin@org1.example.com-cert.pem', peer_tls_cacerts:'/home/studyzy/go/src/github.com/hyperledger/fabric/examples/e2e_cli/crypto-config/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt', orderer_tls_cacerts:'/home/studyzy/go/src/github.com/hyperledger/fabric/examples/e2e_cli/crypto-config/ordererOrganizations/example.com/orderers/orderer.example.com/tls/ca.crt', server_hostname: "peer0.org1.example.com" };var channel = {}; var client = null; var targets = []; var tx_id = null; const getKeyFilesInDir = (dir) => { //該函數用于找到keystore目錄下的私鑰文件的路徑 const files = fs.readdirSync(dir) const keyFiles = [] files.forEach((file_name) => { let filePath = path.join(dir, file_name) if (file_name.endsWith('_sk')) { keyFiles.push(filePath) } }) return keyFiles } Promise.resolve().then(() => { console.log("Load privateKey and signedCert"); client = new hfc(); var createUserOpt = { username: options.user_id, mspid: options.msp_id, cryptoContent: { privateKey: getKeyFilesInDir(options.privateKeyFolder)[0], signedCert: options.signedCert } } //以上代碼指定了當前用戶的私鑰,證書等基本信息 return sdkUtils.newKeyValueStore({ path: "/tmp/fabric-client-stateStore/" }).then((store) => { client.setStateStore(store) return client.createUser(createUserOpt) }) }).then((user) => { channel = client.newChannel(options.channel_id); let data = fs.readFileSync(options.peer_tls_cacerts); let peer = client.newPeer(options.peer_url, { pem: Buffer.from(data).toString(), 'ssl-target-name-override': options.server_hostname } ); //因為啟用了TLS,所以上面的代碼就是指定Peer的TLS的CA證書 channel.addPeer(peer); //接下來連接Orderer的時候也啟用了TLS,也是同樣的處理方法 let odata = fs.readFileSync(options.orderer_tls_cacerts); let caroots = Buffer.from(odata).toString(); var orderer = client.newOrderer(options.orderer_url, { 'pem': caroots, 'ssl-target-name-override': "orderer.example.com" }); channel.addOrderer(orderer); targets.push(peer); return; }).then(() => { tx_id = client.newTransactionID(); console.log("Assigning transaction_id: ", tx_id._transaction_id); //發起轉賬行為,將a->b 10元 var request = { targets: targets, chaincodeId: options.chaincode_id, fcn: 'invoke', args: ['a', 'b', '10'], chainId: options.channel_id, txId: tx_id }; return channel.sendTransactionProposal(request); }).then((results) => { var proposalResponses = results[0]; var proposal = results[1]; var header = results[2]; let isProposalGood = false; if (proposalResponses && proposalResponses[0].response && proposalResponses[0].response.status === 200) { isProposalGood = true; console.log('transaction proposal was good'); } else { console.error('transaction proposal was bad'); } if (isProposalGood) { console.log(util.format( 'Successfully sent Proposal and received ProposalResponse: Status - %s, message - "%s", metadata - "%s", endorsement signature: %s', proposalResponses[0].response.status, proposalResponses[0].response.message, proposalResponses[0].response.payload, proposalResponses[0].endorsement.signature)); var request = { proposalResponses: proposalResponses, proposal: proposal, header: header }; // set the transaction listener and set a timeout of 30sec // if the transaction did not get committed within the timeout period, // fail the test var transactionID = tx_id.getTransactionID(); var eventPromises = []; let eh = client.newEventHub(); //接下來設置EventHub,用于監聽Transaction是否成功寫入,這里也是啟用了TLS let data = fs.readFileSync(options.peer_tls_cacerts); let grpcOpts = { pem: Buffer.from(data).toString(), 'ssl-target-name-override': options.server_hostname } eh.setPeerAddr(options.event_url,grpcOpts); eh.connect();let txPromise = new Promise((resolve, reject) => { let handle = setTimeout(() => { eh.disconnect(); reject(); }, 30000); //向EventHub注冊事件的處理辦法 eh.registerTxEvent(transactionID, (tx, code) => { clearTimeout(handle); eh.unregisterTxEvent(transactionID); eh.disconnect();if (code !== 'VALID') { console.error( 'The transaction was invalid, code = ' + code); reject(); } else { console.log( 'The transaction has been committed on peer ' + eh._ep._endpoint.addr); resolve(); } }); }); eventPromises.push(txPromise); var sendPromise = channel.sendTransaction(request); return Promise.all([sendPromise].concat(eventPromises)).then((results) => { console.log(' event promise all complete and testing complete'); return results[0]; // the first returned value is from the 'sendPromise' which is from the 'sendTransaction()' call }).catch((err) => { console.error( 'Failed to send transaction and get notifications within the timeout period.' ); return 'Failed to send transaction and get notifications within the timeout period.'; }); } else { console.error( 'Failed to send Proposal or receive valid response. Response null or status is not 200. exiting...' ); return 'Failed to send Proposal or receive valid response. Response null or status is not 200. exiting...'; } }, (err) => { console.error('Failed to send proposal due to error: ' + err.stack ? err.stack : err); return 'Failed to send proposal due to error: ' + err.stack ? err.stack : err; }).then((response) => { if (response.status === 'SUCCESS') { console.log('Successfully sent transaction to the orderer.'); return tx_id.getTransactionID(); } else { console.error('Failed to order the transaction. Error code: ' + response.status); return 'Failed to order the transaction. Error code: ' + response.status; } }, (err) => { console.error('Failed to send transaction due to error: ' + err.stack ? err .stack : err); return 'Failed to send transaction due to error: ' + err.stack ? err.stack : err; });
三.測試 推薦使用postman進行測試,可以按照https://github.com/hyperledger/fabric-samples/tree/release/balance-transfer這個例子中演示的步驟進行

cd fabric-samples/balance-transfer/ docker-compose -f artifacts/docker-compose.yaml up

Login Request

  • Register and enroll new users in Organization -?Org1:
  • 在Termial中輸入以下命令

curl -s -X POST http://localhost:4000/users -H "content-type: application/x-www-form-urlencoded" -d 'username=Jim&orgName=org1'

OUTPUT:

{"success": true,"secret": "RaxhMgevgJcm","message": "Jim enrolled Successfully","token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE0OTQ4NjU1OTEsInVzZXJuYW1lIjoiSmltIiwib3JnTmFtZSI6Im9yZzEiLCJpYXQiOjE0OTQ4NjE5OTF9.yWaJhFDuTvMQRaZIqg20Is5t-JJ_1BP58yrNLOKxtNI" } 或者在postman中


四.總結

這只是簡單的測試Node SDK是否可用,如果我們要做項目,那么就會復雜很多,可以參考官方的兩個項目:

https://github.com/hyperledger/fabric-samples/tree/release/balance-transfer

https://github.com/IBM-Blockchain/marbles

總結

以上是生活随笔為你收集整理的Hyperledger Fabric 1.0 实战开发系列 第四课 搭建node.js服务器的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。