balance transfer代码解析及api深度追踪(五)初始化链码

一代码解析
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();(1)
}, (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)(4);
}, (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深度追踪
(1)
* Initializes the channel object with the Membership Service Providers (MSPs). The channel’s
* MSPs are critical in providing applications the ability to validate certificates and verify
* signatures in messages received from the fabric backend. For instance, after calling
* [sendTransactionProposal()]{@link Channel#sendTransactionProposal}, the application can
* verify the signatures in the proposal response’s endorsements to ensure they have not been
* tampered with.
*


* This method retrieves the configuration from the orderer if no “config” parameter is passed in.
* Optionally a configuration may be passed in to initialize this channel without making the call
* to the orderer.
*
* @param {byte[]} config - Optional. An encoded (a.k.a un-decoded) byte array of the protobuf “ConfigUpdate”
* @return {Promise} A Promise that will resolve when the action is complete
*

	initialize(config_update) {
		if (config_update) {
			this.loadConfigUpdate(config_update);
			return Promise.resolve(true);
		}

		var self = this;
		return this.getChannelConfig()(2)
			.then(
				function (config_envelope) {
					logger.debug('initialize - got config envelope from getChannelConfig :: %j', config_envelope);
					var config_items = self.loadConfigEnvelope(config_envelope);
					return Promise.resolve(config_items);
				}
			)
			.catch(
				function (error) {
					logger.error('initialize - system error ::' + error.stack ? error.stack : error);
					return Promise.reject(new Error(error));
				}
			);
	}

(2)
* Asks the peer for the current (latest) configuration block for this channel.
* @param {string | Peer} target - Optional. The peer to be used to make the
* request.
* @returns {Promise} A Promise for a {@link ConfigEnvelope} object containing the configuration items.
*/

	getChannelConfig(target) {
		let method = 'getChannelConfig';
		logger.debug('%s - start for channel %s', method, this._name);
		var targets = this._getTargetForQuery(target);
		var signer = this._clientContext._getSigningIdentity(true);
		var tx_id = new TransactionID(signer, true);
		var request = {
			targets: targets,
			chaincodeId: Constants.CSCC,
			txId: tx_id,
			signer: signer,
			fcn: 'GetConfigBlock',
			args: [this._name]
		};
		return this.sendTransactionProposal(request)(3)
			.then(
				function (results) {
					var responses = results[0];
					// var proposal = results[1];
					logger.debug('%s - results received', method);
					if (responses && Array.isArray(responses)) {
						let response = responses[0];
						if (response instanceof Error) {
							return Promise.reject(response);
						}
						else if (response.response && response.response.payload) {
							let block = _commonProto.Block.decode(response.response.payload);
							let envelope = _commonProto.Envelope.decode(block.data.data[0]);
							let payload = _commonProto.Payload.decode(envelope.payload);
							let config_envelope = _configtxProto.ConfigEnvelope.decode(payload.data);
							return Promise.resolve(config_envelope);
						}
						else {
							logger.error('%s - unknown response ::%s', method, response);
							return Promise.reject(new Error(response));
						}
					}
					return Promise.reject(new Error('Payload results are missing from the get channel config'));
				}
			).catch(
				function (err) {
					logger.error('%s - Failed getting channel config. Error: %s', method, err.stack ? err.stack : err);
					return Promise.reject(err);
				}
			);
	}

(3)
* Sends a transaction proposal to one or more endorsing peers.
*
* After a chaincode gets [installed]{@link Client#installChaincode} and
* [instantiated]{@link Channel#instantiateChaincode}, it’s ready to take endorsement
* proposals and participating in transaction processing. A chaincode transaction
* starts with a proposal that gets sent to the endorsing peers, which executes
* the target chaincode and decides whether the proposal should be endorsed (if it
* executes successfully) or not (if the chaincode returns an error).
*
* @param {ChaincodeInvokeRequest} request
* @param {Number} timeout - A number indicating milliseconds to wait on the
* response before rejecting the promise with a
* timeout error. This overrides the default timeout
* of the Peer instance and the global timeout in the config settings.
* @returns {Promise} A Promise for the {@link ProposalResponseObject}
*/

	sendTransactionProposal(request, timeout) {
		logger.debug('sendTransactionProposal - start');

		if (!request) {
			throw new Error('Missing request object for this transaction proposal');
		}
		request.targets = this._getTargets(request.targets, Constants.NetworkConfig.ENDORSING_PEER_ROLE);

		return Channel.sendTransactionProposal(request, this._name, this._clientContext, timeout);
	}

	/*
	 * Internal static method to allow transaction proposals to be called without
	 * creating a new channel
	 */
	static sendTransactionProposal(request, channelId, clientContext, timeout) {
		// Verify that a Peer has been added
		var errorMsg = clientUtils.checkProposalRequest(request);

		if (errorMsg) {
			// do nothing so we skip the rest of the checks
		} else if (!request.args) {
			// args is not optional because we need for transaction to execute
			errorMsg = 'Missing "args" in Transaction proposal request';
		} else if (!request.targets || request.targets.length < 1) {
			errorMsg = 'Missing peer objects in Transaction proposal';
		}

		if (errorMsg) {
			logger.error('sendTransactionProposal error ' + errorMsg);
			throw new Error(errorMsg);
		}

		var args = [];
		args.push(Buffer.from(request.fcn ? request.fcn : 'invoke', 'utf8'));
		logger.debug('sendTransactionProposal - adding function arg:%s', request.fcn ? request.fcn : 'invoke');

		for (let i = 0; i < request.args.length; i++) {
			logger.debug('sendTransactionProposal - adding arg:%s', request.args[i]);
			args.push(Buffer.from(request.args[i], 'utf8'));
		}
		//special case to support the bytes argument of the query by hash
		if (request.argbytes) {
			logger.debug('sendTransactionProposal - adding the argument :: argbytes');
			args.push(request.argbytes);
		}
		else {
			logger.debug('sendTransactionProposal - not adding the argument :: argbytes');
		}
		let invokeSpec = {
			type: _ccProto.ChaincodeSpec.Type.GOLANG,
			chaincode_id: {
				name: request.chaincodeId
			},
			input: {
				args: args
			}
		};

		var proposal, header;
		var signer = null;
		if (request.signer) {
			signer = request.signer;
		} else {
			signer = clientContext._getSigningIdentity(request.txId.isAdmin());
		}
		var channelHeader = clientUtils.buildChannelHeader(
			_commonProto.HeaderType.ENDORSER_TRANSACTION,
			channelId,
			request.txId.getTransactionID(),
			null,
			request.chaincodeId,
			clientUtils.buildCurrentTimestamp(),
			request.targets[0].getClientCertHash()
		);
		header = clientUtils.buildHeader(signer, channelHeader, request.txId.getNonce());
		proposal = clientUtils.buildProposal(invokeSpec, header, request.transientMap);
		let signed_proposal = clientUtils.signProposal(signer, proposal);

		return clientUtils.sendPeersProposal(request.targets, signed_proposal, timeout)
			.then(
				function (responses) {
					return Promise.resolve([responses, proposal]);
				}
			).catch(
				function (err) {
					logger.error('Failed Proposal. Error: %s', err.stack ? err.stack : err);
					return Promise.reject(err);
				}
			);
	}

(4)
* Sends a chaincode instantiate proposal to one or more endorsing peers.
*
* A chaincode must be instantiated on a channel-by-channel basis before it can
* be used. The chaincode must first be installed on the endorsing peers where
* this chaincode is expected to run, by calling [client.installChaincode()]{@link Client#installChaincode}.
*


* Instantiating a chaincode is a full transaction operation, meaning it must be
* first endorsed as a proposal, then the endorsements are sent to the orderer
* to be processed for ordering and validation. When the transaction finally gets
* committed to the channel’s ledger on the peers, the chaincode is then considered
* activated and the peers are ready to take requests to process transactions.
*
* @param {ChaincodeInstantiateUpgradeRequest} request
* @param {Number} timeout - A number indicating milliseconds to wait on the
* response before rejecting the promise with a
* timeout error. This overrides the default timeout
* of the Peer instance and the global timeout in the config settings.
* @returns {Promise} A Promise for the {@link ProposalResponseObject}
*/

	sendInstantiateProposal(request, timeout) {
		return this._sendChaincodeProposal(request, 'deploy', timeout);
	}

	/**
	 * Sends a chaincode upgrade proposal to one or more endorsing peers.
	 *
	 * Upgrading a chaincode involves steps similar to instantiating a chaincode.
	 * The new chaincode must first be installed on the endorsing peers where
	 * this chaincode is expected to run.
	 * <br><br>
	 * Similar to instantiating a chaincode, upgrading chaincodes is also a full transaction
	 * operation.
	 *
	 * @param {ChaincodeInstantiateUpgradeRequest} request
	 * @param {Number} timeout - A number indicating milliseconds to wait on the
	 *                              response before rejecting the promise with a
	 *                              timeout error. This overrides the default timeout
	 *                              of the Peer instance and the global timeout in the config settings.
	 * @returns {Promise} A Promise for the {@link ProposalResponseObject}
	 */
	sendUpgradeProposal(request, timeout) {
		return this._sendChaincodeProposal(request, 'upgrade', timeout);
	}

	/*
	 * Internal method to handle both chaincode calls
	 */
	_sendChaincodeProposal(request, command, timeout) {
		let errorMsg = null;

		//validate the incoming request
		if (!errorMsg) errorMsg = clientUtils.checkProposalRequest(request);
		if (!errorMsg) errorMsg = clientUtils.checkInstallRequest(request);
		if (errorMsg) {
			logger.error('sendChainCodeProposal error ' + errorMsg);
			return Promise.reject(new Error(errorMsg));
		}
		const peers = this._getTargets(request.targets, Constants.NetworkConfig.ENDORSING_PEER_ROLE);

		// args is optional because some chaincode may not need any input parameters during initialization
		if (!request.args) {
			request.args = [];
		}

		// step 1: construct a ChaincodeSpec
		const args = [];
		args.push(Buffer.from(request.fcn ? request.fcn : 'init', 'utf8'));

		for (let arg of request.args)
			args.push(Buffer.from(arg, 'utf8'));

		const ccSpec = {
			type: clientUtils.translateCCType(request.chaincodeType),
			chaincode_id: {
				name: request.chaincodeId,
				version: request.chaincodeVersion
			},
			input: {
				args: args
			}
		};

		// step 2: construct the ChaincodeDeploymentSpec
		const chaincodeDeploymentSpec = new _ccProto.ChaincodeDeploymentSpec();
		chaincodeDeploymentSpec.setChaincodeSpec(ccSpec);

		const signer = this._clientContext._getSigningIdentity(request.txId.isAdmin());
		const lcccSpec_args = [
			Buffer.from(command),
			Buffer.from(this._name),
			chaincodeDeploymentSpec.toBuffer()
		];
		if (request['endorsement-policy']) {
			lcccSpec_args[3] = this._buildEndorsementPolicy(request['endorsement-policy']);
		}

		const lcccSpec = {
			// type: _ccProto.ChaincodeSpec.Type.GOLANG,
			type: clientUtils.translateCCType(request.chaincodeType),
			chaincode_id: { name: Constants.LSCC },
			input: { args: lcccSpec_args }
		};

		const channelHeader = clientUtils.buildChannelHeader(
			_commonProto.HeaderType.ENDORSER_TRANSACTION,
			this._name,
			request.txId.getTransactionID(),
			null,
			Constants.LSCC,
			clientUtils.buildCurrentTimestamp(),
			peers[0].getClientCertHash()
		);
		const header = clientUtils.buildHeader(signer, channelHeader, request.txId.getNonce());
		const proposal = clientUtils.buildProposal(lcccSpec, header, request.transientMap);
		const signed_proposal = clientUtils.signProposal(signer, proposal);

		return clientUtils.sendPeersProposal(peers, signed_proposal, timeout)
			.then(
				function (responses) {
					return [responses, proposal];
				}
			);
	}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值