搭建基于hyperledger fabric的联盟社区 --搭建node.js服务器
Posted preminem
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了搭建基于hyperledger fabric的联盟社区 --搭建node.js服务器相关的知识,希望对你有一定的参考价值。
接下来我要做的是用fabric sdk来做出应用程序,代替CLI与整个区块链网络交互。并且实现一个http API,向社区提供一个简单的接口,使社区轻松的与区块链交互。
官方虽然提供了Node.JS,Java,Go(最近刚出了python)等多种语言的SDK,但是很多SDK还不成熟和完善,有的甚至文档都没有。我使用Node.js的原因有三。1.官方例子使用的是Node.js SDK 2.以前我做以太坊智能合约开发的时候也用过Node.js 3.最后是因为Node.js实现一个http服务器是非常简单的。
我们可以选择将node.js安装在本地(1.1介绍),或者将node应用部署在docker。需要注意的是fabric目前不支持node7.x版本,需要6.9.x或更高版本和NPM。
本地安装node的话我们只需要执行以下命令即可安装NodeJS的最新v6版本:
curl -sL https://deb.nodesource.com/setup_6.x | sudo -E bash - sudo apt-get install -y nodejs
国内使用NPM会遇到很多问题,可用淘宝NPM镜像:
npm install -g cnpm --registry=https://registry.npm.taobao.org
使用方法是用cnpm代替npm
而我这里主要介绍的方法是将node.js部署在docker。
一. 先拉取基础镜像
sudo docker pull node:6.11.3
再提醒一遍fabric目前不支持node7.x版本,需要6.9.x或更高版本。这一步,也可以省略,后面的Dockerfile文件,会自动拉取该镜像。
二.创建node.js程序
2.1创建 package.json,并写入相关信息和依赖
mkdir -p node/mynodeapp && cd node/mynodeapp
touch package.json
vi 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" ] }
2.2 创建server.js
将与fabric交互的代码放在这里,监听8888端口。
touch server.js
vi server.js
由于我们这次是为peer0.org2开发API,所以本机IP地址为10.0.2.12,代码如下(很长慎点):
var http = require(‘http‘); var url = require(‘url‘); http.createServer(function(req, res){ var arg = url.parse(req.url, true).query; //方法二arg => { aa: ‘001‘, bb: ‘002‘ } console.log(arg.func);//返回001 if (arg.func == "queryPost"){ ‘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: ‘[email protected]‘, msp_id:‘Org2MSP‘, channel_id: ‘mychannel‘, chaincode_id: ‘mycc‘, network_url: ‘grpcs://10.0.2.12:7051‘,//因为启用了TLS,所以是grpcs,如果没有启用TLS,那么就是grpc privateKeyFolder: path.join(__dirname,‘./crypto-config/peerOrganizations/org2.example.com/users/[email protected]/msp/keystore‘), signedCert: path.join(__dirname,‘./crypto-config/peerOrganizations/org2.example.com/users/[email protected]/msp/signcerts/[email protected]‘), tls_cacerts:path.join(__dirname,‘./crypto-config/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt‘), server_hostname: "peer0.org2.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: ‘queryPost‘, args: ["POST"+arg.id] }; 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]); } res.writeHead(200, {‘Content-Type‘: ‘text/plain‘}); res.end(query_responses[0]); console.log("Response is ", query_responses[0].toString());//打印返回的结果 }).catch((err) => { console.error("Caught Error", err); }); }else if (arg.func == "addPost"){ ‘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: ‘[email protected]‘, msp_id:‘Org2MSP‘, channel_id: ‘mychannel‘, chaincode_id: ‘mycc‘, peer_url: ‘grpcs://10.0.2.12:7051‘,//因为启用了TLS,所以是grpcs,如果没有启用TLS,那么就是grpc event_url: ‘grpcs://10.0.2.12:7053‘,//因为启用了TLS,所以是grpcs,如果没有启用TLS,那么就是grpc orderer_url: ‘grpcs://10.0.2.10:7050‘,//因为启用了TLS,所以是grpcs,如果没有启用TLS,那么就是grpc privateKeyFolder: path.join(__dirname,‘./crypto-config/peerOrganizations/org2.example.com/users/[email protected]/msp/keystore‘), signedCert:path.join(__dirname,‘./crypto-config/peerOrganizations/org2.example.com/users/[email protected]/msp/signcerts/[email protected]‘), peer_tls_cacerts: path.join(__dirname,‘./crypto-config/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt‘), orderer_tls_cacerts:path.join(__dirname,‘./crypto-config/ordererOrganizations/example.com/orderers/orderer.example.com/tls/ca.crt‘), server_hostname: "peer0.org2.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); var request = { targets: targets, chaincodeId: options.chaincode_id, fcn: ‘addPost‘, args: [arg.originalwebsite,arg.originalid,arg.title,arg.content,arg.authorid,arg.publishtime,arg.updatetime,arg.category,arg.sourceid,arg.labels,arg.follower_num,arg.browse_num,arg.star_num], 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)); console.log(proposalResponses[0].response.payload.toString()); res.writeHead(200, {‘Content-Type‘: ‘text/plain‘}); res.end(proposalResponses[0].response.payload.toString()); 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; }); }else if(arg.func == "updatePost"){ ‘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: ‘[email protected]‘, msp_id:‘Org2MSP‘, channel_id: ‘mychannel‘, chaincode_id: ‘mycc‘, peer_url: ‘grpcs://10.0.2.12:7051‘,//因为启用了TLS,所以是grpcs,如果没有启用TLS,那么就是grpc event_url: ‘grpcs://10.0.2.12:7053‘,//因为启用了TLS,所以是grpcs,如果没有启用TLS,那么就是grpc orderer_url: ‘grpcs://10.0.2.10:7050‘,//因为启用了TLS,所以是grpcs,如果没有启用TLS,那么就是grpc privateKeyFolder: path.join(__dirname,‘./crypto-config/peerOrganizations/org2.example.com/users/[email protected]/msp/keystore‘), signedCert:path.join(__dirname,‘./crypto-config/peerOrganizations/org2.example.com/users/[email protected]/msp/signcerts/[email protected]‘), peer_tls_cacerts: path.join(__dirname,‘./crypto-config/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt‘), orderer_tls_cacerts:path.join(__dirname,‘./crypto-config/ordererOrganizations/example.com/orderers/orderer.example.com/tls/ca.crt‘), server_hostname: "peer0.org2.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); var request = { targets: targets, chaincodeId: options.chaincode_id, fcn: ‘updatePost‘, args: [arg.id,arg.originalwebsite,arg.originalid,arg.title,arg.content,arg.authorid,arg.publishtime,arg.updatetime,arg.category,arg.sourceid,arg.labels,arg.follower_num,arg.browse_num,arg.star_num], 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; }); }else if(arg.func == "richQueryPosts"){ ‘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: ‘[email protected]‘, msp_id:‘Org2MSP‘, channel_id: ‘mychannel‘, chaincode_id: ‘mycc‘, network_url: ‘grpcs://10.0.2.12:7051‘,//因为启用了TLS,所以是grpcs,如果没有启用TLS,那么就是grpc privateKeyFolder: path.join(__dirname,‘./crypto-config/peerOrganizations/org2.example.com/users/[email protected]/msp/keystore‘), signedCert: path.join(__dirname,‘./crypto-config/peerOrganizations/org2.example.com/users/[email protected]/msp/signcerts/[email protected]‘), tls_cacerts:path.join(__dirname,‘./crypto-config/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt‘), server_hostname: "peer0.org2.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: ‘richQueryPosts‘, args: [arg.attribute,arg.operator,arg.value] }; 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]); } res.writeHead(200, {‘Content-Type‘: ‘text/plain‘}); res.end(query_responses[0]); console.log("Response is ", query_responses[0].toString());//打印返回的结果 }).catch((err) => { console.error("Caught Error", err); }); }else if(arg.func == "getPostNum"){ ‘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: ‘[email protected]‘, msp_id:‘Org2MSP‘, channel_id: ‘mychannel‘, chaincode_id: ‘mycc‘, network_url: ‘grpcs://10.0.2.12:7051‘,//因为启用了TLS,所以是grpcs,如果没有启用TLS,那么就是grpc privateKeyFolder: path.join(__dirname,‘./crypto-config/peerOrganizations/org2.example.com/users/[email protected]/msp/keystore‘), signedCert: path.join(__dirname,‘./crypto-config/peerOrganizations/org2.example.com/users/[email protected]/msp/signcerts/[email protected]‘), tls_cacerts:path.join(__dirname,‘./crypto-config/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt‘), server_hostname: "peer0.org2.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: ‘getPostNum‘, args: [arg.attribute,arg.operator,arg.value] }; 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]); } res.writeHead(200, {‘Content-Type‘: ‘text/plain‘}); res.end(query_responses[0]); console.log("Response is ", query_responses[0].toString());//打印返回的结果 }).catch((err) => { console.error("Caught Error", err); }); } }).listen(8888);//建立服务器并监听端口 console.log(‘Server running at http://127.0.0.1:8888/‘);
三.创建Dockerfile
Docker会依照Dockerfile的内容来构建一个镜像。
cd ..
touch Dockerfile
vi Dockerfile
#设置基础镜像,如果本地没有该镜像,会从Docker.io服务器pull镜像 FROM node:6.11.3 #创建app目录,保存我们的代码 RUN mkdir -p /usr/src/node #设置工作目录 WORKDIR /usr/src/node #复制所有文件到 工作目录。 COPY . /usr/src/node #编译运行node项目,使用npm安装程序的所有依赖,利用taobao的npm安装 WORKDIR /usr/src/node/mynodeapp #暴露container的端口 EXPOSE 8888 #运行命令 CMD ["node", "server.js"]
四.构建image
在Dockerfile文件所在目录下,运行下面命令来构建一个Image
sudo docker build -t fabric/node .
最后提示
Removing intetmediate container <临时容器ID>
Successfully built <镜像ID>
就算构建成功了。(这一步时常失败,要看网络状况)
构建完后查看一下刚构建的镜像:
sudo docker images
多出来了一个fabric/node镜像。
五.运行镜像
sudo docker run -d --name nodeapp -p 8888:8888 fabric/node:latest
-d 表示容器在后台运行
--name 表示给容器别名 nodeapp
-p 表示端口映射。把本机的8888端口映射到容器的8888端口,这样外网就能通过本机的8888端口,访问我们的web了。
后面的 fabric/node 是image的REPOSITORY, latest的镜像的TAG
六.测试
我使用python写了一个简单的发送和接受http请求的程序,当然熟悉别的语言的话也可以用别的语言编写。代码如下:
import urllib.request url = "http://localhost:8888/select?func=richQueryPosts&attribute=title&operator=0&value=d" req = urllib.request.Request(url) print(req) res_data = urllib.request.urlopen(req) res = res_data.read() print (res)
成功接收到包含对应帖子信息的response就说明node部署成功了。
之后对应的社区就可以调用HTTP API来完成社区和区块链的对接了!整个基于hyperledger fabric的社区联盟开发的内容就到这里了。
以上是关于搭建基于hyperledger fabric的联盟社区 --搭建node.js服务器的主要内容,如果未能解决你的问题,请参考以下文章
基于hyperledger fabric 联盟链 + vue cli的项目搭建完整教程
搭建基于hyperledger fabric的联盟社区 --升级chaincode
搭建基于hyperledger fabric的联盟社区 --生成公私钥证书及配置文件
搭建基于hyperledger fabric的联盟社区 --搭建node.js服务器