【系列】balance-transfer
本文在【BigManing的博客】的基础上有较大的改动
0 简介
前言
balance-transfer
├── app  // 与fabric网络交互的实现
│   ├── create-channel.js
│   ├── helper.js
│   ├── install-chaincode.js
│   ├── instantiate-chaincode.js
│   ├── invoke-transaction.js
│   ├── join-channel.js
#│   ├── network-config-aws.json
#│   ├── network-config.json
│   └── query.js
├── app.js   // 定义与fabric网络交互的API
├── artifacts  // 启动fabric网络需要的资料
│   ├── base.yaml
│   ├── channel
│   ├── docker-compose.yaml
│   └── src
├── config.js
├── config.json
├── node_modules
│   └── .......
├── package.json
├── package-lock.json
├── README.md
├── runApp.sh
└── testAPIs.sh
启动脚本
进入到balance-transfer目录,运行runApp.sh脚本,fabric网络以及node服务都会运行起来:
测试脚本
运行testAPIs.sh测试脚本,使用API来操作fabric网络,它主要做了:
- 创建channel
- 安装chaincode
- 初始化chaincode
- 执行chaincode
- 各种查询
1 注册用户
前言
找到app.js中关于users的路由:
//注册用户 
app.post('/users', function(req, res) {
	// 1 参数校验
	var username = req.body.username;
	var orgName = req.body.orgName;
	logger.debug('End point : /users');
	logger.debug('User name : ' + username);
	logger.debug('Org name  : ' + orgName);
	if (!username) {
		res.json(getErrorMessage('\'username\''));
		return;
	}
	if (!orgName) {
		res.json(getErrorMessage('\'orgName\''));
		return;
	}
	// 2 生成jwt  添加用户名以及组织信息
	var token = jwt.sign({
		exp: Math.floor(Date.now() / 1000) + parseInt(hfc.getConfigSetting('jwt_expiretime')),
		username: username,
		orgName: orgName
	}, app.get('secret'));
	// 3  注册用户  如果成功连同jwt一起返回
	helper.getRegisteredUsers(username, orgName, true).then(function(response) {
		if (response && typeof response !== 'string') {
			response.token = token;
			res.json(response);
		} else {
			res.json({
				success: false,
				message: response
			});
		}
	});
});
从上面得知要看具体实现,还需要进入helper.js中查看getRegisteredUsers():
var getRegisteredUsers = function(username, userOrg, isJson) {
	var member;
	var client = getClientForOrg(userOrg);
	var enrollmentSecret = null;
//   设置公私钥存储的地方   
	return hfc.newDefaultKeyValueStore({
		//  这里只要求path参数  来作为存储的地方
		path: getKeyStoreForOrg(getOrgName(userOrg))
	}).then((store) => {
		//  设置状态持久化存储(如(证书,私钥。。))
		client.setStateStore(store);
		// clearing the user context before switching
		client._userContext = null;
		//1  获取用户信息  (从 内存-->statestore  依次查找)
		return client.getUserContext(username, true).then((user) => {
			if (user && user.isEnrolled()) {
				//  从持久化中 成功加载此 user
				logger.info('Successfully loaded member from persistence');
				return user;
			} else {
				let caClient = caClients[userOrg];
				//2  获得adminuser 来注册账户
				return getAdminUser(userOrg).then(function(adminUserObj) {
					member = adminUserObj;
					return caClient.register({
						enrollmentID: username,
						//  与此用户关联的隶属关系
						affiliation: userOrg + '.department1'
					}, member); // 注册员
				}).then((secret) => {
					enrollmentSecret = secret;
					logger.debug(username + ' registered successfully');
					//3  注册成功后  拿着secret  来enroll
					return caClient.enroll({
						enrollmentID: username,
						enrollmentSecret: secret
					});
				}, (err) => {
					logger.debug(username + ' failed to register');
					return '' + err;
					//return 'Failed to register '+username+'. Error: ' + err.stack ? err.stack : err;
				}).then((message) => {  // enroll 返回的信息
					if (message && typeof message === 'string' && message.includes(
							'Error:')) {
						logger.error(username + ' enrollment failed');
						return message;
					}
					logger.debug(username + ' enrolled successfully');
					// 构建user对象 
					member = new User(username);
					member._enrollmentSecret = enrollmentSecret;
					//4  设置此User实例的注册对象  来持久化在client中
					return member.setEnrollment(message.key, message.certificate, getMspID(userOrg));
				}).then(() => {
					//5  保存用户的上下文环境(e.g 证书 私钥 ) 用户签名 各种请求
					client.setUserContext(member);
					return member;
				}, (err) => {
					logger.error(util.format('%s enroll failed: %s', username, err.stack ? err.stack : err));
					return '' + err;
				});;
			}
		});
	}).then((user) => {
		// 6 返回用户信息
		if (isJson && isJson === true) {
			var response = {
				success: true,
				secret: user._enrollmentSecret,
				message: username + ' enrolled Successfully',
			};
			return response;
		}
		return user;
	}, (err) => {
		logger.error(util.format('Failed to get registered user: %s, error: %s', username, err.stack ? err.stack : err));
		return '' + err;
	});
};
基本流程

API访问
为org1组织建立一个用户名为Jim的用户。在命令行里输入:
echo "POST request Enroll on Org1  ..."
echo
ORG1_TOKEN=$(curl -s -X POST \
  http://localhost:4000/users \
  -H "content-type: application/x-www-form-urlencoded" \
  -d 'username=Jim&orgName=org1')    
echo $ORG1_TOKEN
控制面板打印结果:
POST request Enroll on Org1  ...
{"success":true,"secret":"xDfluXIPURbu","message":"Jim enrolled Successfully","token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1MDgxNTkyMjQsInVzZXJuYW1lIjoiSmltIiwib3JnTmFtZSI6Im9yZzEiLCJpYXQiOjE1MDgxMjMyMjR9.rE5UuViSzmDcdHNZRXt22izpopY5eVkJ7YbfXILjSQk"}
echo "ORG1 token is $ORG1_TOKEN"
ORG1 token is 
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2MzE4ODY4NzMsInVzZXJuYW1lIjoiSmltIiwib3JnTmFtZSI6Ik9yZzEiLCJpYXQiOjE2MzE4NTA4NzN9.tFZxq0xvCMwb70x2P2z88o1ZfD260x3psINTV3KLF8k
ORG2 token is 
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE2MzE4ODY5NzEsInVzZXJuYW1lIjoiQmFycnkiLCJvcmdOYW1lIjoiT3JnMiIsImlhdCI6MTYzMTg1MDk3MX0.pGognmQr1rfXWYDN5HK9DE8ik_9auiZHtxK4_ItS5cE
// 上面的token是 访问后面API的必要参数
可以看出 Jim已经成功被注册了,其公私钥存放在/tmp/fabric-client-kvs_peerOrg1中(可在config.json中自定义keyValueStore路径):

node服务后台打印:
[2017-10-16 11:07:04.222] [DEBUG] SampleWebApp - End point : /users
[2017-10-16 11:07:04.222] [DEBUG] SampleWebApp - User name : Jim
[2017-10-16 11:07:04.222] [DEBUG] SampleWebApp - Org name  : org1
[2017-10-16 11:07:04.226] [DEBUG] Helper - [FileKeyValueStore.js]: FileKeyValueStore.js - constructor
[2017-10-16 11:07:04.228] [DEBUG] Helper - [FileKeyValueStore.js]: FileKeyValueStore -- getValue
[2017-10-16 11:07:04.230] [DEBUG] Helper - [FileKeyValueStore.js]: FileKeyValueStore.js - constructor
[2017-10-16 11:07:04.231] [DEBUG] Helper - [FileKeyValueStore.js]: FileKeyValueStore -- getValue
//----->公私钥存放路径
[2017-10-16 11:07:04.310] [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:04.311] [DEBUG] Helper - [FileKeyValueStore.js]: FileKeyValueStore.js - constructor
[2017-10-16 11:07:04.311] [DEBUG] Helper - [utils.CryptoKeyStore]: _getKeyStore returning ks
[2017-10-16 11:07:04.312] [DEBUG] Helper - [crypto_ecdsa_aes]: generateKey, store.setValue
[2017-10-16 11:07:04.313] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param X: 5f8df5637db9f5e75af2990de09b57214b1eefcf834002cd79e6e7a634a23b68
[2017-10-16 11:07:04.313] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param Y: bc8ce6511008bff20bb18ad6f105af889eb3c880cd2275cd97184d3378c47751
[2017-10-16 11:07:04.319] [DEBUG] Helper - [FileKeyValueStore.js]: FileKeyValueStore -- setValue
//----->获取admin
[2017-10-16 11:07:04.715] [INFO] Helper - Successfully enrolled user 'admin'
[2017-10-16 11:07:04.716] [DEBUG] Helper - Msp ID : Org1MSP
[2017-10-16 11:07:04.717] [DEBUG] Helper - [crypto_ecdsa_aes]: importKey - start
[2017-10-16 11:07:04.721] [DEBUG] Helper - [crypto_ecdsa_aes]: importKey - have the key [Circular]
[2017-10-16 11:07:04.722] [DEBUG] Helper - [utils.CryptoKeyStore]: _getKeyStore resolving store
[2017-10-16 11:07:04.723] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param X: 5f8df5637db9f5e75af2990de09b57214b1eefcf834002cd79e6e7a634a23b68
[2017-10-16 11:07:04.723] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param Y: bc8ce6511008bff20bb18ad6f105af889eb3c880cd2275cd97184d3378c47751
[2017-10-16 11:07:04.724] [DEBUG] Helper - [FileKeyValueStore.js]: FileKeyValueStore -- setValue
[2017-10-16 11:07:04.726] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param X: 5f8df5637db9f5e75af2990de09b57214b1eefcf834002cd79e6e7a634a23b68
[2017-10-16 11:07:04.726] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param Y: bc8ce6511008bff20bb18ad6f105af889eb3c880cd2275cd97184d3378c47751
[2017-10-16 11:07:04.727] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param X: 5f8df5637db9f5e75af2990de09b57214b1eefcf834002cd79e6e7a634a23b68
[2017-10-16 11:07:04.727] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param Y: bc8ce6511008bff20bb18ad6f105af889eb3c880cd2275cd97184d3378c47751
[2017-10-16 11:07:04.728] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param X: 5f8df5637db9f5e75af2990de09b57214b1eefcf834002cd79e6e7a634a23b68
[2017-10-16 11:07:04.728] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param Y: bc8ce6511008bff20bb18ad6f105af889eb3c880cd2275cd97184d3378c47751
[2017-10-16 11:07:04.728] [DEBUG] Helper - [FileKeyValueStore.js]: FileKeyValueStore -- setValue
[2017-10-16 11:07:04.743] [DEBUG] Helper - [crypto_ecdsa_aes]: ecdsa signature:  Signature {
  r: <BN: f1034e3347d230585a94f1ea21318d6217a20774754798641f599e33b8a9571f>,
  s: <BN: 5e4d05280fe82c2bbe93eb0e8fefb8998bacf160b6422e370b561c109b1c0ef2>,
  recoveryParam: 0 }
 
  //-----> Jim  register 成功
  
[2017-10-16 11:07:04.950] [DEBUG] Helper - Jim registered successfully
[2017-10-16 11:07:05.033] [DEBUG] Helper - [utils.CryptoKeyStore]: _getKeyStore resolving store
[2017-10-16 11:07:05.034] [DEBUG] Helper - [crypto_ecdsa_aes]: generateKey, store.setValue
[2017-10-16 11:07:05.034] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param X: b3e2a75b9a4fd2b081589b1c45bde49f583aea9d7d466798c7b765c4ca96973d
[2017-10-16 11:07:05.034] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param Y: c58820e5a9db75ab17841ac158e9389ad0d130a6827dc0682dcb2d2c5dccb349
 //-----> Jim  enrolled 成功
 
[2017-10-16 11:07:05.391] [DEBUG] Helper - Jim enrolled successfully
[2017-10-16 11:07:05.391] [DEBUG] Helper - Msp ID : Org1MSP
[2017-10-16 11:07:05.392] [DEBUG] Helper - [crypto_ecdsa_aes]: constructor, keySize: 256
[2017-10-16 11:07:05.392] [DEBUG] Helper - [crypto_ecdsa_aes]: Hash algorithm: SHA2, hash output size: 256
[2017-10-16 11:07:05.392] [DEBUG] Helper - [utils.CryptoKeyStore]: CryptoKeyStore, constructor - start
[2017-10-16 11:07:05.393] [DEBUG] Helper - [utils.CryptoKeyStore]: constructor, no super class specified, using config: fabric-client/lib/impl/FileKeyValueStore.js
[2017-10-16 11:07:05.393] [DEBUG] Helper - [crypto_ecdsa_aes]: importKey - start
[2017-10-16 11:07:05.393] [DEBUG] Helper - [crypto_ecdsa_aes]: importKey - have the key [Circular]
[2017-10-16 11:07:05.393] [DEBUG] Helper - [utils.CryptoKeyStore]: This class requires a CryptoKeyStore to save keys, using the store: {"opts":{"path":"/home/jiang/.hfc-key-store"}}
[2017-10-16 11:07:05.393] [DEBUG] Helper - [FileKeyValueStore.js]: FileKeyValueStore.js - constructor
[2017-10-16 11:07:05.394] [DEBUG] Helper - [utils.CryptoKeyStore]: _getKeyStore returning ks
[2017-10-16 11:07:05.394] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param X: b3e2a75b9a4fd2b081589b1c45bde49f583aea9d7d466798c7b765c4ca96973d
[2017-10-16 11:07:05.394] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param Y: c58820e5a9db75ab17841ac158e9389ad0d130a6827dc0682dcb2d2c5dccb349
[2017-10-16 11:07:05.395] [DEBUG] Helper - [FileKeyValueStore.js]: FileKeyValueStore -- setValue
[2017-10-16 11:07:05.396] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param X: b3e2a75b9a4fd2b081589b1c45bde49f583aea9d7d466798c7b765c4ca96973d
[2017-10-16 11:07:05.397] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param Y: c58820e5a9db75ab17841ac158e9389ad0d130a6827dc0682dcb2d2c5dccb349
[2017-10-16 11:07:05.398] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param X: b3e2a75b9a4fd2b081589b1c45bde49f583aea9d7d466798c7b765c4ca96973d
[2017-10-16 11:07:05.398] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param Y: c58820e5a9db75ab17841ac158e9389ad0d130a6827dc0682dcb2d2c5dccb349
[2017-10-16 11:07:05.399] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param X: b3e2a75b9a4fd2b081589b1c45bde49f583aea9d7d466798c7b765c4ca96973d
[2017-10-16 11:07:05.400] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param Y: c58820e5a9db75ab17841ac158e9389ad0d130a6827dc0682dcb2d2c5dccb349
[2017-10-16 11:07:05.400] [DEBUG] Helper - [FileKeyValueStore.js]: FileKeyValueStore -- setValue
2 创建Channel
前言
这里面有两个重要的参数:
- channel名称
- channel配置文件路径(…/artifacts/channel/mychannel.tx)
这个mychannel.tx是要事先生成好的文件。了解更多channel配置文件相关内容看这里。
路由
app.js
app.post('/channels', function(req, res) {
	logger.info('<<<<<<<<<<<<<<<<< C R E A T E  C H A N N E L >>>>>>>>>>>>>>>>>');
	logger.debug('End point : /channels');
	// 1  校验参数
	var channelName = req.body.channelName;
	var channelConfigPath = req.body.channelConfigPath;
	logger.debug('Channel name : ' + channelName);
	logger.debug('channelConfigPath : ' + channelConfigPath); //../artifacts/channel/mychannel.tx
	if (!channelName) {   // 参数一: channel名称
		res.json(getErrorMessage('\'channelName\''));
		return;
	}
	if (!channelConfigPath) { // 参数二: channel配置文件路径
		res.json(getErrorMessage('\'channelConfigPath\''));
		return;
	}
     // 2  创建通道
	channels.createChannel(channelName, channelConfigPath, req.username, req.orgname)
	.then(function(message) {
		res.send(message);
	});
});
具体实现
create-channel.js
var createChannel = function(channelName, channelConfigPath, username, orgName) {
	logger.debug('\n====== Creating Channel \'' + channelName + '\' ======\n');
	var client = helper.getClientForOrg(orgName);
	var channel = helper.getChannelForOrg(orgName);
	//1 读取channel配置 read in the envelope for the channel config raw bytes
	var envelope = fs.readFileSync(path.join(__dirname, channelConfigPath));
	// 提取配置信息 extract the channel config bytes from the envelope to be signed
	var channelConfig = client.extractChannelConfig(envelope);
	//2 在admin环境下 来初始化这个channel  Acting as a client in the given organization provided with "orgName" param
	return helper.getOrgAdmin(orgName).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(channelConfig);
		let request = {
			//  byte[]
			config: channelConfig,
			//  admin  签名后的数据
			signatures: [signature],
			name: channelName,
			//  这个channel 中的order对象
			orderer: channel.getOrderers()[0],
			txId: client.newTransactionID()  // 交易id
		};
		//4 通过client创建channel   里面  send to orderer  通过order来广播事务
		return client.createChannel(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访问
定义好两个参数channelName以及channelConfigPath ,输入shell命令:
echo "POST request Create channel  ..."
echo
curl -s -X POST \
  http://localhost:4000/channels \
  -H "authorization: Bearer $ORG1_TOKEN" \
  -H "content-type: application/json" \
  -d '{
	"channelName":"mychannel",
	"channelConfigPath":"../artifacts/channel/mychannel.tx"
}'
echo
$ORG1_TOKEN就是注册用户时返回的token。运行结果:
POST request Create channel  ...
{"success":true,"message":"Channel 'mychannel' created Successfully"}
node服务后台打印:
[2017-10-16 11:07:06.446] [DEBUG] SampleWebApp - Decoded from JWT token: username - Jim, orgname - org1
[2017-10-16 11:07:06.446] [INFO] SampleWebApp - <<<<<<<<<<<<<<<<< C R E A T E  C H A N N E L >>>>>>>>>>>>>>>>>
[2017-10-16 11:07:06.446] [DEBUG] SampleWebApp - End point : /channels
[2017-10-16 11:07:06.446] [DEBUG] SampleWebApp - Channel name : mychannel
[2017-10-16 11:07:06.446] [DEBUG] SampleWebApp - channelConfigPath : ../artifacts/channel/mychannel.tx
[2017-10-16 11:07:06.447] [DEBUG] Create-Channel - 
====== Creating Channel 'mychannel' ======
[2017-10-16 11:07:06.450] [DEBUG] Helper - [crypto_ecdsa_aes]: constructor, keySize: 256
[2017-10-16 11:07:06.451] [DEBUG] Helper - [crypto_ecdsa_aes]: Hash algorithm: SHA2, hash output size: 256
[2017-10-16 11:07:06.459] [DEBUG] Helper - [utils.CryptoKeyStore]: CryptoKeyStore, constructor - start
[2017-10-16 11:07:06.459] [DEBUG] Helper - [utils.CryptoKeyStore]: constructor, no super class specified, using config: fabric-client/lib/impl/FileKeyValueStore.js
[2017-10-16 11:07:06.459] [DEBUG] Helper - [FileKeyValueStore.js]: FileKeyValueStore.js - constructor
[2017-10-16 11:07:06.460] [DEBUG] Helper - Msp ID : Org1MSP
[2017-10-16 11:07:06.460] [DEBUG] Helper - [crypto_ecdsa_aes]: importKey - start
[2017-10-16 11:07:06.462] [DEBUG] Helper - [crypto_ecdsa_aes]: importKey - have the key [Circular]
[2017-10-16 11:07:06.462] [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:06.462] [DEBUG] Helper - [FileKeyValueStore.js]: FileKeyValueStore.js - constructor
[2017-10-16 11:07:06.463] [DEBUG] Helper - [utils.CryptoKeyStore]: _getKeyStore returning ks
[2017-10-16 11:07:06.463] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param X: 0a66f3503a3322b2ca8e9dce03322d486ee6ec5970efaad3f153bc13aa2d942c
[2017-10-16 11:07:06.463] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param Y: 312ad05190fa592fb9e8ac2dcdb23c84df7f49e4ee295c2aa1200a50c9146c46
[2017-10-16 11:07:06.463] [DEBUG] Helper - [FileKeyValueStore.js]: FileKeyValueStore -- setValue
[2017-10-16 11:07:06.464] [DEBUG] Helper - [crypto_ecdsa_aes]: importKey - start
[2017-10-16 11:07:06.464] [DEBUG] Helper - [crypto_ecdsa_aes]: importKey - have the key [Circular]
[2017-10-16 11:07:06.465] [DEBUG] Helper - [utils.CryptoKeyStore]: _getKeyStore resolving store
[2017-10-16 11:07:06.465] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param X: 0a66f3503a3322b2ca8e9dce03322d486ee6ec5970efaad3f153bc13aa2d942c
[2017-10-16 11:07:06.465] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param Y: 312ad05190fa592fb9e8ac2dcdb23c84df7f49e4ee295c2aa1200a50c9146c46
[2017-10-16 11:07:06.465] [DEBUG] Helper - [FileKeyValueStore.js]: FileKeyValueStore -- setValue
[2017-10-16 11:07:06.467] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param X: 0a66f3503a3322b2ca8e9dce03322d486ee6ec5970efaad3f153bc13aa2d942c
[2017-10-16 11:07:06.468] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param Y: 312ad05190fa592fb9e8ac2dcdb23c84df7f49e4ee295c2aa1200a50c9146c46
[2017-10-16 11:07:06.468] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param X: 0a66f3503a3322b2ca8e9dce03322d486ee6ec5970efaad3f153bc13aa2d942c
[2017-10-16 11:07:06.469] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param Y: 312ad05190fa592fb9e8ac2dcdb23c84df7f49e4ee295c2aa1200a50c9146c46
[2017-10-16 11:07:06.469] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param X: 0a66f3503a3322b2ca8e9dce03322d486ee6ec5970efaad3f153bc13aa2d942c
[2017-10-16 11:07:06.469] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param Y: 312ad05190fa592fb9e8ac2dcdb23c84df7f49e4ee295c2aa1200a50c9146c46
[2017-10-16 11:07:06.469] [DEBUG] Helper - [FileKeyValueStore.js]: FileKeyValueStore -- setValue
[2017-10-16 11:07:06.470] [DEBUG] Create-Channel - Successfully acquired admin user for the organization "org1"
[2017-10-16 11:07:06.481] [DEBUG] Helper - [crypto_ecdsa_aes]: ecdsa signature:  Signature {
  r: <BN: 69008cc4396fed179cc6b9876d94a1c7e95ad3ed023ddbcece4a574788e88419>,
  s: <BN: 56e1d31c5585f4d939dab9434a2fdb33c9e2afcf4eaac55200f07f9b8b72bfed>,
  recoveryParam: 0 }
[2017-10-16 11:07:06.490] [DEBUG] Helper - [crypto_ecdsa_aes]: ecdsa signature:  Signature {
  r: <BN: 78af3c9f44a0ecb540b942600949b081480eec07e230b7ebaa0e61218e215807>,
  s: <BN: 1ce9943f4853cd41add3f184a570dc3ea52335f8e23704fee3c804277fbfcbf9>,
  recoveryParam: 0 }
// 创建成功
[2017-10-16 11:07:06.561] [DEBUG] Create-Channel -  response ::{"status":"SUCCESS"}
[2017-10-16 11:07:06.561] [DEBUG] Create-Channel - Successfully created the channel.
3 加入到Channel
前言
这篇文章展示如何把peer节点加入到channel中,其中需要两个参数
- channelName 加入到哪个channel
- peers 把哪个节点加进去
定义好这两个参数,然后调用相关API 就可以了。
路由
app.js
//加入到channel    Join Channel
app.post('/channels/:channelName/peers', function(req, res) {
	logger.info('<<<<<<<<<<<<<<<<< J O I N  C H A N N E L >>>>>>>>>>>>>>>>>');
	//1 校验必要参数
	var channelName = req.params.channelName;
	var peers = req.body.peers;
	logger.debug('channelName : ' + channelName);
	logger.debug('peers : ' + peers);
	if (!channelName) {
		res.json(getErrorMessage('\'channelName\''));
		return;
	}
	if (!peers || peers.length == 0) {
		res.json(getErrorMessage('\'peers\''));
		return;
	}
	//2 使用封装好js方法 来 具体实现
	join.joinChannel(channelName, peers, req.username, req.orgname)
	.then(function(message) {
		res.send(message);
	});
});
具体实现
join-channel.js
var util = require('util');
var path = require('path');
var fs = require('fs');
var Peer = require('fabric-client/lib/Peer.js');
var EventHub = require('fabric-client/lib/EventHub.js');
var tx_id = null;
var nonce = null;
var config = require('../config.json');
var helper = require('./helper.js');
var logger = helper.getLogger('Join-Channel');
//helper.hfc.addConfigFile(path.join(__dirname, 'network-config.json'));
var ORGS = helper.ORGS;
var allEventhubs = [];
//
//Attempt to send a request to the orderer with the sendCreateChain method
// 在admin user下 获取 channel的 genises.block  然后 指定peers加入channel
//
var joinChannel = function(channelName, peers, username, org) {
	//关闭事件回调连接
	var closeConnections = function(isSuccess) {
		if (isSuccess) {
			logger.debug('\n============ Join Channel is SUCCESS ============\n');
		} else {
			logger.debug('\n!!!!!!!! ERROR: Join Channel FAILED !!!!!!!!\n');
		}
		logger.debug('');
		for (var key in allEventhubs) {
			var eventhub = allEventhubs[key];
			if (eventhub && eventhub.isconnected()) {
				//logger.debug('Disconnecting the event hub');
				eventhub.disconnect();
			}
		}
	};
	//logger.debug('\n============ Join Channel ============\n')
	logger.info(util.format(
		'Calling peers in organization "%s" to join the channel', org));
	var client = helper.getClientForOrg(org);
	var channel = helper.getChannelForOrg(org);
	var eventhubs = [];
    // 1  在管理员环境下 获取原始块(peer想要加入channel  就得需要这个东西)
	return helper.getOrgAdmin(org).then((admin) => {
		logger.info(util.format('received member object for admin of the organization "%s": ', org));
		tx_id = client.newTransactionID();
		let request = {
			txId : 	tx_id
		};
		return channel.getGenesisBlock(request);
	}).then((genesis_block) => {
        //	2 封装加入到channel的请求
		tx_id = client.newTransactionID();
		var request = {
			targets: helper.newPeers(peers, org),
			txId: tx_id,
			block: genesis_block
		};
		// 3.1  设置事件监听连接
		eventhubs = helper.newEventHubs(peers, org);
		for (let key in eventhubs) {
			let eh = eventhubs[key];
			eh.connect();
			allEventhubs.push(eh);
		}
		var eventPromises = [];
		eventhubs.forEach((eh) => {
			let txPromise = new Promise((resolve, reject) => {
				//3.2 监听区块信息   并设置超时时间
				let handle = setTimeout(reject, parseInt(config.eventWaitTime));
				eh.registerBlockEvent((block) => {
					clearTimeout(handle);
					// in real-world situations, a peer may have more than one channels so
					// we must check that this block came from the channel we asked the peer to join
					if (block.data.data.length === 1) {
						// Config block must only contain one transaction
						var channel_header = block.data.data[0].payload.header.channel_header;
						//3.3 属于本channel的信息  就继续执行  否则就拒绝
						if (channel_header.channel_id === channelName) {
							resolve();
						}
						else {
							reject();
						}
					}
				});
			});
			//3.4 设置 eventPromises集合
			eventPromises.push(txPromise);
		});
		//4  请求加入到channel
		let sendPromise = channel.joinChannel(request);
        // 5   promise流   ( 监听事件  发送事件 )  的 promise   全荣俱荣 一损俱损
		return Promise.all([sendPromise].concat(eventPromises));
	}, (err) => {
		logger.error('Failed to enroll user \'' + username + '\' due to error: ' +
			err.stack ? err.stack : err);
		throw new Error('Failed to enroll user \'' + username +
			'\' due to error: ' + err.stack ? err.stack : err);
	}).then((results) => {
        //7 根据state 判断结果   如果到这里了  说明是sendPromise 返回的结果
        logger.debug(util.format('Join Channel R E S P O N S E : %j', results));
        // 加入成功
		if (results[0] && results[0][0] && results[0][0].response && results[0][0]
			.response.status == 200) {
			logger.info(util.format(
				'Successfully joined peers in organization %s to the channel \'%s\'',
				org, channelName));
			closeConnections(true);
			let response = {
				success: true,
				message: util.format(
					'Successfully joined peers in organization %s to the channel \'%s\'',
					org, channelName)
			};
			return response;
		} else {
			//加入失败
			logger.error(' Failed to join channel');
			closeConnections();
			throw new Error('Failed to join channel');
		}
	}, (err) => {
		logger.error('Failed to join channel due to error: ' + err.stack ? err.stack :
			err);
		closeConnections();
		throw new Error('Failed to join channel due to error: ' + err.stack ? err.stack :
			err);
	});
};
exports.joinChannel = joinChannel;
基本流程

API访问
指定org1的两个peer加入到channel,在具体实现第2点里,helper.js会根据org,peer获取到peer对应的grpc地址,然后封装成一个完整的request。
echo "POST request Join channel on Org1"
echo
curl -s -X POST \
  http://localhost:4000/channels/mychannel/peers \
  -H "authorization: Bearer $ORG1_TOKEN" \
  -H "content-type: application/json" \
  -d '{
	"peers": ["peer1","peer2"]
}'
echo
echo
控制台打印:
POST request Join channel on Org1
{"success":true,"message":"Successfully joined peers in organization org1 to the channel 'mychannel'"}
后台打印:
[2017-10-16 11:07:11.584] [DEBUG] SampleWebApp - Decoded from JWT token: username - Jim, orgname - org1
[2017-10-16 11:07:11.584] [INFO] SampleWebApp - <<<<<<<<<<<<<<<<< J O I N  C H A N N E L >>>>>>>>>>>>>>>>>
// 获取到的参数
[2017-10-16 11:07:11.585] [DEBUG] SampleWebApp - channelName : mychannel
[2017-10-16 11:07:11.585] [DEBUG] SampleWebApp - peers : peer1,peer2
[2017-10-16 11:07:11.585] [INFO] Join-Channel - Calling peers in organization "org1" to join the channel
[2017-10-16 11:07:11.586] [DEBUG] Helper - [crypto_ecdsa_aes]: constructor, keySize: 256
[2017-10-16 11:07:11.586] [DEBUG] Helper - [crypto_ecdsa_aes]: Hash algorithm: SHA2, hash output size: 256
[2017-10-16 11:07:11.587] [DEBUG] Helper - [utils.CryptoKeyStore]: CryptoKeyStore, constructor - start
// 获取admin
[2017-10-16 11:07:11.587] [DEBUG] Helper - [utils.CryptoKeyStore]: constructor, no super class specified, using config: fabric-client/lib/impl/FileKeyValueStore.js
[2017-10-16 11:07:11.587] [DEBUG] Helper - [FileKeyValueStore.js]: FileKeyValueStore.js - constructor
[2017-10-16 11:07:11.588] [DEBUG] Helper - Msp ID : Org1MSP
[2017-10-16 11:07:11.588] [DEBUG] Helper - [crypto_ecdsa_aes]: importKey - start
[2017-10-16 11:07:11.590] [DEBUG] Helper - [crypto_ecdsa_aes]: importKey - have the key [Circular]
[2017-10-16 11:07:11.591] [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:11.591] [DEBUG] Helper - [FileKeyValueStore.js]: FileKeyValueStore.js - constructor
[2017-10-16 11:07:11.591] [DEBUG] Helper - [utils.CryptoKeyStore]: _getKeyStore returning ks
[2017-10-16 11:07:11.591] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param X: 0a66f3503a3322b2ca8e9dce03322d486ee6ec5970efaad3f153bc13aa2d942c
[2017-10-16 11:07:11.591] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param Y: 312ad05190fa592fb9e8ac2dcdb23c84df7f49e4ee295c2aa1200a50c9146c46
[2017-10-16 11:07:11.592] [DEBUG] Helper - [FileKeyValueStore.js]: FileKeyValueStore -- setValue
[2017-10-16 11:07:11.593] [DEBUG] Helper - [crypto_ecdsa_aes]: importKey - start
[2017-10-16 11:07:11.593] [DEBUG] Helper - [crypto_ecdsa_aes]: importKey - have the key [Circular]
[2017-10-16 11:07:11.593] [DEBUG] Helper - [utils.CryptoKeyStore]: _getKeyStore resolving store
[2017-10-16 11:07:11.594] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param X: 0a66f3503a3322b2ca8e9dce03322d486ee6ec5970efaad3f153bc13aa2d942c
[2017-10-16 11:07:11.594] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param Y: 312ad05190fa592fb9e8ac2dcdb23c84df7f49e4ee295c2aa1200a50c9146c46
[2017-10-16 11:07:11.594] [DEBUG] Helper - [FileKeyValueStore.js]: FileKeyValueStore -- setValue
[2017-10-16 11:07:11.596] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param X: 0a66f3503a3322b2ca8e9dce03322d486ee6ec5970efaad3f153bc13aa2d942c
[2017-10-16 11:07:11.596] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param Y: 312ad05190fa592fb9e8ac2dcdb23c84df7f49e4ee295c2aa1200a50c9146c46
[2017-10-16 11:07:11.596] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param X: 0a66f3503a3322b2ca8e9dce03322d486ee6ec5970efaad3f153bc13aa2d942c
[2017-10-16 11:07:11.596] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param Y: 312ad05190fa592fb9e8ac2dcdb23c84df7f49e4ee295c2aa1200a50c9146c46
[2017-10-16 11:07:11.597] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param X: 0a66f3503a3322b2ca8e9dce03322d486ee6ec5970efaad3f153bc13aa2d942c
[2017-10-16 11:07:11.597] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param Y: 312ad05190fa592fb9e8ac2dcdb23c84df7f49e4ee295c2aa1200a50c9146c46
[2017-10-16 11:07:11.597] [DEBUG] Helper - [FileKeyValueStore.js]: FileKeyValueStore -- setValue
[2017-10-16 11:07:11.600] [INFO] Join-Channel - received member object for admin of the organization "org1": 
[2017-10-16 11:07:11.604] [DEBUG] Helper - [crypto_ecdsa_aes]: ecdsa signature:  Signature {
  r: <BN: 7d10c289f1015a3597b929ec079652692dd9104fa2bda7326f8320281e33123d>,
  s: <BN: 50167788c3fc57609ab56e14ca8397bc47fffc2469fd683ddc5a51fae5190958>,
  recoveryParam: 0 }
// 设置监听事件
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:11.634] [DEBUG] Helper - [crypto_ecdsa_aes]: ecdsa signature:  Signature {
  r: <BN: e1cdeef11d37de28810bed04d525abf4ed4959899f64e7129483110b07d9ef50>,
  s: <BN: 65720ba0dfcdb959cce0a3d69b016097c7895aab1891172ded659aece90d467e>,
  recoveryParam: 1 }
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:11.643] [DEBUG] Helper - [crypto_ecdsa_aes]: ecdsa signature:  Signature {
  r: <BN: e1cdeef11d37de28810bed04d525abf4ed4959899f64e7129483110b07d9ef50>,
  s: <BN: 65720ba0dfcdb959cce0a3d69b016097c7895aab1891172ded659aece90d467e>,
  recoveryParam: 1 }
[2017-10-16 11:07:11.652] [DEBUG] Helper - [crypto_ecdsa_aes]: ecdsa signature:  Signature {
  r: <BN: ba3afad71ae6cd1889974364672ed04f15ed3ef6d5c6801ce59ce78bffe27a93>,
  s: <BN: 66b904b771bd6dda916e329e1fc8e5d25b2bae369948bde8e3d12ac3848ac8aa>,
  recoveryParam: 1 }
// 发送请求后的相应
[2017-10-16 11:07:11.957] [DEBUG] Join-Channel - Join Channel R E S P O N S E : [[{"version":0,"timestamp":null,"response":{"status":200,"message":"","payload":{"type":"Buffer","data":[]}},"payload":{"type":"Buffer","data":[]},"endorsement":null},{"version":0,"timestamp":null,"response":{"status":200,"message":"","payload":{"type":"Buffer","data":[]}},"payload":{"type":"Buffer","data":[]},"endorsement":null}],null,null]
[2017-10-16 11:07:11.957] [INFO] Join-Channel - Successfully joined peers in organization org1 to the channel 'mychannel'
[2017-10-16 11:07:11.957] [DEBUG] Join-Channel - 
//
============ Join Channel is SUCCESS ============
[2017-10-16 11:07:11.957] [DEBUG] Join-Channel - 
[2017-10-16 11:07:11.964] [DEBUG] Helper - [crypto_ecdsa_aes]: ecdsa signature:  Signature {
  r: <BN: ab6a1ea9d36c8cabc53cad8cfdf545dc0f7e7751bf43979552bb980f7fcb4b7e>,
  s: <BN: 1839adef53808d6e3ffba1f40495827cc6b4fa047d2c03dfe9ab76933581d35b>,
  recoveryParam: 1 }
[2017-10-16 11:07:11.969] [DEBUG] Helper - [crypto_ecdsa_aes]: ecdsa signature:  Signature {
  r: <BN: ab6a1ea9d36c8cabc53cad8cfdf545dc0f7e7751bf43979552bb980f7fcb4b7e>,
  s: <BN: 1839adef53808d6e3ffba1f40495827cc6b4fa047d2c03dfe9ab76933581d35b>,
  recoveryParam: 1 }
4 安装chaincode
前言
使用sdk安装chaincode时需要指定以下参数
- chaincode名称
- chaincode版本
- chaincode文件路径
在本文示例中传递的chaincode的路径为github.com/example_cc ,系统会加载gopath路径下src目录里面的github.com/example_cc下面的chaincode文件。设置gopath的操作,在具体实现里面提及到。
路由
app.js
//在指定peer上安装chaincode
app.post('/chaincodes', function(req, res) {
	//1 校验参数
	logger.debug('==================== INSTALL CHAINCODE ==================');
	var peers = req.body.peers;
	var chaincodeName = req.body.chaincodeName;
	var chaincodePath = req.body.chaincodePath;
	var chaincodeVersion = req.body.chaincodeVersion;
	//需要安装chaincode的peer
	logger.debug('peers : ' + peers); // target peers list
	//指定chaincode名称
	logger.debug('chaincodeName : ' + chaincodeName);
	//chaincode路径
	logger.debug('chaincodePath  : ' + chaincodePath);
	//chaincode版本
	logger.debug('chaincodeVersion  : ' + chaincodeVersion);
	if (!peers || peers.length == 0) {
		res.json(getErrorMessage('\'peers\''));
		return;
	}
	if (!chaincodeName) {
		res.json(getErrorMessage('\'chaincodeName\''));
		return;
	}
	if (!chaincodePath) {
		res.json(getErrorMessage('\'chaincodePath\''));
		return;
	}
	if (!chaincodeVersion) {
		res.json(getErrorMessage('\'chaincodeVersion\''));
		return;
	}
    // 2 由install-chaincode.js来具体实现
	install.installChaincode(peers, chaincodeName, chaincodePath, chaincodeVersion, req.username, req.orgname)
	.then(function(message) {
		res.send(message);
	});
});
这个路由只做了两件事
- 必要参数校验
- 调用封装好的installChaincode方法来具体实现安装chaincode
具体实现
install-chaincode.js
var path = require('path');
var fs = require('fs');
var util = require('util');
var config = require('../config.json');
var helper = require('./helper.js');
var logger = helper.getLogger('install-chaincode');
var tx_id = null;
var installChaincode = function(peers, chaincodeName, chaincodePath,
	chaincodeVersion, username, org) {
	logger.debug(
		'\n============ Install chaincode on organizations ============\n');
	//  设置gopath变量路径指向balance-transfer/artifacts/     加载chaincode使用
	helper.setupChaincodeDeploy();
	var channel = helper.getChannelForOrg(org);
	var client = helper.getClientForOrg(org);
    //1 获取该组织的admin
	return helper.getOrgAdmin(org).then((user) => {
		//2 封装request
		var request = {
			targets: helper.newPeers(peers, org), // peer对应的rpc地址
			chaincodePath: chaincodePath,
			chaincodeId: chaincodeName,
			chaincodeVersion: chaincodeVersion
		};
		//3 发送请求,安装chaincode
		return client.installChaincode(request);
	}, (err) => {
		logger.error('Failed to enroll user \'' + username + '\'. ' + err);
		throw new Error('Failed to enroll user \'' + username + '\'. ' + err);
	}).then((results) => {
		var proposalResponses = results[0];
		var proposal = results[1];
		var all_good = true;
		// 4 处理返回的结果
		for (var i in proposalResponses) {
			let one_good = false;
			if (proposalResponses && proposalResponses[i].response &&
				proposalResponses[i].response.status === 200) {
				one_good = true;
				logger.info('install proposal was good');
			} else {
				logger.error('install proposal was bad');
			}
			all_good = all_good & one_good;
		}
		// 是否都安装成功
		if (all_good) {
			logger.info(util.format(
				'Successfully sent install Proposal and received ProposalResponse: Status - %s',
				proposalResponses[0].response.status));
			logger.debug('\nSuccessfully Installed chaincode on organization ' + org +
				'\n');
			return 'Successfully Installed chaincode on organization ' + org;
		} else {
			logger.error(
				'Failed to send install Proposal or receive valid response. Response null or status is not 200. exiting...'
			);
			return 'Failed to send install Proposal or receive valid response. Response null or status is not 200. exiting...';
		}
	}, (err) => {
		logger.error('Failed to send install proposal due to error: ' + err.stack ?
			err.stack : err);
		throw new Error('Failed to send install proposal due to error: ' + err.stack ?
			err.stack : err);
	});
};
exports.installChaincode = installChaincode;
基本流程

API访问
github.com/example_cc 这个路径会从gopath环境变量中查找。
echo "POST Install chaincode on Org1"
echo
curl -s -X POST \
  http://localhost:4000/chaincodes \
  -H "authorization: Bearer $ORG1_TOKEN" \
  -H "content-type: application/json" \
  -d '{
	"peers": ["peer0.org1.example.com", "peer1.org1.example.com"],
	"chaincodeName":"mycc",
	"chaincodePath":"github.com/example_cc/go",
	"chaincodeType": "golang",
	"chaincodeVersion":"v0"
}'
echo
echo
控制台打印:
POST Install chaincode on Org1
Successfully Installed chaincode on organization org1
后台打印:
[2017-10-16 11:07:12.352] [DEBUG] SampleWebApp - Decoded from JWT token: username - Jim, orgname - org1
[2017-10-16 11:07:12.352] [DEBUG] SampleWebApp - ==================== INSTALL CHAINCODE ==================
[2017-10-16 11:07:12.352] [DEBUG] SampleWebApp - peers : peer1,peer2
[2017-10-16 11:07:12.352] [DEBUG] SampleWebApp - chaincodeName : mycc
[2017-10-16 11:07:12.353] [DEBUG] SampleWebApp - chaincodePath  : github.com/example_cc
[2017-10-16 11:07:12.353] [DEBUG] SampleWebApp - chaincodeVersion  : v0
[2017-10-16 11:07:12.353] [DEBUG] install-chaincode - 
============ Install chaincode on organizations ============
[2017-10-16 11:07:12.353] [DEBUG] Helper - [crypto_ecdsa_aes]: constructor, keySize: 256
[2017-10-16 11:07:12.354] [DEBUG] Helper - [crypto_ecdsa_aes]: Hash algorithm: SHA2, hash output size: 256
[2017-10-16 11:07:12.354] [DEBUG] Helper - [utils.CryptoKeyStore]: CryptoKeyStore, constructor - start
[2017-10-16 11:07:12.354] [DEBUG] Helper - [utils.CryptoKeyStore]: constructor, no super class specified, using config: fabric-client/lib/impl/FileKeyValueStore.js
[2017-10-16 11:07:12.354] [DEBUG] Helper - [FileKeyValueStore.js]: FileKeyValueStore.js - constructor
[2017-10-16 11:07:12.354] [DEBUG] Helper - Msp ID : Org1MSP
[2017-10-16 11:07:12.354] [DEBUG] Helper - [crypto_ecdsa_aes]: importKey - start
[2017-10-16 11:07:12.355] [DEBUG] Helper - [crypto_ecdsa_aes]: importKey - have the key [Circular]
[2017-10-16 11:07:12.355] [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.355] [DEBUG] Helper - [FileKeyValueStore.js]: FileKeyValueStore.js - constructor
[2017-10-16 11:07:12.356] [DEBUG] Helper - [utils.CryptoKeyStore]: _getKeyStore returning ks
[2017-10-16 11:07:12.356] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param X: 0a66f3503a3322b2ca8e9dce03322d486ee6ec5970efaad3f153bc13aa2d942c
[2017-10-16 11:07:12.356] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param Y: 312ad05190fa592fb9e8ac2dcdb23c84df7f49e4ee295c2aa1200a50c9146c46
[2017-10-16 11:07:12.356] [DEBUG] Helper - [FileKeyValueStore.js]: FileKeyValueStore -- setValue
[2017-10-16 11:07:12.357] [DEBUG] Helper - [crypto_ecdsa_aes]: importKey - start
[2017-10-16 11:07:12.357] [DEBUG] Helper - [crypto_ecdsa_aes]: importKey - have the key [Circular]
[2017-10-16 11:07:12.358] [DEBUG] Helper - [utils.CryptoKeyStore]: _getKeyStore resolving store
[2017-10-16 11:07:12.358] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param X: 0a66f3503a3322b2ca8e9dce03322d486ee6ec5970efaad3f153bc13aa2d942c
[2017-10-16 11:07:12.359] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param Y: 312ad05190fa592fb9e8ac2dcdb23c84df7f49e4ee295c2aa1200a50c9146c46
[2017-10-16 11:07:12.360] [DEBUG] Helper - [FileKeyValueStore.js]: FileKeyValueStore -- setValue
[2017-10-16 11:07:12.363] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param X: 0a66f3503a3322b2ca8e9dce03322d486ee6ec5970efaad3f153bc13aa2d942c
[2017-10-16 11:07:12.363] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param Y: 312ad05190fa592fb9e8ac2dcdb23c84df7f49e4ee295c2aa1200a50c9146c46
[2017-10-16 11:07:12.363] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param X: 0a66f3503a3322b2ca8e9dce03322d486ee6ec5970efaad3f153bc13aa2d942c
[2017-10-16 11:07:12.363] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param Y: 312ad05190fa592fb9e8ac2dcdb23c84df7f49e4ee295c2aa1200a50c9146c46
[2017-10-16 11:07:12.363] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param X: 0a66f3503a3322b2ca8e9dce03322d486ee6ec5970efaad3f153bc13aa2d942c
[2017-10-16 11:07:12.363] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param Y: 312ad05190fa592fb9e8ac2dcdb23c84df7f49e4ee295c2aa1200a50c9146c46
[2017-10-16 11:07:12.363] [DEBUG] Helper - [FileKeyValueStore.js]: FileKeyValueStore -- setValue
info: [packager/Golang.js]: packaging GOLANG from github.com/example_cc
[2017-10-16 11:07:12.384] [DEBUG] Helper - [crypto_ecdsa_aes]: ecdsa signature:  Signature {
  r: <BN: 98e0e079bcad1db53e72e6e001b03f8c76c50c499bc0237a1b8db341231a6341>,
  s: <BN: 23b0d0657eeaccc22def7a429c888c08a83dec55e56bc89fe34964319d6ac875>,
  recoveryParam: 1 }
[2017-10-16 11:07:12.400] [INFO] install-chaincode - install proposal was good
[2017-10-16 11:07:12.400] [INFO] install-chaincode - install proposal was good
[2017-10-16 11:07:12.401] [INFO] install-chaincode - Successfully sent install Proposal and received ProposalResponse: Status - 200
[2017-10-16 11:07:12.401] [DEBUG] install-chaincode - 
Successfully Installed chaincode on organization org1
5 初始化chaincode
前言
初始化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.
6 执行chaincode
前言
这里要实现类似转账功能,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;
基本流程

API访问
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.
7 查询chaincode
前言
第六个文章已经成功执行了转账(A->B),这次我们来查询下A账户现在有多少资产。查询最终会通过channel.queryByChaincode(request, target)来执行chaincode的query方法,我们来看下该方法的实现:
//查询账户 Query callback representing the query of a chaincode
func (t *SimpleChaincode) query(stub shim.ChaincodeStubInterface, args []string) pb.Response {
	var A string // Entities
	var err error
	if len(args) != 1 {
		return shim.Error("Incorrect number of arguments. Expecting name of the person to query")
	}
	A = args[0]
	//从账簿中获取A账户的资产
	// Get the state from the ledger
	Avalbytes, err := stub.GetState(A)
	if err != nil {
		jsonResp := "{\"Error\":\"Failed to get state for " + A + "\"}"
		return shim.Error(jsonResp)
	}
	if Avalbytes == nil {
		jsonResp := "{\"Error\":\"Nil amount for " + A + "\"}"
		return shim.Error(jsonResp)
	}
   //转换数据并返回
	jsonResp := "{\"Name\":\"" + A + "\",\"Amount\":\"" + string(Avalbytes) + "\"}"
	logger.Infof("Query Response:%s\n", jsonResp)
	return shim.Success(Avalbytes)
}
路由
app.js
//查询chaincode  Query on chaincode on target peers
app.get('/channels/:channelName/chaincodes/:chaincodeName', function(req, res) {
	logger.debug('==================== QUERY BY CHAINCODE ==================');
	//1  参数校验
	var channelName = req.params.channelName;
	var chaincodeName = req.params.chaincodeName;
	let args = req.query.args;
	let fcn = req.query.fcn;
	let peer = req.query.peer; // 指定在哪个peer节点上查询
	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;
	}
	args = args.replace(/'/g, '"');
	args = JSON.parse(args);
	logger.debug(args);
    //2 具体实现
	query.queryChaincode(peer, channelName, chaincodeName, args, fcn, req.username, req.orgname)
	.then(function(message) {
		res.send(message);
	});
});
具体实现
query.js
var queryChaincode = function(peer, channelName, chaincodeName, args, fcn, username, org) {
	var channel = helper.getChannelForOrg(org);
	var client = helper.getClientForOrg(org);
	var target = buildTarget(peer, org);
    //1  获取 jim 用户( 内部会设置为上下文环境)
	return helper.getRegisteredUsers(username, org).then((user) => {
		tx_id = client.newTransactionID();
        //2 封装查询请求
		var request = {
			chaincodeId: chaincodeName,
			txId: tx_id,
			fcn: fcn,
			args: args
		};
        //3 发送请求
		return channel.queryByChaincode(request, target);
	}, (err) => {
		logger.info('Failed to get submitter \''+username+'\'');
		return 'Failed to get submitter \''+username+'\'. Error: ' + err.stack ? err.stack :
			err;
	}).then((response_payloads) => {
        //4 处理结果
		if (response_payloads) {
			for (let i = 0; i < response_payloads.length; i++) {
				logger.info(args[0]+' now has ' + response_payloads[i].toString('utf8') +
					' after the move');
				return args[0]+' now has ' + response_payloads[i].toString('utf8') +
					' after the move';
			}
		} else {
			logger.error('response_payloads is null');
			return 'response_payloads is null';
		}
	}, (err) => {
		logger.error('Failed to send query due to error: ' + err.stack ? err.stack :
			err);
		return 'Failed to send query due to error: ' + err.stack ? err.stack : err;
	}).catch((err) => {
		logger.error('Failed to end to end test with error:' + err.stack ? err.stack :
			err);
		return 'Failed to end to end test with error:' + err.stack ? err.stack :
			err;
	});
};
基本流程

API访问
echo "GET query chaincode on peer1 of Org1"
echo
curl -s -X GET \
  "http://localhost:4000/channels/mychannel/chaincodes/mycc?peer=peer1&fcn=query&args=["a"]" \
  -H "authorization: Bearer $ORG1_TOKEN" \
  -H "content-type: application/json"
echo
echo
控制台打印:
GET query chaincode on peer1 of Org1
a now has 90 after the move
后台打印:
[2017-10-16 11:07:43.062] [DEBUG] SampleWebApp - Decoded from JWT token: username - Jim, orgname - org1
[2017-10-16 11:07:43.063] [DEBUG] SampleWebApp - ==================== QUERY BY CHAINCODE ==================
// 获取到的参数
[2017-10-16 11:07:43.063] [DEBUG] SampleWebApp - channelName : mychannel
[2017-10-16 11:07:43.063] [DEBUG] SampleWebApp - chaincodeName : mycc
[2017-10-16 11:07:43.063] [DEBUG] SampleWebApp - fcn : query
[2017-10-16 11:07:43.063] [DEBUG] SampleWebApp - args : ["a"]
[2017-10-16 11:07:43.063] [DEBUG] SampleWebApp - [ 'a' ]
//设置user  Context
[2017-10-16 11:07:43.064] [DEBUG] Helper - [FileKeyValueStore.js]: FileKeyValueStore.js - constructor
[2017-10-16 11:07:43.065] [DEBUG] Helper - [FileKeyValueStore.js]: FileKeyValueStore -- getValue
[2017-10-16 11:07:43.065] [DEBUG] Helper - [crypto_ecdsa_aes]: importKey - start
[2017-10-16 11:07:43.066] [DEBUG] Helper - [crypto_ecdsa_aes]: importKey - have the key [Circular]
[2017-10-16 11:07:43.066] [DEBUG] Helper - [utils.CryptoKeyStore]: _getKeyStore resolving store
[2017-10-16 11:07:43.066] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param X: b3e2a75b9a4fd2b081589b1c45bde49f583aea9d7d466798c7b765c4ca96973d
[2017-10-16 11:07:43.066] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param Y: c58820e5a9db75ab17841ac158e9389ad0d130a6827dc0682dcb2d2c5dccb349
[2017-10-16 11:07:43.066] [DEBUG] Helper - [FileKeyValueStore.js]: FileKeyValueStore -- setValue
[2017-10-16 11:07:43.067] [DEBUG] Helper - [utils.CryptoKeyStore]: _getKeyStore resolving store
[2017-10-16 11:07:43.067] [DEBUG] Helper - [FileKeyValueStore.js]: FileKeyValueStore -- getValue
[2017-10-16 11:07:43.067] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param X: b3e2a75b9a4fd2b081589b1c45bde49f583aea9d7d466798c7b765c4ca96973d
[2017-10-16 11:07:43.067] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param Y: c58820e5a9db75ab17841ac158e9389ad0d130a6827dc0682dcb2d2c5dccb349
[2017-10-16 11:07:43.068] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param X: b3e2a75b9a4fd2b081589b1c45bde49f583aea9d7d466798c7b765c4ca96973d
[2017-10-16 11:07:43.068] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param Y: c58820e5a9db75ab17841ac158e9389ad0d130a6827dc0682dcb2d2c5dccb349
[2017-10-16 11:07:43.068] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param X: b3e2a75b9a4fd2b081589b1c45bde49f583aea9d7d466798c7b765c4ca96973d
[2017-10-16 11:07:43.068] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param Y: c58820e5a9db75ab17841ac158e9389ad0d130a6827dc0682dcb2d2c5dccb349
[2017-10-16 11:07:43.068] [DEBUG] Helper - [FileKeyValueStore.js]: FileKeyValueStore -- setValue
[2017-10-16 11:07:43.069] [INFO] Helper - Successfully loaded member from persistence
[2017-10-16 11:07:43.074] [DEBUG] Helper - [crypto_ecdsa_aes]: ecdsa signature:  Signature {
  r: <BN: ef77aa291a7322316d81eac973dfaebbe65f1fd92680b11108b4d7614da3547d>,
  s: <BN: 2b0119915f46c53b1eabfcadf4b6cbc0a38a8f188e14ebbc1a30c3866f4f5205>,
  recoveryParam: 0 }
  //查询结果
[2017-10-16 11:07:43.084] [INFO] Query - a now has 90 after the move
8 查询指定的区块信息
前言
根据块号查询区块信息。需要如下参数:
- 哪个channel
- 哪个peer节点
- 第几个区块
示例中展示的是org1组织下的peer1节点上第一个区块的信息。
路由
app.js
//查询区块信息  Query Get Block by BlockNumber
app.get('/channels/:channelName/blocks/:blockId', function(req, res) {
	logger.debug('==================== GET BLOCK BY NUMBER ==================');
	let blockId = req.params.blockId;
	let peer = req.query.peer;
	logger.debug('channelName : ' + req.params.channelName);
	logger.debug('BlockID : ' + blockId);
	logger.debug('Peer : ' + peer);
	if (!blockId) {
		res.json(getErrorMessage('\'blockId\''));
		return;
	}
	// 具体实现
	query.getBlockByNumber(peer, blockId, req.username, req.orgname)
		.then(function(message) {
			res.send(message);
		});
});
具体实现
这个实现很简单,关键就是channel.queryBlock(parseInt(blockNumber), target)。
query.js
var getBlockByNumber = function(peer, blockNumber, username, org) {
	//1 节点地址
	var target = buildTarget(peer, org);
	//2 channel 
	var channel = helper.getChannelForOrg(org);
	//3  获取当前注册用户
	return helper.getRegisteredUsers(username, org).then((member) => {
		//4 查询区块信息
		return channel.queryBlock(parseInt(blockNumber), target);
	}, (err) => {
		logger.info('Failed to get submitter "' + username + '"');
		return 'Failed to get submitter "' + username + '". Error: ' + err.stack ?
			err.stack : err;
	}).then((response_payloads) => {
		//5 处理结果
		if (response_payloads) {
			//logger.debug(response_payloads);
			logger.debug(response_payloads);
			return response_payloads; //response_payloads.data.data[0].buffer;
		} else {
			logger.error('response_payloads is null');
			return 'response_payloads is null';
		}
	}, (err) => {
		logger.error('Failed to send query due to error: ' + err.stack ? err.stack :
			err);
		return 'Failed to send query due to error: ' + err.stack ? err.stack : err;
	}).catch((err) => {
		logger.error('Failed to query with error:' + err.stack ? err.stack : err);
		return 'Failed to query with error:' + err.stack ? err.stack : err;
	});
};
基本流程

API访问
echo "GET query Block by blockNumber"
echo
curl -s -X GET \
  "http://localhost:4000/channels/mychannel/blocks/1?peer=peer1" \
  -H "authorization: Bearer $ORG1_TOKEN" \
  -H "content-type: application/json"
echo
echo
控制台打印:
GET query Block by blockNumber
{"header":{"number":{"low":1,"high":0,"unsigned":true},"previous_hash":"d4630656e5704810b3637b25b94ce95a47d0929602b9d241e37a58176848a667","data_hash":"d3625dbc705806e98a309ae8c324e8f6d807914cabb31cb1973f60eda9bd21e1"},"data":{"data":[{"signature":{"type":"Buffer","data":[48,69,2,33,0,205,121,109,25,5,213,63,198,97,159,42,141,61,89,125,142,69,222,114,100,176,190,3,36,68,120,70,81,11,245,175,55,2,32,5,248,239,184,51,179,125,45,122,20,26,149,43,72,41,51,169,185,186,102,83,195,144,32,162,158,45,255,89,214,254,70]},"payload":{"header":{"channel_header":{"type":"ENDORSER_TRANSACTION","version":3,"timestamp":"Mon Oct 16 2017 11:07:12 GMT+0800 (CST)","channel_id":"mychannel","tx_id":"67b9645f86e5085516f86c4cdbd117614bf7b597889c5ff778e5a9aee6291b02","epoch":0,"extension":{"type":"Buffer","data":[18,6,18,4,108,115,99,99]}},"signature_header":{"creator":{"Mspid":"Org1MSP","IdBytes":"-----BEGIN CERTIFICATE-----\nMIICGTCCAb+gAwIBAgIQKKKdQSzsDoUYn/LPAuRWGTAKBggqhkjOPQQDAjBzMQsw\nCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZy\nYW5jaXNjbzEZMBcGA1UEChMQb3JnMS5leGFtcGxlLmNvbTEcMBoGA1UEAxMTY2Eu\nb3JnMS5leGFtcGxlLmNvbTAeFw0xNzA2MjMxMjMzMTlaFw0yNzA2MjExMjMzMTla\nMFsxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1T\nYW4gRnJhbmNpc2NvMR8wHQYDVQQDDBZBZG1pbkBvcmcxLmV4YW1wbGUuY29tMFkw\nEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAECmbzUDozIrLKjp3OAzItSG7m7Flw76rT\n8VO8E6otlCwxKtBRkPpZL7norC3NsjyE339J5O4pXCqhIApQyRRsRqNNMEswDgYD\nVR0PAQH/BAQDAgeAMAwGA1UdEwEB/wQCMAAwKwYDVR0jBCQwIoAgDnKSJOiz8xeE\nyKk8W4729MHJHZ5uV3xFwzFjYJ/kABEwCgYIKoZIzj0EAwIDSAAwRQIhALT02pc/\nyfE/4wUJfUBQ32GifUEh8JktAXzL/73S0rjYAiACNSp6zAQBX9SBxTOGMk4cGGAy\nCKqf8052NVUs2CvPzA==\n-----END CERTIFICATE-----\n"},"nonce":{"type":"Buffer","data":[209,157,141,55,219,50,184,51,248,42,28,75,15,107,80,10,229,77,244,240,72,74,253,220]}}},"data":{"actions":[{"header":{"creator":{"Mspid":"Org1MSP","IdBytes":"-----BEGIN CERTIFICATE-----\nMIICGTCCAb+gAwIBAgIQKKKdQSzsDoUYn/LPAuRWGTAKBggqhkjOPQQDAjBzMQsw\nCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZy\nYW5jaXNjbzEZMBcGA1UEChMQb3JnMS5leGFtcGxlLmNvbTEcMBoGA1UEAxMTY2Eu\nb3JnMS5leGFtcGxlLmNvbTAeFw0xNzA2MjMxMjMzMTlaFw0yNzA2MjExMjMzMTla\nMFsxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1T\nYW4gRnJhbmNpc2NvMR8wHQYDVQQDDBZBZG1pbkBvcmcxLmV4YW1wbGUuY29tMFkw\nEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAECmbzUDozIrLKjp3OAzItSG7m7Flw76rT\n8VO8E6otlCwxKtBRkPpZL7norC3NsjyE339J5O4pXCqhIApQyRRsRqNNMEswDgYD\nVR0PAQH/BAQDAgeAMAwGA1UdEwEB/wQCMAAwKwYDVR0jBCQwIoAgDnKSJOiz8xeE\nyKk8W4729MHJHZ5uV3xFwzFjYJ/kABEwCgYIKoZIzj0EAwIDSAAwRQIhALT02pc/\nyfE/4wUJfUBQ32GifUEh8JktAXzL/73S0rjYAiACNSp6zAQBX9SBxTOGMk4cGGAy\nCKqf8052NVUs2CvPzA==\n-----END CERTIFICATE-----\n"},"nonce":{"type":"Buffer","data":[209,157,141,55,219,50,184,51,248,42,28,75,15,107,80,10,229,77,244,240,72,74,253,220]}},"payload":{"chaincode_proposal_payload":{"input":{"type":"Buffer","data":[10,115,8,1,18,6,18,4,108,115,99,99,26,103,10,6,100,101,112,108,111,121,10,9,109,121,99,104,97,110,110,101,108,10,40,10,38,8,1,18,10,18,4,109,121,99,99,26,2,118,48,26,22,10,4,105,110,105,116,10,1,97,10,3,49,48,48,10,1,98,10,3,50,48,48,10,40,18,12,18,10,8,1,18,2,8,0,18,2,8,1,26,11,18,9,10,7,79,114,103,49,77,83,80,26,11,18,9,10,7,79,114,103,50,77,83,80]}},"action":{"proposal_response_payload":{"proposal_hash":"4e4159787b219394892fa4ec007a34c16d3aa44cdf4ded5f56bbd1e25b98a327","extension":{"results":{"data_model":0,"ns_rwset":[{"namespace":"lscc","rwset":{"reads":[{"key":"mycc","version":null}],"range_queries_info":[],"writes":[{"key":"mycc","is_delete":false,"value":"\n\u0004mycc\u0012\u0002v0\u001a\u0004escc\"\u0004vscc*(\u0012\f\u0012\n\b\u0001\u0012\u0002\b\u0000\u0012\u0002\b\u0001\u001a\u000b\u0012\t\n\u0007Org1MSP\u001a\u000b\u0012\t\n\u0007Org2MSP2D\n �����ϧ�i?v��OCjˢ��\"���Hq\u001e���Gb\u0012 *PI�w�\u000fjL5x6^�E=�)ˡF��\t\u0019\u0015��C5\u00115: ���ԣV��k����ر���\u000b>z!F�P\"�+I�B,\u0012\f\u0012\n\b\u0001\u0012\u0002\b\u0000\u0012\u0002\b\u0001\u001a\r\u0012\u000b\n\u0007Org1MSP\u0010\u0001\u001a\r\u0012\u000b\n\u0007Org2MSP\u0010\u0001"}]}},{"namespace":"mycc","rwset":{"reads":[],"range_queries_info":[],"writes":[{"key":"a","is_delete":false,"value":"100"},{"key":"b","is_delete":false,"value":"200"}]}}]},"events":{"chaincode_id":"","tx_id":"","event_name":"","payload":{"type":"Buffer","data":[]}},"response":{"status":200,"message":"","payload":"\n\u0004mycc\u0012\u0002v0\u001a\u0004escc\"\u0004vscc*(\u0012\f\u0012\n\b\u0001\u0012\u0002\b\u0000\u0012\u0002\b\u0001\u001a\u000b\u0012\t\n\u0007Org1MSP\u001a\u000b\u0012\t\n\u0007Org2MSP2D\n �����ϧ�i?v��OCjˢ��\"���Hq\u001e���Gb\u0012 *PI�w�\u000fjL5x6^�E=�)ˡF��\t\u0019\u0015��C5\u00115: ���ԣV��k����ر���\u000b>z!F�P\"�+I�B,\u0012\f\u0012\n\b\u0001\u0012\u0002\b\u0000\u0012\u0002\b\u0001\u001a\r\u0012\u000b\n\u0007Org1MSP\u0010\u0001\u001a\r\u0012\u000b\n\u0007Org2MSP\u0010\u0001"}}},"endorsements":[{"endorser":{"Mspid":"Org1MSP","IdBytes":"-----BEGIN -----\nMIICGDCCAb+gAwIBAgIQPcMFFEB/vq6mEL6vXV7aUTAKBggqhkjOPQQDAjBzMQsw\nCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZy\nYW5jaXNjbzEZMBcGA1UEChMQb3JnMS5leGFtcGxlLmNvbTEcMBoGA1UEAxMTY2Eu\nb3JnMS5leGFtcGxlLmNvbTAeFw0xNzA2MjMxMjMzMTlaFw0yNzA2MjExMjMzMTla\nMFsxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1T\nYW4gRnJhbmNpc2NvMR8wHQYDVQQDExZwZWVyMC5vcmcxLmV4YW1wbGUuY29tMFkw\nEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEzS9k2gCKHcat8Wj4T2nB1uyC8R2zg3um\nxdTL7nmgFWp0uyCCbQQxD/VS+8R/3DNvEFkvzhcjc9NU/nRqMirpLqNNMEswDgYD\nVR0PAQH/BAQDAgeAMAwGA1UdEwEB/wQCMAAwKwYDVR0jBCQwIoAgDnKSJOiz8xeE\nyKk8W4729MHJHZ5uV3xFwzFjYJ/kABEwCgYIKoZIzj0EAwIDRwAwRAIgHBdxbHUG\nrFUzKPX9UmmN3SwigWcRUREUy/GTb3hDIAsCIEF1BxTqv8ilQYE8ql0wJL4mTber\nHE6DFYvvBCUnicUh\n-----END -----\n"},"signature":{"type":"Buffer","data":[48,68,2,32,53,175,47,213,145,239,141,185,232,177,37,83,215,130,19,85,244,146,114,234,151,107,4,87,218,179,100,59,91,21,99,215,2,32,35,200,206,164,189,219,49,64,112,47,245,92,104,49,133,67,155,63,166,39,119,44,142,233,220,133,13,98,196,52,174,210]}},{"endorser":{"Mspid":"Org1MSP","IdBytes":"-----BEGIN -----\nMIICGjCCAcCgAwIBAgIRAI+BBtEBvpOqhfRZZH7eV/YwCgYIKoZIzj0EAwIwczEL\nMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNhbiBG\ncmFuY2lzY28xGTAXBgNVBAoTEG9yZzEuZXhhbXBsZS5jb20xHDAaBgNVBAMTE2Nh\nLm9yZzEuZXhhbXBsZS5jb20wHhcNMTcwNjIzMTIzMzE5WhcNMjcwNjIxMTIzMzE5\nWjBbMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMN\nU2FuIEZyYW5jaXNjbzEfMB0GA1UEAxMWcGVlcjEub3JnMS5leGFtcGxlLmNvbTBZ\nMBMGByqGSM49AgEGCCqGSM49AwEHA0IABCnT04ltvjsgiZVuCGLsRYzEiCTJZlZw\nh3HT/273B3NkWA7wrlyK7FfAanIyexuR1UI9m4+YKNqFG6cgYnf8MsejTTBLMA4G\nA1UdDwEB/wQEAwIHgDAMBgNVHRMBAf8EAjAAMCsGA1UdIwQkMCKAIA5ykiTos/MX\nhMipPFuO9vTByR2ebld8RcMxY2Cf5AARMAoGCCqGSM49BAMCA0gAMEUCIQCSRdWm\ni4IgVUajvzWVxyE/wi7n617pVqS4+nJ7gbTRjQIgefzBwS+bkNhPc3/rktySFLRC\nWMnq87KyqMLc6iRaJx0=\n-----END -----\n"},"signature":{"type":"Buffer","data":[48,68,2,32,49,202,231,101,244,203,225,202,230,130,68,144,86,215,248,29,212,45,30,53,252,235,47,97,196,34,47,54,244,61,235,138,2,32,108,206,246,139,231,118,64,222,217,72,255,122,247,140,42,179,245,0,121,247,29,144,10,85,126,108,64,239,40,210,95,55]}}]}}}]}}}]},"metadata":{"metadata":[{"value":"","signatures":[{"signature_header":{"creator":{"Mspid":"OrdererMSP","IdBytes":"-----BEGIN -----\nMIICDTCCAbOgAwIBAgIRALFafJiTFN/47AvAGfvj1ZEwCgYIKoZIzj0EAwIwaTEL\nMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNhbiBG\ncmFuY2lzY28xFDASBgNVBAoTC2V4YW1wbGUuY29tMRcwFQYDVQQDEw5jYS5leGFt\ncGxlLmNvbTAeFw0xNzA2MjMxMjMzMTlaFw0yNzA2MjExMjMzMTlaMFgxCzAJBgNV\nBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1TYW4gRnJhbmNp\nc2NvMRwwGgYDVQQDExNvcmRlcmVyLmV4YW1wbGUuY29tMFkwEwYHKoZIzj0CAQYI\nKoZIzj0DAQcDQgAEYtguLKFBLLc0VSwyPHHHNe76HH71oOXK6wun8Y/5vtMawPZ/\nWTm/vBVUWdfNlzc9eA28aXx6zBAB8iRm16EeU6NNMEswDgYDVR0PAQH/BAQDAgeA\nMAwGA1UdEwEB/wQCMAAwKwYDVR0jBCQwIoAgDUbM8OlDbBvDtuK/gM2yAsSUNgT5\nXHLuD/g50+wwBxkwCgYIKoZIzj0EAwIDSAAwRQIhANJuEGHBftrtlWgie9zgc60J\n/XVytPN/D0rPlkMV17n7AiBBbStggGBfFYcQ2LhDhcKut8nScJ2OFrt+dJSdJbod\n7A==\n-----END -----\n"},"nonce":{"type":"Buffer","data":[42,196,94,140,132,249,107,239,115,100,207,74,238,65,73,153,42,76,71,99,33,135,138,160]}},"signature":{"type":"Buffer","data":[48,68,2,32,37,118,87,237,154,168,159,238,222,217,182,188,97,70,172,216,74,24,177,18,107,78,24,11,254,90,198,6,178,16,8,246,2,32,12,197,28,86,154,195,54,13,130,206,7,201,233,127,14,90,40,255,112,90,112,86,172,78,150,121,153,145,255,183,56,254]}}]},{"value":{"index":{"low":0,"high":0,"unsigned":true}},"signatures":[{"signature_header":{"creator":{"Mspid":"OrdererMSP","IdBytes":"-----BEGIN -----\nMIICDTCCAbOgAwIBAgIRALFafJiTFN/47AvAGfvj1ZEwCgYIKoZIzj0EAwIwaTEL\nMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNhbiBG\ncmFuY2lzY28xFDASBgNVBAoTC2V4YW1wbGUuY29tMRcwFQYDVQQDEw5jYS5leGFt\ncGxlLmNvbTAeFw0xNzA2MjMxMjMzMTlaFw0yNzA2MjExMjMzMTlaMFgxCzAJBgNV\nBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1TYW4gRnJhbmNp\nc2NvMRwwGgYDVQQDExNvcmRlcmVyLmV4YW1wbGUuY29tMFkwEwYHKoZIzj0CAQYI\nKoZIzj0DAQcDQgAEYtguLKFBLLc0VSwyPHHHNe76HH71oOXK6wun8Y/5vtMawPZ/\nWTm/vBVUWdfNlzc9eA28aXx6zBAB8iRm16EeU6NNMEswDgYDVR0PAQH/BAQDAgeA\nMAwGA1UdEwEB/wQCMAAwKwYDVR0jBCQwIoAgDUbM8OlDbBvDtuK/gM2yAsSUNgT5\nXHLuD/g50+wwBxkwCgYIKoZIzj0EAwIDSAAwRQIhANJuEGHBftrtlWgie9zgc60J\n/XVytPN/D0rPlkMV17n7AiBBbStggGBfFYcQ2LhDhcKut8nScJ2OFrt+dJSdJbod\n7A==\n-----END -----\n"},"nonce":{"type":"Buffer","data":[101,237,86,161,237,72,245,90,132,37,151,195,55,93,252,137,201,244,205,55,168,50,105,215]}},"signature":{"type":"Buffer","data":[48,69,2,33,0,133,132,112,132,183,121,20,114,203,82,140,195,26,111,80,190,191,145,27,38,81,59,70,187,47,226,3,206,49,48,113,53,2,32,116,89,154,23,170,133,67,107,183,164,180,171,192,220,85,198,248,143,26,64,156,131,69,158,233,118,28,98,163,211,78,234]}}]},[0]]}}
后台打印:
[2017-10-16 11:07:43.099] [DEBUG] SampleWebApp - Decoded from JWT token: username - Jim, orgname - org1
[2017-10-16 11:07:43.100] [DEBUG] SampleWebApp - ==================== GET BLOCK BY NUMBER ==================
[2017-10-16 11:07:43.101] [DEBUG] SampleWebApp - channelName : mychannel
[2017-10-16 11:07:43.102] [DEBUG] SampleWebApp - BlockID : 1
[2017-10-16 11:07:43.102] [DEBUG] SampleWebApp - Peer : peer1
[2017-10-16 11:07:43.103] [DEBUG] Helper - [FileKeyValueStore.js]: FileKeyValueStore.js - constructor
[2017-10-16 11:07:43.104] [DEBUG] Helper - [FileKeyValueStore.js]: FileKeyValueStore -- getValue
[2017-10-16 11:07:43.104] [DEBUG] Helper - [crypto_ecdsa_aes]: importKey - start
[2017-10-16 11:07:43.105] [DEBUG] Helper - [crypto_ecdsa_aes]: importKey - have the key [Circular]
[2017-10-16 11:07:43.105] [DEBUG] Helper - [utils.CryptoKeyStore]: _getKeyStore resolving store
[2017-10-16 11:07:43.106] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param X: b3e2a75b9a4fd2b081589b1c45bde49f583aea9d7d466798c7b765c4ca96973d
[2017-10-16 11:07:43.106] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param Y: c58820e5a9db75ab17841ac158e9389ad0d130a6827dc0682dcb2d2c5dccb349
[2017-10-16 11:07:43.106] [DEBUG] Helper - [FileKeyValueStore.js]: FileKeyValueStore -- setValue
[2017-10-16 11:07:43.107] [DEBUG] Helper - [utils.CryptoKeyStore]: _getKeyStore resolving store
[2017-10-16 11:07:43.107] [DEBUG] Helper - [FileKeyValueStore.js]: FileKeyValueStore -- getValue
[2017-10-16 11:07:43.107] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param X: b3e2a75b9a4fd2b081589b1c45bde49f583aea9d7d466798c7b765c4ca96973d
[2017-10-16 11:07:43.108] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param Y: c58820e5a9db75ab17841ac158e9389ad0d130a6827dc0682dcb2d2c5dccb349
[2017-10-16 11:07:43.108] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param X: b3e2a75b9a4fd2b081589b1c45bde49f583aea9d7d466798c7b765c4ca96973d
[2017-10-16 11:07:43.109] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param Y: c58820e5a9db75ab17841ac158e9389ad0d130a6827dc0682dcb2d2c5dccb349
[2017-10-16 11:07:43.109] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param X: b3e2a75b9a4fd2b081589b1c45bde49f583aea9d7d466798c7b765c4ca96973d
[2017-10-16 11:07:43.109] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param Y: c58820e5a9db75ab17841ac158e9389ad0d130a6827dc0682dcb2d2c5dccb349
[2017-10-16 11:07:43.109] [DEBUG] Helper - [FileKeyValueStore.js]: FileKeyValueStore -- setValue
[2017-10-16 11:07:43.110] [INFO] Helper - Successfully loaded member from persistence
[2017-10-16 11:07:43.115] [DEBUG] Helper - [crypto_ecdsa_aes]: ecdsa signature:  Signature {
  r: <BN: d37de5f50783d114c4df6ae57737bfad55bf959ca90c2d04eb7eb6644ffd6de>,
  s: <BN: 4939dc43cb965a2e633487e126599412da0a8350a7aae22eb0251b35e1a7589>,
  recoveryParam: 0 }
[2017-10-16 11:07:43.126] [DEBUG] Query - { header: 
   { number: Long { low: 1, high: 0, unsigned: true },
     previous_hash: 'd4630656e5704810b3637b25b94ce95a47d0929602b9d241e37a58176848a667',
     data_hash: 'd3625dbc705806e98a309ae8c324e8f6d807914cabb31cb1973f60eda9bd21e1' },
  data: { data: [ [Object] ] },
  metadata: { metadata: [ [Object], [Object], [Object] ] } }
9 查询指定的交易信息
前言
根据交易id查询交易详细信息。需要如下参数:
- 交易id
- peer节点
- channel
我们可以复用第六篇文章中的交易ideb058850e7247ad0bc25ec57ced1cd1255666c390ca0c9300858ce6e57175221。
路由
接收指定的peer以及交易id,校验参数后传入到具体的实现中。
app.js
//根据交易id  查询交易详情 Query Get Transaction by Transaction ID
app.get('/channels/:channelName/transactions/:trxnId', function(req, res) {
	logger.debug(
		'================ GET TRANSACTION BY TRANSACTION_ID ======================'
	);
	logger.debug('channelName : ' + req.params.channelName);
	let trxnId = req.params.trxnId;
	let peer = req.query.peer;
	if (!trxnId) {
		res.json(getErrorMessage('\'trxnId\''));
		return;
	}
	// 具体实现
	query.getTransactionByID(peer, trxnId, req.username, req.orgname)
		.then(function(message) {
			res.send(message);
		});
});
具体实现
query.js
var getTransactionByID = function(peer, trxnID, username, org) {
	//1  peer节点地址
	var target = buildTarget(peer, org);
	//2 获取channel
	var channel = helper.getChannelForOrg(org);
    //3 获取注册用户
	return helper.getRegisteredUsers(username, org).then((member) => {
		//4 查询交易详情
		return channel.queryTransaction(trxnID, target);
	}, (err) => {
		logger.info('Failed to get submitter "' + username + '"');
		return 'Failed to get submitter "' + username + '". Error: ' + err.stack ?
			err.stack : err;
	}).then((response_payloads) => {
		//5 处理响应
		if (response_payloads) {
			logger.debug(response_payloads);
			return response_payloads;
		} else {
			logger.error('response_payloads is null');
			return 'response_payloads is null';
		}
	}, (err) => {
		logger.error('Failed to send query due to error: ' + err.stack ? err.stack :
			err);
		return 'Failed to send query due to error: ' + err.stack ? err.stack : err;
	}).catch((err) => {
		logger.error('Failed to query with error:' + err.stack ? err.stack : err);
		return 'Failed to query with error:' + err.stack ? err.stack : err;
	});
};
基本流程

API访问
echo "GET query Transaction by TransactionID"
echo
curl -s -X GET http://localhost:4000/channels/mychannel/transactions/eb058850e7247ad0bc25ec57ced1cd1255666c390ca0c9300858ce6e57175221?peer=peer1 \
  -H "authorization: Bearer $ORG1_TOKEN" \
  -H "content-type: application/json"
echo
echo
控制台打印:
GET query Transaction by TransactionID
{"validationCode":0,"transactionEnvelope":{"signature":{"type":"Buffer","data":[48,69,2,33,0,177,26,37,152,112,224,187,240,114,88,79,53,58,177,81,95,71,89,200,84,235,71,91,237,204,186,56,181,195,98,164,215,2,32,102,121,110,5,234,233,1,94,99,238,162,8,112,138,154,142,145,133,56,33,199,34,26,132,60,75,208,125,235,250,233,124]},"payload":{"header":{"channel_header":{"type":"ENDORSER_TRANSACTION","version":3,"timestamp":"Mon Oct 16 2017 11:07:40 GMT+0800 (CST)","channel_id":"mychannel","tx_id":"eb058850e7247ad0bc25ec57ced1cd1255666c390ca0c9300858ce6e57175221","epoch":0,"extension":{"type":"Buffer","data":[18,6,18,4,109,121,99,99]}},"signature_header":{"creator":{"Mspid":"Org1MSP","IdBytes":"-----BEGIN CERTIFICATE-----\nMIIB7zCCAZWgAwIBAgIUTQ2LENWmI4cRoknmGQFqZ6a+8uswCgYIKoZIzj0EAwIw\nczELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNh\nbiBGcmFuY2lzY28xGTAXBgNVBAoTEG9yZzEuZXhhbXBsZS5jb20xHDAaBgNVBAMT\nE2NhLm9yZzEuZXhhbXBsZS5jb20wHhcNMTcxMDE2MDMwMjAwWhcNMTgxMDE2MDMw\nMjAwWjAOMQwwCgYDVQQDEwNKaW0wWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAASz\n4qdbmk/SsIFYmxxFveSfWDrqnX1GZ5jHt2XEypaXPcWIIOWp23WrF4QawVjpOJrQ\n0TCmgn3AaC3LLSxdzLNJo2wwajAOBgNVHQ8BAf8EBAMCB4AwDAYDVR0TAQH/BAIw\nADAdBgNVHQ4EFgQU42nR4T+yFtzFUcCWx06codR4rU8wKwYDVR0jBCQwIoAgDnKS\nJOiz8xeEyKk8W4729MHJHZ5uV3xFwzFjYJ/kABEwCgYIKoZIzj0EAwIDSAAwRQIh\nANpJucU0QfIApR7BrR2wzqU22Oq1Mv2slupaSSEhqUcuAiAK0iN+dkb8qsJPbUHp\nsX26SgxX8YIiKWpL0t+OYEqjsw==\n-----END CERTIFICATE-----\n"},"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]}}},"data":{"actions":[{"header":{"creator":{"Mspid":"Org1MSP","IdBytes":"-----BEGIN CERTIFICATE-----\nMIIB7zCCAZWgAwIBAgIUTQ2LENWmI4cRoknmGQFqZ6a+8uswCgYIKoZIzj0EAwIw\nczELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNh\nbiBGcmFuY2lzY28xGTAXBgNVBAoTEG9yZzEuZXhhbXBsZS5jb20xHDAaBgNVBAMT\nE2NhLm9yZzEuZXhhbXBsZS5jb20wHhcNMTcxMDE2MDMwMjAwWhcNMTgxMDE2MDMw\nMjAwWjAOMQwwCgYDVQQDEwNKaW0wWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAASz\n4qdbmk/SsIFYmxxFveSfWDrqnX1GZ5jHt2XEypaXPcWIIOWp23WrF4QawVjpOJrQ\n0TCmgn3AaC3LLSxdzLNJo2wwajAOBgNVHQ8BAf8EBAMCB4AwDAYDVR0TAQH/BAIw\nADAdBgNVHQ4EFgQU42nR4T+yFtzFUcCWx06codR4rU8wKwYDVR0jBCQwIoAgDnKS\nJOiz8xeEyKk8W4729MHJHZ5uV3xFwzFjYJ/kABEwCgYIKoZIzj0EAwIDSAAwRQIh\nANpJucU0QfIApR7BrR2wzqU22Oq1Mv2slupaSSEhqUcuAiAK0iN+dkb8qsJPbUHp\nsX26SgxX8YIiKWpL0t+OYEqjsw==\n-----END CERTIFICATE-----\n"},"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]}},"payload":{"chaincode_proposal_payload":{"input":{"type":"Buffer","data":[10,28,8,1,18,6,18,4,109,121,99,99,26,16,10,4,109,111,118,101,10,1,97,10,1,98,10,2,49,48]}},"action":{"proposal_response_payload":{"proposal_hash":"36c833a60246db1941e7c403e1e3d3cf2f240bdc40c210da80278d463fb094c6","extension":{"results":{"data_model":0,"ns_rwset":[{"namespace":"lscc","rwset":{"reads":[{"key":"mycc","version":{"block_num":{"low":1,"high":0,"unsigned":true},"tx_num":{"low":0,"high":0,"unsigned":true}}}],"range_queries_info":[],"writes":[]}},{"namespace":"mycc","rwset":{"reads":[{"key":"a","version":{"block_num":{"low":1,"high":0,"unsigned":true},"tx_num":{"low":0,"high":0,"unsigned":true}}},{"key":"b","version":{"block_num":{"low":1,"high":0,"unsigned":true},"tx_num":{"low":0,"high":0,"unsigned":true}}}],"range_queries_info":[],"writes":[{"key":"a","is_delete":false,"value":"90"},{"key":"b","is_delete":false,"value":"210"}]}}]},"events":{"chaincode_id":"","tx_id":"","event_name":"","payload":{"type":"Buffer","data":[]}},"response":{"status":200,"message":"","payload":""}}},"endorsements":[{"endorser":{"Mspid":"Org1MSP","IdBytes":"-----BEGIN -----\nMIICGDCCAb+gAwIBAgIQPcMFFEB/vq6mEL6vXV7aUTAKBggqhkjOPQQDAjBzMQsw\nCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2FuIEZy\nYW5jaXNjbzEZMBcGA1UEChMQb3JnMS5leGFtcGxlLmNvbTEcMBoGA1UEAxMTY2Eu\nb3JnMS5leGFtcGxlLmNvbTAeFw0xNzA2MjMxMjMzMTlaFw0yNzA2MjExMjMzMTla\nMFsxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1T\nYW4gRnJhbmNpc2NvMR8wHQYDVQQDExZwZWVyMC5vcmcxLmV4YW1wbGUuY29tMFkw\nEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEzS9k2gCKHcat8Wj4T2nB1uyC8R2zg3um\nxdTL7nmgFWp0uyCCbQQxD/VS+8R/3DNvEFkvzhcjc9NU/nRqMirpLqNNMEswDgYD\nVR0PAQH/BAQDAgeAMAwGA1UdEwEB/wQCMAAwKwYDVR0jBCQwIoAgDnKSJOiz8xeE\nyKk8W4729MHJHZ5uV3xFwzFjYJ/kABEwCgYIKoZIzj0EAwIDRwAwRAIgHBdxbHUG\nrFUzKPX9UmmN3SwigWcRUREUy/GTb3hDIAsCIEF1BxTqv8ilQYE8ql0wJL4mTber\nHE6DFYvvBCUnicUh\n-----END -----\n"},"signature":{"type":"Buffer","data":[48,68,2,32,63,184,99,69,87,244,62,157,237,78,167,227,25,195,112,215,214,197,244,114,183,91,98,30,135,103,97,82,53,102,214,64,2,32,96,34,207,210,245,68,136,213,125,235,146,198,246,248,179,48,130,115,48,159,54,172,212,58,1,142,37,211,118,47,195,173]}},{"endorser":{"Mspid":"Org1MSP","IdBytes":"-----BEGIN -----\nMIICGjCCAcCgAwIBAgIRAI+BBtEBvpOqhfRZZH7eV/YwCgYIKoZIzj0EAwIwczEL\nMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNhbiBG\ncmFuY2lzY28xGTAXBgNVBAoTEG9yZzEuZXhhbXBsZS5jb20xHDAaBgNVBAMTE2Nh\nLm9yZzEuZXhhbXBsZS5jb20wHhcNMTcwNjIzMTIzMzE5WhcNMjcwNjIxMTIzMzE5\nWjBbMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMN\nU2FuIEZyYW5jaXNjbzEfMB0GA1UEAxMWcGVlcjEub3JnMS5leGFtcGxlLmNvbTBZ\nMBMGByqGSM49AgEGCCqGSM49AwEHA0IABCnT04ltvjsgiZVuCGLsRYzEiCTJZlZw\nh3HT/273B3NkWA7wrlyK7FfAanIyexuR1UI9m4+YKNqFG6cgYnf8MsejTTBLMA4G\nA1UdDwEB/wQEAwIHgDAMBgNVHRMBAf8EAjAAMCsGA1UdIwQkMCKAIA5ykiTos/MX\nhMipPFuO9vTByR2ebld8RcMxY2Cf5AARMAoGCCqGSM49BAMCA0gAMEUCIQCSRdWm\ni4IgVUajvzWVxyE/wi7n617pVqS4+nJ7gbTRjQIgefzBwS+bkNhPc3/rktySFLRC\nWMnq87KyqMLc6iRaJx0=\n-----END -----\n"},"signature":{"type":"Buffer","data":[48,68,2,32,76,217,173,123,31,20,202,218,178,182,34,209,106,247,120,120,18,17,185,185,79,107,181,134,40,40,117,89,215,41,176,186,2,32,1,76,239,78,145,183,212,170,26,111,86,80,140,178,212,198,166,201,33,28,86,181,198,25,15,79,227,97,43,56,101,216]}}]}}}]}}}}
后台打印:
[2017-10-16 11:07:43.140] [DEBUG] SampleWebApp - Decoded from JWT token: username - Jim, orgname - org1
[2017-10-16 11:07:43.140] [DEBUG] SampleWebApp - ================ GET TRANSACTION BY TRANSACTION_ID ======================
[2017-10-16 11:07:43.141] [DEBUG] SampleWebApp - channelName : mychannel
[2017-10-16 11:07:43.142] [DEBUG] Helper - [FileKeyValueStore.js]: FileKeyValueStore.js - constructor
[2017-10-16 11:07:43.144] [DEBUG] Helper - [FileKeyValueStore.js]: FileKeyValueStore -- getValue
[2017-10-16 11:07:43.145] [DEBUG] Helper - [crypto_ecdsa_aes]: importKey - start
[2017-10-16 11:07:43.146] [DEBUG] Helper - [crypto_ecdsa_aes]: importKey - have the key [Circular]
[2017-10-16 11:07:43.146] [DEBUG] Helper - [utils.CryptoKeyStore]: _getKeyStore resolving store
[2017-10-16 11:07:43.146] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param X: b3e2a75b9a4fd2b081589b1c45bde49f583aea9d7d466798c7b765c4ca96973d
[2017-10-16 11:07:43.146] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param Y: c58820e5a9db75ab17841ac158e9389ad0d130a6827dc0682dcb2d2c5dccb349
[2017-10-16 11:07:43.146] [DEBUG] Helper - [FileKeyValueStore.js]: FileKeyValueStore -- setValue
[2017-10-16 11:07:43.147] [DEBUG] Helper - [utils.CryptoKeyStore]: _getKeyStore resolving store
[2017-10-16 11:07:43.147] [DEBUG] Helper - [FileKeyValueStore.js]: FileKeyValueStore -- getValue
[2017-10-16 11:07:43.147] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param X: b3e2a75b9a4fd2b081589b1c45bde49f583aea9d7d466798c7b765c4ca96973d
[2017-10-16 11:07:43.147] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param Y: c58820e5a9db75ab17841ac158e9389ad0d130a6827dc0682dcb2d2c5dccb349
[2017-10-16 11:07:43.148] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param X: b3e2a75b9a4fd2b081589b1c45bde49f583aea9d7d466798c7b765c4ca96973d
[2017-10-16 11:07:43.148] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param Y: c58820e5a9db75ab17841ac158e9389ad0d130a6827dc0682dcb2d2c5dccb349
[2017-10-16 11:07:43.148] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param X: b3e2a75b9a4fd2b081589b1c45bde49f583aea9d7d466798c7b765c4ca96973d
[2017-10-16 11:07:43.148] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param Y: c58820e5a9db75ab17841ac158e9389ad0d130a6827dc0682dcb2d2c5dccb349
[2017-10-16 11:07:43.148] [DEBUG] Helper - [FileKeyValueStore.js]: FileKeyValueStore -- setValue
[2017-10-16 11:07:43.148] [INFO] Helper - Successfully loaded member from persistence
[2017-10-16 11:07:43.155] [DEBUG] Helper - [crypto_ecdsa_aes]: ecdsa signature:  Signature {
  r: <BN: 6d0ae79a06d8b5d9d593d8a22f9667e41ef41d7005f635e071d61730e4519868>,
  s: <BN: 2aa650cffd0dcf227f76add8a490a94eae4717a572576e2f56105d58cb21d292>,
  recoveryParam: 1 }
[2017-10-16 11:07:43.167] [DEBUG] Query - { validationCode: 0,
  transactionEnvelope: 
   { signature: <Buffer 30 45 02 21 00 b1 1a 25 98 70 e0 bb f0 72 58 4f 35 3a b1 51 5f 47 59 c8 54 eb 47 5b ed cc ba 38 b5 c3 62 a4 d7 02 20 66 79 6e 05 ea e9 01 5e 63 ee a2 ... >,
     payload: { header: [Object], data: [Object] } } }
10 查询链信息
前言
查询链信息。需要如下参数:
- peer节点
- channel
channel是fabric重要的特性,一个peer加入了几个channel中,那么peer节点就维护几个链的信息。不属于这个channel的peer获取不到该channel内的链信息。这个类似于qq群。
这个示例是展示的mychannel的链信息。
路由
app.js
//查询链信息  Query for Channel Information
app.get('/channels/:channelName', function(req, res) {
	logger.debug(
		'================ GET CHANNEL INFORMATION ======================');
	logger.debug('channelName : ' + req.params.channelName);
	let peer = req.query.peer;
	query.getChainInfo(peer, req.username, req.orgname).then(
		function(message) {
			res.send(message);
		});
});
具体实现
query.js
var getChainInfo = function(peer, username, org) {
    //  peer节点地址
    var target = buildTarget(peer, org);
    // 获取channel
    var channel = helper.getChannelForOrg(org);
    //获取注册用户
	return helper.getRegisteredUsers(username, org).then((member) => {
        //查询链详情
		return channel.queryInfo(target);
	}, (err) => {
		logger.info('Failed to get submitter "' + username + '"');
		return 'Failed to get submitter "' + username + '". Error: ' + err.stack ?
			err.stack : err;
	}).then((blockchainInfo) => {
		// 打印信息
		if (blockchainInfo) {			
			logger.debug('===========================================');
			logger.debug(blockchainInfo.currentBlockHash);
			logger.debug('===========================================');
			//logger.debug(blockchainInfo);
			return blockchainInfo;
		} else {
			logger.error('response_payloads is null');
			return 'response_payloads is null';
		}
	}, (err) => {
		logger.error('Failed to send query due to error: ' + err.stack ? err.stack :
			err);
		return 'Failed to send query due to error: ' + err.stack ? err.stack : err;
	}).catch((err) => {
		logger.error('Failed to query with error:' + err.stack ? err.stack : err);
		return 'Failed to query with error:' + err.stack ? err.stack : err;
	});
};
基本流程

API访问
echo "GET query ChainInfo"
echo
curl -s -X GET \
  "http://localhost:4000/channels/mychannel?peer=peer1" \
  -H "authorization: Bearer $ORG1_TOKEN" \
  -H "content-type: application/json"
echo
echo
控制台打印:
GET query ChainInfo
{"height":{"low":3,"high":0,"unsigned":true},"currentBlockHash":{"buffer":{"type":"Buffer","data":[8,3,18,32,163,148,207,219,172,100,216,50,0,14,18,240,253,118,10,33,155,0,195,60,214,175,29,159,16,220,140,111,52,191,57,88,26,32,58,119,237,8,196,95,11,249,0,137,153,78,78,255,51,23,180,39,52,42,188,123,150,38,169,155,111,170,90,53,202,228]},"offset":4,"markedOffset":-1,"limit":36,"littleEndian":true,"noAssert":false},"previousBlockHash":{"buffer":{"type":"Buffer","data":[8,3,18,32,163,148,207,219,172,100,216,50,0,14,18,240,253,118,10,33,155,0,195,60,214,175,29,159,16,220,140,111,52,191,57,88,26,32,58,119,237,8,196,95,11,249,0,137,153,78,78,255,51,23,180,39,52,42,188,123,150,38,169,155,111,170,90,53,202,228]},"offset":38,"markedOffset":-1,"limit":70,"littleEndian":true,"noAssert":false}}
后台打印:
[2017-10-16 11:07:43.140] [DEBUG] SampleWebApp - Decoded from JWT token: username - Jim, orgname - org1
[2017-10-16 11:07:43.140] [DEBUG] SampleWebApp - ================ GET TRANSACTION BY TRANSACTION_ID ======================
[2017-10-16 11:07:43.141] [DEBUG] SampleWebApp - channelName : mychannel
[2017-10-16 11:07:43.142] [DEBUG] Helper - [FileKeyValueStore.js]: FileKeyValueStore.js - constructor
[2017-10-16 11:07:43.144] [DEBUG] Helper - [FileKeyValueStore.js]: FileKeyValueStore -- getValue
[2017-10-16 11:07:43.145] [DEBUG] Helper - [crypto_ecdsa_aes]: importKey - start
[2017-10-16 11:07:43.146] [DEBUG] Helper - [crypto_ecdsa_aes]: importKey - have the key [Circular]
[2017-10-16 11:07:43.146] [DEBUG] Helper - [utils.CryptoKeyStore]: _getKeyStore resolving store
[2017-10-16 11:07:43.146] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param X: b3e2a75b9a4fd2b081589b1c45bde49f583aea9d7d466798c7b765c4ca96973d
[2017-10-16 11:07:43.146] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param Y: c58820e5a9db75ab17841ac158e9389ad0d130a6827dc0682dcb2d2c5dccb349
[2017-10-16 11:07:43.146] [DEBUG] Helper - [FileKeyValueStore.js]: FileKeyValueStore -- setValue
[2017-10-16 11:07:43.147] [DEBUG] Helper - [utils.CryptoKeyStore]: _getKeyStore resolving store
[2017-10-16 11:07:43.147] [DEBUG] Helper - [FileKeyValueStore.js]: FileKeyValueStore -- getValue
[2017-10-16 11:07:43.147] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param X: b3e2a75b9a4fd2b081589b1c45bde49f583aea9d7d466798c7b765c4ca96973d
[2017-10-16 11:07:43.147] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param Y: c58820e5a9db75ab17841ac158e9389ad0d130a6827dc0682dcb2d2c5dccb349
[2017-10-16 11:07:43.148] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param X: b3e2a75b9a4fd2b081589b1c45bde49f583aea9d7d466798c7b765c4ca96973d
[2017-10-16 11:07:43.148] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param Y: c58820e5a9db75ab17841ac158e9389ad0d130a6827dc0682dcb2d2c5dccb349
[2017-10-16 11:07:43.148] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param X: b3e2a75b9a4fd2b081589b1c45bde49f583aea9d7d466798c7b765c4ca96973d
[2017-10-16 11:07:43.148] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param Y: c58820e5a9db75ab17841ac158e9389ad0d130a6827dc0682dcb2d2c5dccb349
[2017-10-16 11:07:43.148] [DEBUG] Helper - [FileKeyValueStore.js]: FileKeyValueStore -- setValue
[2017-10-16 11:07:43.148] [INFO] Helper - Successfully loaded member from persistence
[2017-10-16 11:07:43.155] [DEBUG] Helper - [crypto_ecdsa_aes]: ecdsa signature:  Signature {
  r: <BN: 6d0ae79a06d8b5d9d593d8a22f9667e41ef41d7005f635e071d61730e4519868>,
  s: <BN: 2aa650cffd0dcf227f76add8a490a94eae4717a572576e2f56105d58cb21d292>,
  recoveryParam: 1 }
[2017-10-16 11:07:43.167] [DEBUG] Query - { validationCode: 0,
  transactionEnvelope: 
   { signature: <Buffer 30 45 02 21 00 b1 1a 25 98 70 e0 bb f0 72 58 4f 35 3a b1 51 5f 47 59 c8 54 eb 47 5b ed cc ba 38 b5 c3 62 a4 d7 02 20 66 79 6e 05 ea e9 01 5e 63 ee a2 ... >,
     payload: { header: [Object], data: [Object] } } }[2017-10-16 11:07:43.180] [DEBUG] SampleWebApp - Decoded from JWT token: username - Jim, orgname - org1
[2017-10-16 11:07:43.180] [DEBUG] SampleWebApp - ================ GET CHANNEL INFORMATION ======================
[2017-10-16 11:07:43.180] [DEBUG] SampleWebApp - channelName : mychannel
[2017-10-16 11:07:43.181] [DEBUG] Helper - [FileKeyValueStore.js]: FileKeyValueStore.js - constructor
[2017-10-16 11:07:43.182] [DEBUG] Helper - [FileKeyValueStore.js]: FileKeyValueStore -- getValue
[2017-10-16 11:07:43.184] [DEBUG] Helper - [crypto_ecdsa_aes]: importKey - start
[2017-10-16 11:07:43.185] [DEBUG] Helper - [crypto_ecdsa_aes]: importKey - have the key [Circular]
[2017-10-16 11:07:43.185] [DEBUG] Helper - [utils.CryptoKeyStore]: _getKeyStore resolving store
[2017-10-16 11:07:43.186] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param X: b3e2a75b9a4fd2b081589b1c45bde49f583aea9d7d466798c7b765c4ca96973d
[2017-10-16 11:07:43.186] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param Y: c58820e5a9db75ab17841ac158e9389ad0d130a6827dc0682dcb2d2c5dccb349
[2017-10-16 11:07:43.186] [DEBUG] Helper - [FileKeyValueStore.js]: FileKeyValueStore -- setValue
[2017-10-16 11:07:43.187] [DEBUG] Helper - [utils.CryptoKeyStore]: _getKeyStore resolving store
[2017-10-16 11:07:43.187] [DEBUG] Helper - [FileKeyValueStore.js]: FileKeyValueStore -- getValue
[2017-10-16 11:07:43.189] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param X: b3e2a75b9a4fd2b081589b1c45bde49f583aea9d7d466798c7b765c4ca96973d
[2017-10-16 11:07:43.189] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param Y: c58820e5a9db75ab17841ac158e9389ad0d130a6827dc0682dcb2d2c5dccb349
[2017-10-16 11:07:43.190] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param X: b3e2a75b9a4fd2b081589b1c45bde49f583aea9d7d466798c7b765c4ca96973d
[2017-10-16 11:07:43.190] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param Y: c58820e5a9db75ab17841ac158e9389ad0d130a6827dc0682dcb2d2c5dccb349
[2017-10-16 11:07:43.190] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param X: b3e2a75b9a4fd2b081589b1c45bde49f583aea9d7d466798c7b765c4ca96973d
[2017-10-16 11:07:43.191] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param Y: c58820e5a9db75ab17841ac158e9389ad0d130a6827dc0682dcb2d2c5dccb349
[2017-10-16 11:07:43.191] [DEBUG] Helper - [FileKeyValueStore.js]: FileKeyValueStore -- setValue
[2017-10-16 11:07:43.192] [INFO] Helper - Successfully loaded member from persistence
[2017-10-16 11:07:43.197] [DEBUG] Helper - [crypto_ecdsa_aes]: ecdsa signature:  Signature {
  r: <BN: 54b9f607de6ce70a481f5addc019254444542641dba18c69eedb4f8e95753b26>,
  s: <BN: 58c66685d958ccb6c99cf1556efc24353e1c8545a4b6ac2f8aa0fa1e75dca7af>,
  recoveryParam: 0 }
[2017-10-16 11:07:43.207] [DEBUG] Query - ===========================================
[2017-10-16 11:07:43.207] [DEBUG] Query - ByteBuffer {
  buffer: <Buffer 08 03 12 20 a3 94 cf db ac 64 d8 32 00 0e 12 f0 fd 76 0a 21 9b 00 c3 3c d6 af 1d 9f 10 dc 8c 6f 34 bf 39 58 1a 20 3a 77 ed 08 c4 5f 0b f9 00 89 99 4e ... >,
  offset: 4,
  markedOffset: -1,
  limit: 36,
  littleEndian: true,
  noAssert: false }
11 查询已经安装/实例化的chaincode
前言
查询节点上的chaincode信息。需要如下参数:
- peer节点
这里展示下org1下的peer1节点已经安装的chaincode信息。
路由
app.js
//查询chaincode信息 Query to fetch all Installed/instantiated chaincodes
app.get('/chaincodes', function(req, res) {
	var peer = req.query.peer;
	var installType = req.query.type;
	// 这个api是根据installType(installed / instantiated)来区分查找的是哪类chaincode
	if (installType === 'installed') {
		logger.debug(
			'================ GET INSTALLED CHAINCODES ======================');
	} else {
		logger.debug(
			'================ GET INSTANTIATED CHAINCODES ======================');
	}
    //具体实现 
	query.getInstalledChaincodes(peer, installType, req.username, req.orgname)
	.then(function(message) {
		res.send(message);
	});
});
具体实现
query.js
var getInstalledChaincodes = function(peer, type, username, org) {
	// peer地址
	var target = buildTarget(peer, org);
	// channel实例
	var channel = helper.getChannelForOrg(org);
	//client实例
	var client = helper.getClientForOrg(org);
	return helper.getOrgAdmin(org).then((member) => {
		//关键是API的调用
		if (type === 'installed') {
			return client.queryInstalledChaincodes(target);
		} else {
			return channel.queryInstantiatedChaincodes(target);
		}
	}, (err) => {
		logger.info('Failed to get submitter "' + username + '"');
		return 'Failed to get submitter "' + username + '". Error: ' + err.stack ?
			err.stack : err;
	}).then((response) => {
		if (response) {
			// 根据类型 区分打印结果
			if (type === 'installed') {
				logger.debug('<<< Installed Chaincodes >>>');
			} else {
				logger.debug('<<< Instantiated Chaincodes >>>');
			}
			var details = [];
			for (let i = 0; i < response.chaincodes.length; i++) {
				logger.debug('name: ' + response.chaincodes[i].name + ', version: ' +
					response.chaincodes[i].version + ', path: ' + response.chaincodes[i].path
				);
				details.push('name: ' + response.chaincodes[i].name + ', version: ' +
					response.chaincodes[i].version + ', path: ' + response.chaincodes[i].path
				);
			}
			return details;
		} else {
			logger.error('response is null');
			return 'response is null';
		}
	}, (err) => {
		logger.error('Failed to send query due to error: ' + err.stack ? err.stack :
			err);
		return 'Failed to send query due to error: ' + err.stack ? err.stack : err;
	}).catch((err) => {
		logger.error('Failed to query with error:' + err.stack ? err.stack : err);
		return 'Failed to query with error:' + err.stack ? err.stack : err;
	});
};
基本流程

API访问
echo "GET query Installed chaincodes"
echo
curl -s -X GET \
  "http://localhost:4000/chaincodes?peer=peer1&type=installed" \
  -H "authorization: Bearer $ORG1_TOKEN" \
  -H "content-type: application/json"
echo
echo
控制台打印:
GET query Installed chaincodes
["name: mycc, version: v0, path: github.com/example_cc"]
后台打印:
[2017-10-16 11:07:43.140] [DEBUG] SampleWebApp - Decoded from JWT token: username - Jim, orgname - org1
[2017-10-16 11:07:43.140] [DEBUG] SampleWebApp - ================ GET TRANSACTION BY TRANSACTION_ID ======================
[2017-10-16 11:07:43.141] [DEBUG] SampleWebApp - channelName : mychannel
[2017-10-16 11:07:43.142] [DEBUG] Helper - [FileKeyValueStore.js]: FileKeyValueStore.js - constructor
[2017-10-16 11:07:43.144] [DEBUG] Helper - [FileKeyValueStore.js]: FileKeyValueStore -- getValue
[2017-10-16 11:07:43.145] [DEBUG] Helper - [crypto_ecdsa_aes]: importKey - start
[2017-10-16 11:07:43.146] [DEBUG] Helper - [crypto_ecdsa_aes]: importKey - have the key [Circular]
[2017-10-16 11:07:43.146] [DEBUG] Helper - [utils.CryptoKeyStore]: _getKeyStore resolving store
[2017-10-16 11:07:43.146] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param X: b3e2a75b9a4fd2b081589b1c45bde49f583aea9d7d466798c7b765c4ca96973d
[2017-10-16 11:07:43.146] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param Y: c58820e5a9db75ab17841ac158e9389ad0d130a6827dc0682dcb2d2c5dccb349
[2017-10-16 11:07:43.146] [DEBUG] Helper - [FileKeyValueStore.js]: FileKeyValueStore -- setValue
[2017-10-16 11:07:43.147] [DEBUG] Helper - [utils.CryptoKeyStore]: _getKeyStore resolving store
[2017-10-16 11:07:43.147] [DEBUG] Helper - [FileKeyValueStore.js]: FileKeyValueStore -- getValue
[2017-10-16 11:07:43.147] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param X: b3e2a75b9a4fd2b081589b1c45bde49f583aea9d7d466798c7b765c4ca96973d
[2017-10-16 11:07:43.147] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param Y: c58820e5a9db75ab17841ac158e9389ad0d130a6827dc0682dcb2d2c5dccb349
[2017-10-16 11:07:43.148] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param X: b3e2a75b9a4fd2b081589b1c45bde49f583aea9d7d466798c7b765c4ca96973d
[2017-10-16 11:07:43.148] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param Y: c58820e5a9db75ab17841ac158e9389ad0d130a6827dc0682dcb2d2c5dccb349
[2017-10-16 11:07:43.148] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param X: b3e2a75b9a4fd2b081589b1c45bde49f583aea9d7d466798c7b765c4ca96973d
[2017-10-16 11:07:43.148] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param Y: c58820e5a9db75ab17841ac158e9389ad0d130a6827dc0682dcb2d2c5dccb349
[2017-10-16 11:07:43.148] [DEBUG] Helper - [FileKeyValueStore.js]: FileKeyValueStore -- setValue
[2017-10-16 11:07:43.148] [INFO] Helper - Successfully loaded member from persistence
[2017-10-16 11:07:43.155] [DEBUG] Helper - [crypto_ecdsa_aes]: ecdsa signature:  Signature {
  r: <BN: 6d0ae79a06d8b5d9d593d8a22f9667e41ef41d7005f635e071d61730e4519868>,
  s: <BN: 2aa650cffd0dcf227f76add8a490a94eae4717a572576e2f56105d58cb21d292>,
  recoveryParam: 1 }
[2017-10-16 11:07:43.167] [DEBUG] Query - { validationCode: 0,
  transactionEnvelope: 
   { signature: <Buffer 30 45 02 21 00 b1 1a 25 98 70 e0 bb f0 72 58 4f 35 3a b1 51 5f 47 59 c8 54 eb 47 5b ed cc ba 38 b5 c3 62 a4 d7 02 20 66 79 6e 05 ea e9 01 5e 63 ee a2 ... >,
     payload: { header: [Object], data: [Object] } } }[2017-10-16 11:07:43.180] [DEBUG] SampleWebApp - Decoded from JWT token: username - Jim, orgname - org1
[2017-10-16 11:07:43.180] [DEBUG] SampleWebApp - ================ GET CHANNEL INFORMATION ======================
[2017-10-16 11:07:43.180] [DEBUG] SampleWebApp - channelName : mychannel
[2017-10-16 11:07:43.181] [DEBUG] Helper - [FileKeyValueStore.js]: FileKeyValueStore.js - constructor
[2017-10-16 11:07:43.182] [DEBUG] Helper - [FileKeyValueStore.js]: FileKeyValueStore -- getValue
[2017-10-16 11:07:43.184] [DEBUG] Helper - [crypto_ecdsa_aes]: importKey - start
[2017-10-16 11:07:43.185] [DEBUG] Helper - [crypto_ecdsa_aes]: importKey - have the key [Circular]
[2017-10-16 11:07:43.185] [DEBUG] Helper - [utils.CryptoKeyStore]: _getKeyStore resolving store
[2017-10-16 11:07:43.186] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param X: b3e2a75b9a4fd2b081589b1c45bde49f583aea9d7d466798c7b765c4ca96973d
[2017-10-16 11:07:43.186] [DEBUG] Helper [2017-10-16 11:07:43.219] [DEBUG] SampleWebApp - Decoded from JWT token: username - Jim, orgname - org1
[2017-10-16 11:07:43.220] [DEBUG] SampleWebApp - ================ GET INSTALLED CHAINCODES ======================
[2017-10-16 11:07:43.222] [DEBUG] Helper - [crypto_ecdsa_aes]: constructor, keySize: 256
[2017-10-16 11:07:43.222] [DEBUG] Helper - [crypto_ecdsa_aes]: Hash algorithm: SHA2, hash output size: 256
[2017-10-16 11:07:43.223] [DEBUG] Helper - [utils.CryptoKeyStore]: CryptoKeyStore, constructor - start
[2017-10-16 11:07:43.224] [DEBUG] Helper - [utils.CryptoKeyStore]: constructor, no super class specified, using config: fabric-client/lib/impl/FileKeyValueStore.js
[2017-10-16 11:07:43.224] [DEBUG] Helper - [FileKeyValueStore.js]: FileKeyValueStore.js - constructor
[2017-10-16 11:07:43.225] [DEBUG] Helper - Msp ID : Org1MSP
[2017-10-16 11:07:43.225] [DEBUG] Helper - [crypto_ecdsa_aes]: importKey - start
[2017-10-16 11:07:43.225] [DEBUG] Helper - [crypto_ecdsa_aes]: importKey - have the key [Circular]
[2017-10-16 11:07:43.226] [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:43.226] [DEBUG] Helper - [FileKeyValueStore.js]: FileKeyValueStore.js - constructor
[2017-10-16 11:07:43.226] [DEBUG] Helper - [utils.CryptoKeyStore]: _getKeyStore returning ks
[2017-10-16 11:07:43.226] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param X: 0a66f3503a3322b2ca8e9dce03322d486ee6ec5970efaad3f153bc13aa2d942c
[2017-10-16 11:07:43.227] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param Y: 312ad05190fa592fb9e8ac2dcdb23c84df7f49e4ee295c2aa1200a50c9146c46
[2017-10-16 11:07:43.227] [DEBUG] Helper - [FileKeyValueStore.js]: FileKeyValueStore -- setValue
[2017-10-16 11:07:43.227] [DEBUG] Helper - [crypto_ecdsa_aes]: importKey - start
[2017-10-16 11:07:43.228] [DEBUG] Helper - [crypto_ecdsa_aes]: importKey - have the key [Circular]
[2017-10-16 11:07:43.228] [DEBUG] Helper - [utils.CryptoKeyStore]: _getKeyStore resolving store
[2017-10-16 11:07:43.228] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param X: 0a66f3503a3322b2ca8e9dce03322d486ee6ec5970efaad3f153bc13aa2d942c
[2017-10-16 11:07:43.228] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param Y: 312ad05190fa592fb9e8ac2dcdb23c84df7f49e4ee295c2aa1200a50c9146c46
[2017-10-16 11:07:43.229] [DEBUG] Helper - [FileKeyValueStore.js]: FileKeyValueStore -- setValue
[2017-10-16 11:07:43.229] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param X: 0a66f3503a3322b2ca8e9dce03322d486ee6ec5970efaad3f153bc13aa2d942c
[2017-10-16 11:07:43.229] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param Y: 312ad05190fa592fb9e8ac2dcdb23c84df7f49e4ee295c2aa1200a50c9146c46
[2017-10-16 11:07:43.229] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param X: 0a66f3503a3322b2ca8e9dce03322d486ee6ec5970efaad3f153bc13aa2d942c
[2017-10-16 11:07:43.229] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param Y: 312ad05190fa592fb9e8ac2dcdb23c84df7f49e4ee295c2aa1200a50c9146c46
[2017-10-16 11:07:43.230] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param X: 0a66f3503a3322b2ca8e9dce03322d486ee6ec5970efaad3f153bc13aa2d942c
[2017-10-16 11:07:43.230] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param Y: 312ad05190fa592fb9e8ac2dcdb23c84df7f49e4ee295c2aa1200a50c9146c46
[2017-10-16 11:07:43.230] [DEBUG] Helper - [FileKeyValueStore.js]: FileKeyValueStore -- setValue
[2017-10-16 11:07:43.235] [DEBUG] Helper - [crypto_ecdsa_aes]: ecdsa signature:  Signature {
  r: <BN: 7998f934a2a39ba42f71db18fad6e5f36e3f537e218a777fff0c95944cbea02a>,
  s: <BN: 21f6d2e03770cb886555b549ac0baf658c0858f79512a38d1811a1ad3c60b6b0>,
  recoveryParam: 0 }
[2017-10-16 11:07:43.255] [DEBUG] Query - <<< Installed Chaincodes >>>
[2017-10-16 11:07:43.255] [DEBUG] Query - name: mycc, version: v0, path: github.com/example_cc
12 查询已经加入的channel名称
前言
查询peer加入的channel名称。需要如下参数:
- peer节点
路由
app.js
//获取加入channel名称
app.get('/channels', function(req, res) {
	logger.debug('================ GET CHANNELS ======================');
	logger.debug('peer: ' + req.query.peer);
	var peer = req.query.peer;
	if (!peer) {
		res.json(getErrorMessage('\'peer\''));
		return;
	}
	query.getChannels(peer, req.username, req.orgname)
	.then(function(
		message) {
		res.send(message);
	});
});
具体实现
query.js
var getChannels = function(peer, username, org) {
    // peer地址
    var target = buildTarget(peer, org);
    // channel实例
    var channel = helper.getChannelForOrg(org);
    //client实例
    var client = helper.getClientForOrg(org);
    // 获取当前注册用户
	return helper.getRegisteredUsers(username, org).then((member) => {
		//通过client调用api
		return client.queryChannels(target);
	}, (err) => {
		logger.info('Failed to get submitter "' + username + '"');
		return 'Failed to get submitter "' + username + '". Error: ' + err.stack ?
			err.stack : err;
	}).then((response) => {
		//处理响应
		if (response) {
			logger.debug('<<< channels >>>');
			var channelNames = [];
			for (let i = 0; i < response.channels.length; i++) {
				channelNames.push('channel id: ' + response.channels[i].channel_id);
			}
			logger.debug(channelNames);
			return response;
		} else {
			logger.error('response_payloads is null');
			return 'response_payloads is null';
		}
	}, (err) => {
		logger.error('Failed to send query due to error: ' + err.stack ? err.stack :
			err);
		return 'Failed to send query due to error: ' + err.stack ? err.stack : err;
	}).catch((err) => {
		logger.error('Failed to query with error:' + err.stack ? err.stack : err);
		return 'Failed to query with error:' + err.stack ? err.stack : err;
	});
};
基本流程

API访问
echo "GET query Channels"
echo
curl -s -X GET \
  "http://localhost:4000/channels?peer=peer1" \
  -H "authorization: Bearer $ORG1_TOKEN" \
  -H "content-type: application/json"
echo
echo
控制台打印:
GET query Channels
{"channels":[{"channel_id":"mychannel"}]}
后台打印:
[2017-10-16 11:07:43.315] [DEBUG] SampleWebApp - ================ GET CHANNELS ======================
[2017-10-16 11:07:43.316] [DEBUG] SampleWebApp - peer: peer1
[2017-10-16 11:07:43.316] [DEBUG] Helper - [FileKeyValueStore.js]: FileKeyValueStore.js - constructor
[2017-10-16 11:07:43.317] [DEBUG] Helper - [FileKeyValueStore.js]: FileKeyValueStore -- getValue
[2017-10-16 11:07:43.319] [DEBUG] Helper - [crypto_ecdsa_aes]: importKey - start
[2017-10-16 11:07:43.319] [DEBUG] Helper - [crypto_ecdsa_aes]: importKey - have the key [Circular]
[2017-10-16 11:07:43.320] [DEBUG] Helper - [utils.CryptoKeyStore]: _getKeyStore resolving store
[2017-10-16 11:07:43.320] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param X: b3e2a75b9a4fd2b081589b1c45bde49f583aea9d7d466798c7b765c4ca96973d
[2017-10-16 11:07:43.320] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param Y: c58820e5a9db75ab17841ac158e9389ad0d130a6827dc0682dcb2d2c5dccb349
[2017-10-16 11:07:43.322] [DEBUG] Helper - [FileKeyValueStore.js]: FileKeyValueStore -- setValue
[2017-10-16 11:07:43.323] [DEBUG] Helper - [utils.CryptoKeyStore]: _getKeyStore resolving store
[2017-10-16 11:07:43.324] [DEBUG] Helper - [FileKeyValueStore.js]: FileKeyValueStore -- getValue
[2017-10-16 11:07:43.325] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param X: b3e2a75b9a4fd2b081589b1c45bde49f583aea9d7d466798c7b765c4ca96973d
[2017-10-16 11:07:43.325] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param Y: c58820e5a9db75ab17841ac158e9389ad0d130a6827dc0682dcb2d2c5dccb349
[2017-10-16 11:07:43.325] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param X: b3e2a75b9a4fd2b081589b1c45bde49f583aea9d7d466798c7b765c4ca96973d
[2017-10-16 11:07:43.325] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param Y: c58820e5a9db75ab17841ac158e9389ad0d130a6827dc0682dcb2d2c5dccb349
[2017-10-16 11:07:43.325] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param X: b3e2a75b9a4fd2b081589b1c45bde49f583aea9d7d466798c7b765c4ca96973d
[2017-10-16 11:07:43.325] [DEBUG] Helper - [ecdsa/key.js]: ECDSA curve param Y: c58820e5a9db75ab17841ac158e9389ad0d130a6827dc0682dcb2d2c5dccb349
[2017-10-16 11:07:43.325] [DEBUG] Helper - [FileKeyValueStore.js]: FileKeyValueStore -- setValue
[2017-10-16 11:07:43.326] [INFO] Helper - Successfully loaded member from persistence
[2017-10-16 11:07:43.334] [DEBUG] Helper - [crypto_ecdsa_aes]: ecdsa signature:  Signature {
  r: <BN: e8f972a0b424c772ab360fdf4f0e3341a1d82398886cd7e93fcff87354f35f37>,
  s: <BN: 3ecb06de15192b6a0797e0719d2db80128b9bd1491d472b61ecb4fb3893c55c6>,
  recoveryParam: 0 }
[2017-10-16 11:07:43.346] [DEBUG] Query - <<< channels >>>
[2017-10-16 11:07:43.346] [DEBUG] Query - [ 'channel id: mychannel' ]

 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号