声明使用的版本
- fabric版本如下:1.4.8
- node-sdk版本:1.4.8
- node版本:v8.11.1
- ubuntu版本:16.04
关于锚节点你需要知道的
锚节点的概念
某一个组织,当只有使用了锚节点,组织内的消息才能与另外的组织进行交互,简单来说锚节点就是组织的网关
为什么需要使用锚节点
Fabric中,每个组织可以指定Anchor Peer,其他组织的节点就可以将Gossip消息发送到这个Anchor Peer上,进而Anchor Peer将获得整个网络信息,区块广播到本组织内。
SDK添加锚节点的思路
- 1、从创世块中配置某个组织的锚节点
- 2、用工具生成锚节点的.tx文件
- 3、读取这个.tx到二进制流中
- 4、用对应组织的admin权限,更新到通道中
开始用代码实现
本文暂时只是通过使用通道文件的形式来更新锚节点,后面还可以使用直接更新通道配置的形式来更新
按照上面的说法,我们来用代码实现
// 更新锚节点
const updateAnchorPeers = async function (orgName, orgAdminName, ordererName, configUpdatePath, channelName) {
let error_message = ""
try {
const ccpPath = path.resolve(__dirname, "connect-sdk.json");
const ccp = JSON.parse(fs.readFileSync(ccpPath, 'utf8'));
const walletPath = path.join(process.cwd(), 'wallet');
const wallet = new FileSystemWallet(walletPath);
console.log(`Wallet path: ${walletPath}`);
let checkUserResult = await checkUser(wallet, orgAdminName)
if(!checkUserResult) {
// 从crypto-config文件夹中导出org admin的身份,保存到钱包中
await getAdminIdentify(wallet, orgAdminName, ccp.organizations[orgName].adminPrivateKey.path, ccp.organizations[orgName].signedCert.path, ccp.organizations[orgName].mspid)
}
const gateway = new Gateway();
await gateway.connect(ccp, { wallet, identity: orgAdminName, discovery: { enabled: true, asLocalhost: false } });
// // first read in the file, this gives us a binary config envelope
// let adminKey = fs.readFileSync(path.join(__dirname, adminOrgKeyPath));
// // let adminCert = fs.readFileSync(path.join(__dirname, './crypto-config/peerOrganizations/org1.zeng.com/users/Admin@org1.zeng.com/msp/cacerts/ca.org1.zeng.com-cert.pem'));
// let adminCert = fs.readFileSync(path.join(__dirname, adminOrgCertPath));
var client = gateway.getClient()
// client.setAdminSigningIdentity(adminKey.toString(),adminCert.toString(), orgName)
let channel = client.newChannel(channelName);
if(!channel) {
let message = util.format('Channel %s was not defined in the connection profile', channelName);
// logger.error(message);
console.log(message)
throw new Error(message);
}
// read in the envelope for the channel config raw bytes
var envelope = fs.readFileSync(path.join(__dirname, configUpdatePath));
// extract the channel config bytes from the envelope to be signed
var channelConfig = client.extractChannelConfig(envelope); // 提取通道的配置文件
// Acting as a client in the given organization provided with "orgName" param
// sign the channel config bytes as "endorsement", this is required by
// the orderer's channel creation policy
// this will use the admin identity assigned to the client when the connection profile was loaded
let signature = client.signChannelConfig(channelConfig); // 对提取的通道配置文件进行签名,client目前的身份是admin
let request = {
config: channelConfig,
signatures: [signature],
name: channelName,
txId: client.newTransactionID(true) // get an admin based transactionID
};
var promises = [];
let event_hubs = channel.getChannelEventHubsForOrg(); // 注册通道的针对当前org的事件,原文如下: Gets a list of ChannelEventHubs based on an organization. If the organization name is omitted then the current organization of the current user is used.
logger.debug('found %s eventhubs for this organization %s',event_hubs.length, orgName);
event_hubs.forEach((eh) => {
let anchorUpdateEventPromise = new Promise((resolve, reject) => {
logger.debug('anchorUpdateEventPromise - setting up event');
const event_timeout = setTimeout(() => {
let message = 'REQUEST_TIMEOUT:' + eh.getPeerAddr();
logger.error(message);
eh.disconnect();
}, 60000);
eh.registerBlockEvent((block) => { // To register for block events.
logger.info('The config update has been committed on peer %s',eh.getPeerAddr());
clearTimeout(event_timeout);
resolve();
}, (err) => {
clearTimeout(event_timeout);
logger.error(err);
reject(err);
},
// the default for 'unregister' is true for block listeners
// so no real need to set here, however for 'disconnect'
// the default is false as most event hubs are long running
// in this use case we are using it only once
{unregister: true, disconnect: true}
);
eh.connect();
});
promises.push(anchorUpdateEventPromise);
});
var orderer=client.getOrderer(ordererName)
channel.addOrderer(orderer)
var sendPromise = client.updateChannel(request);
// put the send to the orderer last so that the events get registered and
// are ready for the orderering and committing
promises.push(sendPromise);
let results = await Promise.all(promises);
logger.debug(util.format('------->>> R E S P O N S E : %j', results));
let response = results.pop(); // orderer results are last in the results
if (response) {
if (response.status === 'SUCCESS') {
logger.info('Successfully update anchor peers to the channel %s', channelName);
} else {
error_message = util.format('Failed to update anchor peers to the channel %s with status: %s reason: %s', channelName, response.status, response.info);
logger.error(error_message);
}
} else {
error_message = util.format('Failed to update anchor peers to the channel %s', channelName);
logger.error(error_message);
}
} catch (error) {
logger.error('Failed to update anchor peers due to error: ' + error.stack ? error.stack : error);
error_message = error.toString();
}
if (!error_message) {
let message = util.format(
'Successfully update anchor peers in organization %s to the channel \'%s\'',
orgName, channelName);
logger.info(message);
const response = {
success: true,
message: message
};
return response;
} else {
let message = util.format('Failed to update anchor peers. cause:%s',error_message);
logger.error(message);
const response = {
success: false,
message: message
};
return response;
}
}
头文件部分如下
'use strict';
const { FileSystemWallet, Gateway, X509WalletMixin } = require('fabric-network');
const Client = require('fabric-client');
const utils = require('fabric-client/lib/utils.js');
const fs = require('fs');
const path = require('path');
const util = require('util');
const {incHashString, getConfig, loadWallet} = require('./utils');
var log4js = require('log4js');
var getLogger = function(moduleName) {
var logger = log4js.getLogger(moduleName);
// logger.setLevel('DEBUG');
logger.level = 'DEBUG';
return logger;
};
const logger = getLogger('test');
调用代码部分如下
let ordererName = "orderer.zeng.com"
let channelName = "mychannel"
// let orgName = "Org1"
// let orgAdminName = "admin1"
// let configUpdatePath = "Org1MSPanchors.tx"
let orgName = "Org2"
let orgAdminName = "admin2"
let configUpdatePath = "Org2MSPanchors.tx"
updateAnchorPeers(orgName, orgAdminName, ordererName, configUpdatePath, channelName)
调用成功后显示信息如下
[2021-04-13T10:07:11.677] [DEBUG] test - found 0 eventhubs for this organization Org1
[2021-04-13T10:07:11.737] [DEBUG] test - ------->>> R E S P O N S E : [{"status":"SUCCESS","info":""}]
[2021-04-13T10:07:11.738] [INFO] test - Successfully update anchor peers to the channel mychannel
[2021-04-13T10:07:11.738] [INFO] test - Successfully update anchor peers in organization Org1 to the channel 'mychannel'