Hyperledger Fabric SDK 示例fabric-samples-《balance-transfer》之六《执行chaincode》
2017-11-01 18:02
671 查看
本文已在我的公众号BigManing_blog原创首发。
转载请标明出处:
https://blog.csdn.net/qq_27818541/article/details/78416848
本文出自:【BigManing的博客】
控制台打印:
后台打印:
转载请标明出处:
https://blog.csdn.net/qq_27818541/article/details/78416848
本文出自:【BigManing的博客】
前言
这里要实现类似转账功能,A->B, 最终要执行的是chaincode的move方法。这里我们看下
chaincode的
move方法:
func (t *SimpleChaincode) move(stub shim.ChaincodeStubInterface, args []string) pb.Response { // must be an invoke //1 这里可以理解成 两个账户 var A, B string // Entities //2 分别对应的资产值 var Aval, Bval int // Asset holdings var X int // Transaction value var err error if len(args) != 3 { return shim.Error("Incorrect number of arguments. Expecting 4, function followed by 2 names and 1 value") } A = args[0] B = args[1] //3 先获取A账户的资产值 Get the state from the ledger Avalbytes, err := stub.GetState(A) if err != nil { return shim.Error("Failed to get state") } if Avalbytes == nil { return shim.Error("Entity not found") } Aval, _ = strconv.Atoi(string(Avalbytes)) //4 获取B账户的资产值 Bvalbytes, err := stub.GetState(B) if err != nil { return shim.Error("Failed to get state") } if Bvalbytes == nil { return shim.Error("Entity not found") } Bval, _ = strconv.Atoi(string(Bvalbytes)) //5 根据入参 进行账户之间资产的转移 X, err = strconv.Atoi(args[2]) if err != nil { return shim.Error("Invalid transaction amount, expecting a integer value") } Aval = Aval - X Bval = Bval + X logger.Infof("Aval = %d, Bval = %d\n", Aval, Bval) //6 最后把最新资产值写入账簿 (类似map的存储方式 k-v) Write the state back to the ledger err = stub.PutState(A, []byte(strconv.Itoa(Aval))) if err != nil { return shim.Error(err.Error()) } err = stub.PutState(B, []byte(strconv.Itoa(Bval))) if err != nil { return shim.Error(err.Error()) } return shim.Success(nil); }
路由
app.js
//在指定的peer上执行交易 Invoke transaction on chaincode on target peers app.post('/channels/:channelName/chaincodes/:chaincodeName', function(req, res) { logger.debug('==================== INVOKE ON CHAINCODE =================='); //1 参数校验 //执行交易所在的节点 var peers = req.body.peers; //chaincode名称 var chaincodeName = req.params.chaincodeName; //channel名称 var channelName = req.params.channelName; //chaincode方法 var fcn = req.body.fcn; //方法参数 var args = req.body.args; logger.debug('channelName : ' + channelName); logger.debug('chaincodeName : ' + chaincodeName); logger.debug('fcn : ' + fcn); logger.debug('args : ' + args); if (!chaincodeName) { res.json(getErrorMessage('\'chaincodeName\'')); return; } if (!channelName) { res.json(getErrorMessage('\'channelName\'')); return; } if (!fcn) { res.json(getErrorMessage('\'fcn\'')); return; } if (!args) { res.json(getErrorMessage('\'args\'')); return; } //2 具体实现 invoke.invokeChaincode(peers, channelName, chaincodeName, fcn, args, req.username, req.orgname) .then(function(message) { res.send(message); }); });
具体实现
这里面会涉及到fabric执行交易的基本流程:invoke-transaction.js
var path = require('path'); var fs = require('fs'); var util = require('util'); var hfc = require('fabric-client'); var Peer = require('fabric-client/lib/Peer.js'); var helper = require('./helper.js'); var logger = helper.getLogger('invoke-chaincode'); var EventHub = require('fabric-client/lib/EventHub.js'); var ORGS = hfc.getConfigSetting('network-config'); var invokeChaincode = function (peerNames, channelName, chaincodeName, fcn, args, username, org) { logger.debug(util.format('\n============ invoke transaction on organization %s ============\n', org)); var client = helper.getClientForOrg(org); var channel = helper.getChannelForOrg(org); var targets = (peerNames) ? helper.newPeers(peerNames, org) : undefined; var tx_id = null; //1 获取 jim 用户( 内部会设置为上下文环境) return helper.getRegisteredUsers(username, org).then((user) => { tx_id = client.newTransactionID(); logger.debug(util.format('Sending transaction "%j"', tx_id)); //2 封装交易提案请求 var request = { chaincodeId: chaincodeName, fcn: fcn, args: args, chainId: channelName, txId: tx_id }; if (targets) request.targets = targets; //3 发送交易提案给背书节点 // send proposal to endorser return channel.sendTransactionProposal(request); }, (err) => { logger.error('Failed to enroll user \'' + username + '\'. ' + err); throw new Error('Failed to enroll user \'' + username + '\'. ' + err); }).then((results) => { //4 处理背书结果 var proposalResponses = results[0]; var proposal = results[1]; var all_good = true; for (var i in proposalResponses) { let one_good = false; if (proposalResponses && proposalResponses[i].response && proposalResponses[i].response.status === 200) { one_good = true; logger.info('transaction proposal was good'); } else { logger.error('transaction proposal was bad'); } all_good = all_good & one_good; } if (all_good) { logger.debug(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)); //5 如果背书结果ok 封装正式交易请求 var request = { proposalResponses: proposalResponses, proposal: proposal }; // 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 = []; if (!peerNames) { peerNames = channel.getPeers().map(function (peer) { return peer.getName(); }); } //5.1 设置事件监听 并生成带有超时设置的promise var eventhubs = helper.newEventHubs(peerNames, org); for (let key in eventhubs) { let eh = eventhubs[key]; eh.connect(); let txPromise = new Promise((resolve, reject) => { let handle = setTimeout(() => { eh.disconnect(); reject(); }, 30000); eh.registerTxEvent(transactionID, (tx, code) => { clearTimeout(handle); eh.unregisterTxEvent(transactionID); eh.disconnect(); if (code !== 'VALID') { logger.error( 'The balance transfer transaction was invalid, code = ' + code); reject(); } else { logger.info( 'The balance transfer transaction has been committed on peer ' + eh._ep._endpoint.addr); resolve(); } }); }); eventPromises.push(txPromise); }; //6 发送交易 var sendPromise = channel.sendTransaction(request); //7 集合所有的promise 并执行 return Promise.all([sendPromise].concat(eventPromises)).then((results) => { logger.debug(' 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) => { logger.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 { logger.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) => { logger.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) => { //8 处理第七步返回的结果 if (response.status === 'SUCCESS') { logger.info('Successfully sent transaction to the orderer.'); return tx_id.getTransactionID(); } else { logger.error('Failed to order the transaction. Error code: ' + response.status); return 'Failed to order the transaction. Error code: ' + response.status; } }, (err) => { logger.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; }); }; exports.invokeChaincode = invokeChaincode;
基本流程
Created with Raphaël 2.1.2Start 获取到当前用户封装交易提案请求发送提案request给背书节点所有的背书响应是否ok封装交易请求发送交易,最终调用move方法处理结果End yesnoAPI访问
echo "POST invoke chaincode on peers of Org1 and Org2" echo TRX_ID=$(curl -s -X POST \ http://localhost:4000/channels/mychannel/chaincodes/mycc \ -H "authorization: Bearer $ORG1_TOKEN" \ -H "content-type: application/json" \ -d '{ "fcn":"move", "args":["a","b","10"] }') echo "Transacton ID is $TRX_ID" echo echo
控制台打印:
Transacton ID is eb058850e7247ad0bc25ec57ced1cd1255666c390ca0c9300858ce6e57175221
后台打印:
[2017-10-16 11:07:40.822] [DEBUG] SampleWebApp - Decoded from JWT token: username - Jim, orgname - org1 [2017-10-16 11:07:40.823] [DEBUG] SampleWebApp - ==================== INVOKE ON CHAINCODE ================== // 后台获取到的参数 [2017-10-16 11:07:40.823] [DEBUG] SampleWebApp - channelName : mychannel [2017-10-16 11:07:40.823] [DEBUG] SampleWebApp - chaincodeName : mycc [2017-10-16 11:07:40.823] [DEBUG] SampleWebApp - fcn : move [2017-10-16 11:07:40.823] [DEBUG] SampleWebApp - args : a,b,10 [2017-10-16 11:07:40.824] [DEBUG] invoke-chaincode - ============ invoke transaction on organization org1 ============ // 设置Jim为当前的上下文环境 [2017-10-16 11:07:40.824] [DEBUG] Helper - [FileKeyValueStore.js]: FileKeyValueStore.js - constructor [2017-10-16 11:07:40.825] [DEBUG] Helper - [FileKeyValueStore.js]: FileKeyValueStore -- getValue [2017-10-16 11:07:40.826] [DEBUG] Helper - [crypto_ecdsa_aes]: importKey - start [2017-10-16 11:07:40.826] [DEBUG] Helper - [crypto_ecdsa_aes]: importKey - have the key [Circular] [2017-10-16 11:07:40.827] [DEBUG] Helper - [utils.CryptoKeyStore]: _getKeyStore resolving store [2017-10-16 11:07:40.828] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param X: b3e2a75b9a4fd2b081589b1c45bde49f583aea9d7d466798c7b765c4ca96973d [2017-10-16 11:07:40.828] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param Y: c58820e5a9db75ab17841ac158e9389ad0d130a6827dc0682dcb2d2c5dccb349 [2017-10-16 11:07:40.829] [DEBUG] Helper - [FileKeyValueStore.js]: FileKeyValueStore -- setValue [2017-10-16 11:07:40.831] [DEBUG] Helper - [utils.CryptoKeyStore]: _getKeyStore resolving store [2017-10-16 11:07:40.831] [DEBUG] Helper - [FileKeyValueStore.js]: FileKeyValueStore -- getValue [2017-10-16 11:07:40.832] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param X: b3e2a75b9a4fd2b081589b1c45bde49f583aea9d7d466798c7b765c4ca96973d [2017-10-16 11:07:40.832] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param Y: c58820e5a9db75ab17841ac158e9389ad0d130a6827dc0682dcb2d2c5dccb349 [2017-10-16 11:07:40.832] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param X: b3e2a75b9a4fd2b081589b1c45bde49f583aea9d7d466798c7b765c4ca96973d [2017-10-16 11:07:40.832] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param Y: c58820e5a9db75ab17841ac158e9389ad0d130a6827dc0682dcb2d2c5dccb349 [2017-10-16 11:07:40.832] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param X: b3e2a75b9a4fd2b081589b1c45bde49f583aea9d7d466798c7b765c4ca96973d [2017-10-16 11:07:40.832] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param Y: c58820e5a9db75ab17841ac158e9389ad0d130a6827dc0682dcb2d2c5dccb349 [2017-10-16 11:07:40.832] [DEBUG] Helper - [FileKeyValueStore.js]: FileKeyValueStore -- setValue [2017-10-16 11:07:40.833] [INFO] Helper - Successfully loaded member from persistence // 发送交易提案 [2017-10-16 11:07:40.833] [DEBUG] invoke-chaincode - Sending transaction "{"_nonce":{"type":"Buffer","data":[169,122,192,203,43,77,68,42,128,240,8,81,90,35,63,156,13,236,81,59,126,148,200,17]},"_transaction_id":"eb058850e7247ad0bc25ec57ced1cd1255666c390ca0c9300858ce6e57175221"}" [2017-10-16 11:07:40.841] [DEBUG] Helper - [crypto_ecdsa_aes]: ecdsa signature: Signature { r: <BN: 2a552dc46d1921f3bacd95df82cc38c855946021a93a7b8cba61ee9b4cdb9857>, s: <BN: 4877817703a392a85561824acfcf695ec09a37d8032c2d52afddccfae2063d22>, recoveryParam: 0 } [2017-10-16 11:07:40.855] [INFO] invoke-chaincode - transaction proposal was good [2017-10-16 11:07:40.855] [INFO] invoke-chaincode - transaction proposal was good // 交易提案的响应 [2017-10-16 11:07:40.855] [DEBUG] invoke-chaincode - Successfully sent Proposal and received ProposalResponse: Status - 200, message - "OK", metadata - "", endorsement signature: 0D ?�cEW�>��N���p����r�[b�gaR5f�@ `"���D��}������0�s0�6��:�%�v/í //设置监听事件 info: [EventHub.js]: _connect - options {"grpc.ssl_target_name_override":"peer0.org1.example.com","grpc.default_authority":"peer0.org1.example.com"} [2017-10-16 11:07:40.861] [DEBUG] Helper - [crypto_ecdsa_aes]: ecdsa signature: Signature { r: <BN: c3b1ae588f3356ce1caf07d06d26ca92ccd4255a38e99c41cce9c51513ba61c1>, s: <BN: 7747f104839f5f40e9cbef787513341c3de7cf87da18fb24fbdf786b3d7dc191>, recoveryParam: 0 } info: [EventHub.js]: _connect - options {"grpc.ssl_target_name_override":"peer1.org1.example.com","grpc.default_authority":"peer1.org1.example.com"} [2017-10-16 11:07:40.867] [DEBUG] Helper - [crypto_ecdsa_aes]: ecdsa signature: Signature { r: <BN: c3b1ae588f3356ce1caf07d06d26ca92ccd4255a38e99c41cce9c51513ba61c1>, s: <BN: 7747f104839f5f40e9cbef787513341c3de7cf87da18fb24fbdf786b3d7dc191>, recoveryParam: 0 } [2017-10-16 11:07:40.875] [DEBUG] Helper - [crypto_ecdsa_aes]: ecdsa signature: Signature { r: <BN: b11a259870e0bbf072584f353ab1515f4759c854eb475bedccba38b5c362a4d7>, s: <BN: 66796e05eae9015e63eea208708a9a8e91853821c7221a843c4bd07debfae97c>, recoveryParam: 1 } [2017-10-16 11:07:43.022] [DEBUG] Helper - [crypto_ecdsa_aes]: ecdsa signature: Signature { r: <BN: b516e7e14243395b12a21a51c864c0b65f442d57501b07cce481892b8e2c7caa>, s: <BN: cff64d35bdd6b9a10bec5e5bd5b90f2adcb8f576b77c28d7317d4d0c003fb3d>, recoveryParam: 1 } [2017-10-16 11:07:43.022] [INFO] invoke-chaincode - The balance transfer transaction has been committed on peer localhost:7058 [2017-10-16 11:07:43.045] [DEBUG] Helper - [crypto_ecdsa_aes]: ecdsa signature: Signature { r: <BN: b516e7e14243395b12a21a51c864c0b65f442d57501b07cce481892b8e2c7caa>, s: <BN: cff64d35bdd6b9a10bec5e5bd5b90f2adcb8f576b77c28d7317d4d0c003fb3d>, recoveryParam: 1 } [2017-10-16 11:07:43.045] [INFO] invoke-chaincode - The balance transfer transaction has been committed on peer localhost:7053 [2017-10-16 11:07:43.046] [DEBUG] invoke-chaincode - event promise all complete and testing complete // 交易会由orderer打包成区块,最终由peer写入各自的账本 [2017-10-16 11:07:43.046] [INFO] invoke-chaincode - Successfully sent transaction to the orderer.
相关文章推荐
- Hyperledger Fabric SDK 示例fabric-samples-《balance-transfer》之十一《查询已经安装/实例化的chaincode》
- Hyperledger Fabric SDK 示例fabric-samples-《balance-transfer》之七《查询chaincode》
- Hyperledger Fabric SDK 示例fabric-samples-《balance-transfer》之八《查询指定的区块信息》
- Hyperledger Fabric SDK 示例fabric-samples-《balance-transfer》之三《加入到Channel》
- Hyperledger Fabric SDK 示例fabric-samples-《balance-transfer》之十二《查询已经加入的channel名称》
- Hyperledger Fabric SDK 示例fabric-samples-《balance-transfer》之四《安装chaincode》
- Hyperledger Fabric SDK 示例fabric-samples-《balance-transfer》之五《初始化chaincode》
- Hyperledger Fabric SDK 示例fabric-samples-《balance-transfer》之九《查询指定的交易信息》
- Hyperledger Fabric SDK 示例fabric-samples-《balance-transfer》之十《查询链信息》
- Hyperledger Fabric SDK 示例fabric-samples-《balance-transfer》之二《创建Channel》
- Hyperledger Fabric SDK 示例fabric-samples-《balance-transfer》之一《注册用户》
- Hyperledger Fabric SDK 示例 fabric-samples-《balance-transfer》之简介
- hyperledger/fabric-sdk-node测试运行
- windows下 hyperledger fabric-sdk-go编译
- HyperLedger Fabric的Java Chaincode配置
- 在 hyperledger fabric 环境对Validating Peers布署 chaincode (智能合约)
- Hyperledger fabric Client Node.js Hello World示例程序
- hyperledger fabric-sample 运行 chaincode-docker-devmode 遇到的坑
- hyperledger/fabric sdk-java编译
- Hyperledger Fabric(三)- fabric-sdk-java