transfer balance 解析及深度追踪(二)创建通道

一 代码解析
var createChannel = function(channelName, channelConfigPath, username, orgName) {
logger.debug(’\n====== Creating Channel ‘’ + channelName + ‘’ ======\n’);
var client = helper.getClientForOrg(orgName);
var channel = helper.getChannelForOrg(orgName);

var envelope = fs.readFileSync(path.join(__dirname, channelConfigPath));
// 提取配置信息 extract the channel config bytes from the envelope to be signed
var channelConfig = client.extractChannelConfig(1)(envelope);
return helper.getOrgAdmin(orgName)(2).then((admin) => {
logger.debug(util.format(‘Successfully acquired admin user for the organization “%s”’, orgName));
// sign the channel config bytes as “endorsement”, this is required by
// the orderer’s channel creation policy
//3 签名channel order要求 要创建(更新)的channel 必须要admin签名
let signature = client.signChannelConfig(3)(channelConfig);
let request = {
// byte[]
config: channelConfig,
// admin 签名后的数据
signatures: [signature],
name: channelName,
// 这个channel 中的order对象
orderer: channel.getOrderers()(4)[0],
txId: client.newTransactionID() (5) // 交易id
};
//4 通过client创建channel 里面 send to orderer 通过order来广播事务
return client.createChannel(6)(request);
}, (err) => {
logger.error(‘Failed to enroll user ‘’+username+’’. Error: ’ + err);
throw new Error(‘Failed to enroll user ‘’+username+’’’ + err);
}).then((response) => {
logger.debug(’ response ::%j’, response);
//5 处理响应结果
if (response && response.status === ‘SUCCESS’) {
logger.debug(‘Successfully created the channel.’);
let response = {
success: true,
message: ‘Channel ‘’ + channelName + ‘’ created Successfully’
};
return response;
} else {
logger.error(’\n!!! Failed to create the channel ‘’ + channelName +
‘’ !!!\n\n’);
throw new Error(‘Failed to create the channel ‘’ + channelName + ‘’’);
}
}, (err) => {
logger.error('Failed to initialize the channel: ’ + err.stack ? err.stack :
err);
throw new Error('Failed to initialize the channel: ’ + err.stack ? err.stack : err);
});
};
二 api追踪
(1)
* Extracts the protobuf ‘ConfigUpdate’ object out of the ‘ConfigEnvelope’ object
* that is produced by the [configtxgen tool]{@link http://hyperledger-fabric.readthedocs.io/en/latest/configtxgen.html}.
* The returned object may then be signed using the signChannelConfig() method of this class. Once the all
* signatures have been collected, the ‘ConfigUpdate’ object and the signatures may be used
* on the [createChannel()]{@link Client#createChannel} or [updateChannel()]{@link Client#updateChannel} calls.
*
* @param {byte[]} config_envelope - The encoded bytes of the ConfigEnvelope protobuf
* @returns {byte[]} The encoded bytes of the ConfigUpdate protobuf, ready to be signed
*/

	extractChannelConfig(config_envelope) {
		logger.debug('extractConfigUpdate - start');
		try {
			var envelope = _commonProto.Envelope.decode(config_envelope);
			var payload = _commonProto.Payload.decode(envelope.getPayload().toBuffer());
			var configtx = _configtxProto.ConfigUpdateEnvelope.decode(payload.getData().toBuffer());
			return configtx.getConfigUpdate().toBuffer();
		}
		catch(err) {
			if(err instanceof Error) {
				logger.error('Problem with extracting the config update object :: %s', err.stack ? err.stack : err);
				throw err;
			}
			else {
				logger.error('Problem with extracting the config update object :: %s',err);
				throw new Error(err);
			}
		}
	}

(2)
var getOrgAdmin = function(userOrg) {
var admin = ORGS[userOrg].admin;
var keyPath = path.join(__dirname, admin.key);
var keyPEM = Buffer.from(readAllFiles(keyPath)[0]).toString();
var certPath = path.join(__dirname, admin.cert);
var certPEM = readAllFiles(certPath)[0].toString();
var client = getClientForOrg(userOrg);
var cryptoSuite = hfc.newCryptoSuite();
if (userOrg) {
cryptoSuite.setCryptoKeyStore(hfc.newCryptoKeyStore({path: getKeyStoreForOrg(getOrgName(userOrg))}));
client.setCryptoSuite(cryptoSuite);
}
return hfc.newDefaultKeyValueStore({
path: getKeyStoreForOrg(getOrgName(userOrg))
}).then((store) => {
client.setStateStore(store);
return client.createUser({
username: ‘peer’+userOrg+‘Admin’,
mspid: getMspID(userOrg),
cryptoContent: {
privateKeyPEM: keyPEM,
signedCertPEM: certPEM
}
});
});
};
(3)
/**
* Channel configuration updates can be sent to the orderers to be processed. The
* orderer enforces the Channel creation or update policies such that the updates
* will be made only when enough signatures from participating organizations are
* discovered in the request. Typically channel creation or update requests must
* be signed by participating organizations’ ADMIN principals, although this policy
* can be customized when the consortium is defined.
*


* This method uses the client instance’s current signing identity to sign over the
* configuration bytes passed in, and returns the signature that is ready to be
* included in the configuration update protobuf message to send to the orderer.
*
* @param {byte[]} config - The Configuration Update in byte form
* @return {ConfigSignature} - The signature of the current user on the config bytes
*/

	signChannelConfig(config) {
		logger.debug('signChannelConfigUpdate - start');
		if (typeof config === 'undefined' || config === null) {
			throw new Error('Channel configuration update parameter is required.');
		}
		if(!(config instanceof Buffer)) {
			throw new Error('Channel configuration update parameter is not in the correct form.');
		}
		// should try to use the admin signer if assigned
		// then use the assigned user
		var signer = this._getSigningIdentity(true);
		// signature is across a signature header and the config update
		let proto_signature_header = new _commonProto.SignatureHeader();
		proto_signature_header.setCreator(signer.serialize());
		proto_signature_header.setNonce(sdkUtils.getNonce());
		var signature_header_bytes = proto_signature_header.toBuffer();
		// get all the bytes to be signed together, then sign
		let signing_bytes = Buffer.concat([signature_header_bytes, config]);
		let sig = signer.sign(signing_bytes);
		let signature_bytes = Buffer.from(sig);
		// build the return object
		let proto_config_signature = new _configtxProto.ConfigSignature();
		proto_config_signature.setSignatureHeader(signature_header_bytes);
		proto_config_signature.setSignature(signature_bytes);
		return proto_config_signature;
	}

(4)

  • Returns the orderers of this channel object.
    * @returns {Orderer[]} The list of orderers in the channel object
    /
    getOrderers() {
    return this._orderers;
    }
    (5)
    /
    *
    * Returns a new {@link TransactionID} object. Fabric transaction ids are constructed
    * as a hash of a nonce concatenated with the signing identity’s serialized bytes. The
    * TransactionID object keeps the nonce and the resulting id string bundled together
    * as a coherent pair.
    *


    * This method requires the client instance to have been assigned a userContext.
    * @param {boolean} If this transactionID should be built based on the admin credentials
    * Default is a non admin TransactionID
    * @returns {TransactionID} An object that contains a transaction id based on the
    * client’s userContext and a randomly generated nonce value.
    */

      newTransactionID(admin) {
      	if(admin) {
      		if(typeof admin === 'boolean') {
      			if(admin) {
      				logger.debug('newTransactionID - getting an admin TransactionID');
      			} else {
      				logger.debug('newTransactionID - getting non admin TransactionID');
      			}
      		} else {
      			throw new Error('"admin" parameter must be of type boolean');
      		}
      	} else {
      		admin = false;
      		logger.debug('newTransactionID - no admin parameter, returning non admin TransactionID');
      	}
      	return new TransactionID(this._getSigningIdentity(admin), admin);
      }
    

/**
* The class representing the transaction identifier. Provides for
* automatically creating the nonce value when an instance of this
* object is created.
*
* @class
/
var TransactionID = class {
/
*
* Builds a new tranaction Id based on a user’s certificate and an automatically
* generates a nonce value.
* @param {Identity} signer_or_userContext - An instance of {@link Identity} that provides an unique
* base for this transaction id. This also may be an instance of a {@User}.
* @param {boolean} admin - Indicates that this instance will be used for administrative transactions.
*/

	constructor(signer_or_userContext, admin) {
		logger.debug('const - start');
		if (typeof signer_or_userContext === 'undefined' || signer_or_userContext === null) {
			throw new Error('Missing userContext or signing identity parameter');
		}
		var signer = null;
		if((User.isInstance(signer_or_userContext))) {
			signer = signer_or_userContext.getSigningIdentity();
		} else {
			signer = signer_or_userContext;
		}

		this._nonce = sdkUtils.getNonce(); //nonce is in bytes
		let creator_bytes = signer.serialize();//same as signatureHeader.Creator
		let trans_bytes = Buffer.concat([this._nonce, creator_bytes]);
		let trans_hash = hashPrimitives.sha2_256(trans_bytes);
		this._transaction_id = Buffer.from(trans_hash).toString();
		logger.debug('const - transaction_id %s',this._transaction_id);

		this._admin = admin;
	}
	/**
	 * The transaction ID
	 */
	getTransactionID() {
		return this._transaction_id;
	}
	/**
	 * The nonce value
	 */
	getNonce() {
		return this._nonce;
	}
	/**
	 * indicates if this transactionID was generated for an admin
	 */
	isAdmin() {
		if(this._admin) {
			return true;
		} else {
			return false;
		}
	}
};

module.exports = TransactionID;

(6)

  • @param {ChannelRequest} request - The request object.
    * @returns {Promise} Promise for a result object with status on the acceptance of the create request
    * by the orderer. Note that this is not the confirmation of successful creation
    * of the channel. The client application must poll the orderer to discover whether
    * the channel has been created completely or not.
    */

      createChannel(request) {
      	var have_envelope = false;
      	if(request && request.envelope) {
      		logger.debug('createChannel - have envelope');
      		have_envelope = true;
      	}
      	return this._createOrUpdateChannel(request, have_envelope);
      }
    
  • internal method to support create or update of a channel
    */

      _createOrUpdateChannel(request, have_envelope) {
      	logger.debug('_createOrUpdateChannel - start');
      	var error_msg = null;
      	var orderer = null;
      	if(!request) {
      		error_msg = 'Missing all required input request parameters for initialize channel';
      	}
      	// Verify that a config envelope or config has been included in the request object
      	else if (!request.config && !have_envelope) {
      		error_msg = 'Missing config request parameter containing the configuration of the channel';
      	}
      	else if(!request.signatures && !have_envelope) {
      		error_msg = 'Missing signatures request parameter for the new channel';
      	}
      	else if(!Array.isArray(request.signatures ) && !have_envelope) {
      		error_msg = 'Signatures request parameter must be an array of signatures';
      	}
      	else if(!request.txId && !have_envelope) {
      		error_msg = 'Missing txId request parameter';
      	}
      	// verify that we have the name of the new channel
      	else if(!request.name) {
      		error_msg = 'Missing name request parameter';
      	}
      	if(error_msg) {
      		logger.error('_createOrUpdateChannel error %s',error_msg);
      		return Promise.reject(new Error(error_msg));
      	}
      	try {
      		orderer = this.getTargetOrderer(request.orderer, null, request.name);
      	} catch (err) {
      		return Promise.reject(err);
      	}
    
      	var self = this;
      	var channel_id = request.name;
      	var channel = null;
          // caller should have gotten a admin based TransactionID
      	// but maybe not, so go with whatever they have decided
      	var signer = this._getSigningIdentity(request.txId.isAdmin());
      	var signature = null;
      	var payload = null;
      	if (have_envelope) {
      		logger.debug('_createOrUpdateChannel - have envelope');
      		var envelope = _commonProto.Envelope.decode(request.envelope);
      		signature = envelope.signature;
      		payload = envelope.payload;
      	}
      	else {
      		logger.debug('_createOrUpdateChannel - have config_update');
      		var proto_config_Update_envelope = new _configtxProto.ConfigUpdateEnvelope();
      		proto_config_Update_envelope.setConfigUpdate(request.config);
      		var signatures = _stringToSignature(request.signatures);
      		proto_config_Update_envelope.setSignatures(signatures);
      		var proto_channel_header = clientUtils.buildChannelHeader(
      			_commonProto.HeaderType.CONFIG_UPDATE,
      			request.name,
      			request.txId.getTransactionID()
      		);
      		var proto_header = clientUtils.buildHeader(signer, proto_channel_header, request.txId.getNonce());
      		var proto_payload = new _commonProto.Payload();
      		proto_payload.setHeader(proto_header);
      		proto_payload.setData(proto_config_Update_envelope.toBuffer());
      		var payload_bytes = proto_payload.toBuffer();
      		let sig = signer.sign(payload_bytes);
      		let signature_bytes = Buffer.from(sig);
      		signature = signature_bytes;
      		payload = payload_bytes;
      	}
      	// building manually or will get protobuf errors on send
      	var out_envelope = {
      		signature: signature,
      		payload : payload
      	};
      	logger.debug('_createOrUpdateChannel - about to send envelope');
      	return orderer.sendBroadcast(out_envelope)
      		.then(
      			function(results) {
      				logger.debug('_createOrUpdateChannel - good results from broadcast :: %j',results);
      				return Promise.resolve(results);
      			}
      		)
      		.catch(
      			function(error) {
      				if(error instanceof Error) {
      					logger.debug('_createOrUpdateChannel - rejecting with %s', error);
      					return Promise.reject(error);
      				}
      				else {
      					logger.error('_createOrUpdateChannel - system error :: %s', error);
      					return Promise.reject(new Error(error));
      				}
      			}
      		);
      }
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值