本文已在我的公众号Fabric技术分享原创首发。
转载请标明出处:
https://blog.csdn.net/qq_27818541/article/details/78390354
本文出自:【BigManing的博客】
前言
初始化chaincode只需要在一个节点上初始即可。我们需要指定以下参数:
- channel名称
- chaincode名称
- chaincode版本
- 初始化要执行的方法(默认为
Init
) - 方法参数
本例中chaincode初始化的时候会调用合约的Init
的方法,所以我们需要传递该方法内部定义的参数,我们先来看下该Init
的具体实现:
example_cc.go
func (t *SimpleChaincode) Init(stub shim.ChaincodeStubInterface) pb.Response {
logger.Info("########### example_cc0 Init ###########")
_, args := stub.GetFunctionAndParameters()
var A, B string // Entities
var Aval, Bval int // Asset holdings
var err error
// 1 获取四个参数
// Initialize the chaincode
A = args[0]
Aval, err = strconv.Atoi(args[1])
if err != nil {
return shim.Error("Expecting integer value for asset holding")
}
B = args[2]
Bval, err = strconv.Atoi(args[3])
if err != nil {
return shim.Error("Expecting integer value for asset holding")
}
logger.Info("Aval = %d, Bval = %d\n", Aval, Bval)
//2 写入到分类账中(类似map一样 k-v存储)
// Write the state 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
//初始化chaincode Instantiate chaincode on target peers
app.post('/channels/:channelName/chaincodes', function(req, res) {
logger.debug('==================== INSTANTIATE CHAINCODE ==================');
var chaincodeName = req.body.chaincodeName;
var chaincodeVersion = req.body.chaincodeVersion;
var channelName = req.params.channelName;
var fcn = req.body.fcn;
var args = req.body.args;
//1 参数校验
// channel名字
logger.debug('channelName : ' + channelName);
//chaincode名字
logger.debug('chaincodeName : ' + chaincodeName);
//chaincode版本
logger.debug('chaincodeVersion : ' + chaincodeVersion); //
//执行的方法
logger.debug('fcn : ' + fcn);
//方法参数
logger.debug('args : ' + args);
if (!chaincodeName) {
res.json(getErrorMessage('\'chaincodeName\''));
return;
}
if (!chaincodeVersion) {
res.json(getErrorMessage('\'chaincodeVersion\''));
return;
}
if (!channelName) {
res.json(getErrorMessage('\'channelName\''));
return;
}
if (!args) {
res.json(getErrorMessage('\'args\''));
return;
}
//2 具体实现
instantiate.instantiateChaincode(channelName, chaincodeName, chaincodeVersion, fcn, args, req.username, req.orgname)
.then(function(message) {
res.send(message);
});
});
具体实现
instantiate-chaincode.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 EventHub = require('fabric-client/lib/EventHub.js');
var helper = require('./helper.js');
var logger = helper.getLogger('instantiate-chaincode');
var ORGS = hfc.getConfigSetting('network-config');
var tx_id = null;
var eh = null;
var instantiateChaincode = function(channelName, chaincodeName, chaincodeVersion, functionName, args, username, org) {
logger.debug('\n============ Instantiate chaincode on organization ' + org +
' ============\n');
var channel = helper.getChannelForOrg(org);
var client = helper.getClientForOrg(org);
// 1 获取组织管理员
return helper.getOrgAdmin(org).then((user) => {
// read the config block from the orderer for the channel
// and initialize the verify MSPs based on the participating
// organizations
// 2 初始化 channel 的msp 会从order里获取配置
return channel.initialize();
}, (err) => {
logger.error('Failed to enroll user \'' + username + '\'. ' + err);
throw new Error('Failed to enroll user \'' + username + '\'. ' + err);
}).then((success) => {
tx_id = client.newTransactionID();
// send proposal to endorser
//3.1封装提案请求
var request = {
chaincodeId: chaincodeName,
chaincodeVersion: chaincodeVersion,
args: args,
txId: tx_id
};
if (functionName)
request.fcn = functionName;
// 3.2 提交初始化chaincode提案给背书节点
return channel.sendInstantiateProposal(request);
}, (err) => {
logger.error('Failed to initialize the channel');
throw new Error('Failed to initialize the channel');
}).then((results) => {
var proposalResponses = results[0];
var proposal = results[1];
var all_good = true;
//4 验证所有的背书响应是否ok
for (var i in proposalResponses) {
let one_good = false;
if (proposalResponses && proposalResponses[i].response &&
proposalResponses[i].response.status === 200) {
one_good = true;
logger.info('instantiate proposal was good');
} else {
logger.error('instantiate proposal was bad');
}
all_good = all_good & one_good;
}
if (all_good) {
logger.info(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));
//4.0 封装交易请求
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 deployId = tx_id.getTransactionID();
// 4.1 设置监听事件链接
eh = client.newEventHub();
let data = fs.readFileSync(path.join(__dirname, ORGS[org].peers['peer1'][
'tls_cacerts'
]));
eh.setPeerAddr(ORGS[org].peers['peer1']['events'], {
pem: Buffer.from(data).toString(),
'ssl-target-name-override': ORGS[org].peers['peer1']['server-hostname']
});
eh.connect();
//4.2 监听事件并设置超时, 生成promise
let txPromise = new Promise((resolve, reject) => {
let handle = setTimeout(() => {
eh.disconnect();
reject();
}, 30000);
eh.registerTxEvent(deployId, (tx, code) => {
logger.info(
'The chaincode instantiate transaction has been committed on peer ' +
eh._ep._endpoint.addr);
clearTimeout(handle);
eh.unregisterTxEvent(deployId);
eh.disconnect();
if (code !== 'VALID') {
logger.error('The chaincode instantiate transaction was invalid, code = ' + code);
reject();
} else {
logger.info('The chaincode instantiate transaction was valid.');
resolve();
}
});
});
// 5 背书响应ok 发送交易
var sendPromise = channel.sendTransaction(request);
//6 集成promise 并运行
return Promise.all([sendPromise].concat([txPromise])).then((results) => {
logger.debug('Event promise all complete and testing complete');
//7 这个是第五步执行的结果
return results[0]; // the first returned value is from the 'sendPromise' which is from the 'sendTransaction()' call
}).catch((err) => {
logger.error(
util.format('Failed to send instantiate transaction and get notifications within the timeout period. %s', err)
);
return 'Failed to send instantiate transaction and get notifications within the timeout period.';
});
} else {
logger.error(
'Failed to send instantiate Proposal or receive valid response. Response null or status is not 200. exiting...'
);
return 'Failed to send instantiate Proposal or receive valid response. Response null or status is not 200. exiting...';
}
}, (err) => {
logger.error('Failed to send instantiate proposal due to error: ' + err.stack ?
err.stack : err);
return 'Failed to send instantiate 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 'Chaincode Instantiation is SUCCESS';
} 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 instantiate due to error: ' + err.stack ? err
.stack : err);
return 'Failed to send instantiate due to error: ' + err.stack ? err.stack :
err;
});
};
exports.instantiateChaincode = instantiateChaincode;
基本流程
API访问
echo "POST instantiate chaincode on peer1 of Org1"
echo
curl -s -X POST \
http://localhost:4000/channels/mychannel/chaincodes \
-H "authorization: Bearer $ORG1_TOKEN" \
-H "content-type: application/json" \
-d '{
"chaincodeName":"mycc",
"chaincodeVersion":"v0",
"args":["a","100","b","200"]
}'
echo
echo
控制台打印:
POST instantiate chaincode on peer1 of Org1
Chaincode Instantiation is SUCCESS
后台打印:
[2017-10-16 11:07:12.477] [DEBUG] SampleWebApp - Decoded from JWT token: username - Jim, orgname - org1
[2017-10-16 11:07:12.477] [DEBUG] SampleWebApp - ==================== INSTANTIATE CHAINCODE ==================
// 后台获取到的参数
[2017-10-16 11:07:12.477] [DEBUG] SampleWebApp - channelName : mychannel
[2017-10-16 11:07:12.477] [DEBUG] SampleWebApp - chaincodeName : mycc
[2017-10-16 11:07:12.477] [DEBUG] SampleWebApp - chaincodeVersion : v0
[2017-10-16 11:07:12.477] [DEBUG] SampleWebApp - fcn : undefined
[2017-10-16 11:07:12.478] [DEBUG] SampleWebApp - args : a,100,b,200
[2017-10-16 11:07:12.478] [DEBUG] instantiate-chaincode -
============ Instantiate chaincode on organization org1 ============
[2017-10-16 11:07:12.478] [DEBUG] Helper - [crypto_ecdsa_aes]: constructor, keySize: 256
[2017-10-16 11:07:12.478] [DEBUG] Helper - [crypto_ecdsa_aes]: Hash algorithm: SHA2, hash output size: 256
[2017-10-16 11:07:12.479] [DEBUG] Helper - [utils.CryptoKeyStore]: CryptoKeyStore, constructor - start
[2017-10-16 11:07:12.479] [DEBUG] Helper - [utils.CryptoKeyStore]: constructor, no super class specified, using config: fabric-client/lib/impl/FileKeyValueStore.js
[2017-10-16 11:07:12.479] [DEBUG] Helper - [FileKeyValueStore.js]: FileKeyValueStore.js - constructor
[2017-10-16 11:07:12.482] [DEBUG] Helper - Msp ID : Org1MSP
[2017-10-16 11:07:12.482] [DEBUG] Helper - [crypto_ecdsa_aes]: importKey - start
[2017-10-16 11:07:12.483] [DEBUG] Helper - [crypto_ecdsa_aes]: importKey - have the key [Circular]
[2017-10-16 11:07:12.484] [DEBUG] Helper - [utils.CryptoKeyStore]: This class requires a CryptoKeyStore to save keys, using the store: {"opts":{"path":"/tmp/fabric-client-kvs_peerOrg1"}}
[2017-10-16 11:07:12.484] [DEBUG] Helper - [FileKeyValueStore.js]: FileKeyValueStore.js - constructor
[2017-10-16 11:07:12.485] [DEBUG] Helper - [utils.CryptoKeyStore]: _getKeyStore returning ks
[2017-10-16 11:07:12.485] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param X: 0a66f3503a3322b2ca8e9dce03322d486ee6ec5970efaad3f153bc13aa2d942c
[2017-10-16 11:07:12.485] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param Y: 312ad05190fa592fb9e8ac2dcdb23c84df7f49e4ee295c2aa1200a50c9146c46
[2017-10-16 11:07:12.488] [DEBUG] Helper - [FileKeyValueStore.js]: FileKeyValueStore -- setValue
[2017-10-16 11:07:12.488] [DEBUG] Helper - [crypto_ecdsa_aes]: importKey - start
[2017-10-16 11:07:12.488] [DEBUG] Helper - [crypto_ecdsa_aes]: importKey - have the key [Circular]
[2017-10-16 11:07:12.489] [DEBUG] Helper - [utils.CryptoKeyStore]: _getKeyStore resolving store
[2017-10-16 11:07:12.489] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param X: 0a66f3503a3322b2ca8e9dce03322d486ee6ec5970efaad3f153bc13aa2d942c
[2017-10-16 11:07:12.489] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param Y: 312ad05190fa592fb9e8ac2dcdb23c84df7f49e4ee295c2aa1200a50c9146c46
[2017-10-16 11:07:12.489] [DEBUG] Helper - [FileKeyValueStore.js]: FileKeyValueStore -- setValue
[2017-10-16 11:07:12.490] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param X: 0a66f3503a3322b2ca8e9dce03322d486ee6ec5970efaad3f153bc13aa2d942c
[2017-10-16 11:07:12.490] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param Y: 312ad05190fa592fb9e8ac2dcdb23c84df7f49e4ee295c2aa1200a50c9146c46
[2017-10-16 11:07:12.490] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param X: 0a66f3503a3322b2ca8e9dce03322d486ee6ec5970efaad3f153bc13aa2d942c
[2017-10-16 11:07:12.491] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param Y: 312ad05190fa592fb9e8ac2dcdb23c84df7f49e4ee295c2aa1200a50c9146c46
[2017-10-16 11:07:12.491] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param X: 0a66f3503a3322b2ca8e9dce03322d486ee6ec5970efaad3f153bc13aa2d942c
[2017-10-16 11:07:12.491] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param Y: 312ad05190fa592fb9e8ac2dcdb23c84df7f49e4ee295c2aa1200a50c9146c46
[2017-10-16 11:07:12.491] [DEBUG] Helper - [FileKeyValueStore.js]: FileKeyValueStore -- setValue
[2017-10-16 11:07:12.498] [DEBUG] Helper - [crypto_ecdsa_aes]: ecdsa signature: Signature {
r: <BN: 543af07c0785003b0f406545e1ff7bc72dbdb78b9180719cb164d0230d35bd0b>,
s: <BN: 4d14477dcb169248fa51fab7721c4c54d34bdf3e24de19a93b63cc2de74eec27>,
recoveryParam: 1 }
[2017-10-16 11:07:12.510] [DEBUG] Helper - [crypto_ecdsa_aes]: ecdsa signature: Signature {
r: <BN: 5d56b83f757abe7e261a11e2dd737a03397b610c9ec66df6f2f617cb4bd118f7>,
s: <BN: 417d31cdb264150f32b8d7781d7c70e2d428064ab2b02057db2d68f653d98cc8>,
recoveryParam: 0 }
[2017-10-16 11:07:12.520] [DEBUG] Helper - [crypto_ecdsa_aes]: constructor, keySize: 256
[2017-10-16 11:07:12.521] [DEBUG] Helper - [crypto_ecdsa_aes]: Hash algorithm: SHA2, hash output size: 256
[2017-10-16 11:07:12.521] [DEBUG] Helper - [utils.CryptoKeyStore]: CryptoKeyStore, constructor - start
[2017-10-16 11:07:12.521] [DEBUG] Helper - [utils.CryptoKeyStore]: constructor, no super class specified, using config: fabric-client/lib/impl/FileKeyValueStore.js
[2017-10-16 11:07:12.522] [DEBUG] Helper - [crypto_ecdsa_aes]: constructor, keySize: 256
[2017-10-16 11:07:12.522] [DEBUG] Helper - [crypto_ecdsa_aes]: Hash algorithm: SHA2, hash output size: 256
[2017-10-16 11:07:12.522] [DEBUG] Helper - [utils.CryptoKeyStore]: CryptoKeyStore, constructor - start
[2017-10-16 11:07:12.522] [DEBUG] Helper - [utils.CryptoKeyStore]: constructor, no super class specified, using config: fabric-client/lib/impl/FileKeyValueStore.js
[2017-10-16 11:07:12.530] [DEBUG] Helper - [crypto_ecdsa_aes]: ecdsa signature: Signature {
r: <BN: 26309898c764726afae02fc8db2d9a90940ef1e01ee4ef29a5fb499c3b8a7ea>,
s: <BN: 3741f21b4bb248ef180260f9f171e3d9ed0e870b1c850032ccee86d127085e32>,
recoveryParam: 1 }
[2017-10-16 11:07:38.630] [INFO] instantiate-chaincode - instantiate proposal was good
[2017-10-16 11:07:38.630] [INFO] instantiate-chaincode - instantiate proposal was good
// 发送交易提案成功 并且相应ok
[2017-10-16 11:07:38.630] [INFO] instantiate-chaincode - Successfully sent Proposal and received ProposalResponse: Status - 200, message - "OK", metadata - "
myccv0escc"vscc*(
Org1MSP
Org2MSP2D
�����ϧ�i?v��OCjˢ��"���Hq���Gb *PI�w�jL5x6^�E=�)ˡF�� ��C55: ���ԣV��k����ر���
>z!F�P"�+I�B,
Org1MSP
b�4��SP", endorsement signature: 0D 5�/Ց��%SׂU��r��kWڳd;[c� #�Τ��1@p/�\h1�C�?�'w,��܅
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:38.642] [DEBUG] Helper - [crypto_ecdsa_aes]: ecdsa signature: Signature {
r: <BN: e1cdeef11d37de28810bed04d525abf4ed4959899f64e7129483110b07d9ef50>,
s: <BN: 65720ba0dfcdb959cce0a3d69b016097c7895aab1891172ded659aece90d467e>,
recoveryParam: 1 }
[2017-10-16 11:07:38.647] [DEBUG] Helper - [crypto_ecdsa_aes]: ecdsa signature: Signature {
r: <BN: cd796d1905d53fc6619f2a8d3d597d8e45de7264b0be0324447846510bf5af37>,
s: <BN: 5f8efb833b37d2d7a141a952b482933a9b9ba6653c39020a29e2dff59d6fe46>,
recoveryParam: 0 }
[2017-10-16 11:07:40.802] [INFO] instantiate-chaincode - The chaincode instantiate transaction has been committed on peer localhost:7053
[2017-10-16 11:07:40.808] [DEBUG] Helper - [crypto_ecdsa_aes]: ecdsa signature: Signature {
r: <BN: ab6a1ea9d36c8cabc53cad8cfdf545dc0f7e7751bf43979552bb980f7fcb4b7e>,
s: <BN: 1839adef53808d6e3ffba1f40495827cc6b4fa047d2c03dfe9ab76933581d35b>,
recoveryParam: 1 }
// 交易 有效 ok
[2017-10-16 11:07:40.809] [INFO] instantiate-chaincode - The chaincode instantiate transaction was valid.
[2017-10-16 11:07:40.809] [DEBUG] instantiate-chaincode - Event promise all complete and testing complete
[2017-10-16 11:07:40.809] [INFO] instantiate-chaincode - Successfully sent transaction to the orderer.