balance transfer 提供了很多查询接口,包括链码查询,根据区块号查询区块数据,根据交易ID查询交易信息,查询链上的区块数,查询已安装或已实例化的链码,查询通道。
源码解析
1.调用链码查询:调用指定背书节点上部署的普通chaincode对状态数据库进行查询操作,该方法只会发送交易提案到目标节点,并不会产生新的交易发送给排序服务。
// 调用指定节点上部署的普通链码进行查询
app.get('/channels/:channelName/chaincodes/:chaincodeName', async function(req, res) {
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;
// 处理参数
args = args.replace(/'/g, '"');
args = JSON.parse(args);
logger.debug(args);
let message = await query.queryChaincode(peer, channelName, chaincodeName, args, fcn, req.username, req.orgname);
res.send(message);
});
// query.js中的queryChaincode()方法
var queryChaincode = async function(peer, channelName, chaincodeName, args, fcn, username, org_name) {
try {
// 创建client和channel对象
var client = await helper.getClientForOrg(org_name, username);
var channel = client.getChannel(channelName);
// 构造查询请求
var request = {
targets : [peer], // 允许指定多个节点
chaincodeId: chaincodeName,
fcn: fcn,
args: args
};
// 调用SDK中的queryByChaincode()方法,内部调用sendTransactionProposal()
// 向所有目标背书节点发送生成的交易提案,并提取出所有提案响应中的payload组成一个list返回
let response_payloads = await channel.queryByChaincode(request);
// 从响应内容中解析出查询结果, response_payloads是一个list类型
// 其中每个元素都是一个字节数组(bytes array),对应每一个指定节点的查询结果
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[0].toString('utf8') +
' after the move';
} else {
logger.error('response_payloads is null');
return 'response_payloads is null';
}
} catch(error) {
logger.error('Failed to query due to error: ' + error.stack ? error.stack : error);
return error.toString();
}
};
2.根据区块号查询区块数据
app.get('/channels/:channelName/blocks/:blockId', async function(req, res) {
let blockId = req.params.blockId;
let peer = req.query.peer;
let message = await query.getBlockByNumber(peer, req.params.channelName, blockId, req.username, req.orgname);
res.send(message);
});
var getBlockByNumber = async function(peer, channelName, blockNumber, username, org_name) {
try {
// 创建client和channel对象
var client = await helper.getClientForOrg(org_name, username);
var channel = client.getChannel(channelName);
// 调用SDK中的queryBlock方法,内部调用sendTransactionProposal()发送交易提案到背书节点,
// 背书节点会调用 QSCC 系统链码中的 GetBlockByNumber 接口从链上获取区块数据
let response_payload = await channel.queryBlock(parseInt(blockNumber, peer));
if (response_payload) {
logger.debug(response_payload);
return response_payload;
} else {
logger.error('response_payload is null');
return 'response_payload is null';
}
} catch(error) {
logger.error('Failed to query due to error: ' + error.stack ? error.stack : error);
return error.toString();
}
};
总结
其他的查询方法与上面查询区块的方法类似,都是先调用query.js
的对应接口,再调用SDK中的对应接口,然后内部调用 sendTransactionProposal()
来发送交易提案到背书节点,随后背书节点调用相应系统链码中的对应方法来进行查询。
查询功能 | app调用 | SDK调用 | 链码调用 | 链码方法fcn |
---|---|---|---|---|
链码查询 | queryChaincode | queryByChaincode | chaincode | query |
根据区块号获取区块 | getBlockByNumber | queryBlock | QSCC | GetBlockByNumber |
根据交易号获取交易 | getTransactionByID | queryTransaction | QSCC | GetTransactionByID |
根据区块hash获取区块 | getBlockByHash | queryBlockByHash | QSCC | GetBlockByHash |
查询链信息 | getChainInfo | queryInfo | QSCC | GetChainInfo |
查询已安装链码 | getInstalledChaincodes | queryInstalledChaincodes | LSCC | getinstalledchaincodes |
查询已实例化链码 | getInstalledChaincodes | queryInstantiatedChaincodes | LSCC | getchaincodes |
查询链信息 | getChainInfo | queryInfo | QSCC | GetChainInfo |
查询加入的通道 | getChannels | queryChannels | CSCC | GetChannels |