fabric的组织配置信息一般是提前写在configtx.yaml文件中的,通过configtx.yaml生成系统创世区块和通道文件。而系统启动和通道创建是通过创世区块和通道文件进行的,因此要在fabric系统运行时添加组织则是非常困难的。
还好,fabric-1.0提供了configtxlator工具,为动态修改fabric通道信息提供可能。本文将介绍如何利用configtxlator为fabric-1.0网络动态添加组织。
运行fabric网络
本文利用fabric-sample项目中的first-network作为测试的示例。文档参考
下载fabric-sample
从github上克隆fabric-sample项目
$ git clone https://github.com/hyperledger/fabric-samples.git
$ cd fabric-samples
下载镜像和binary包
$ curl -sSL https://goo.gl/eYdRbX | bash
这一步可能需要翻墙,可以从这里下载,然后运行,或者
$ curl -sSL http://oui195df4.bkt.clouddn.com/download-bin.sh | bash
这一步会拉取fabric-1.0的镜像和binary包
生成证书和通道文件
为了测试添加组织,先利用cryptogen工具生成三个组织的证书。
修改first-network,添加org3
生成证书和通道文件
$ ./byfn.sh -m generate
证书文件在crypto-config文件夹里,通道文件在channel-artifacts文件夹中
启动两个组织的fabric网络
执行
$ ./byfn.sh -m up
启动包括两个组织的fabric网络,cli容器会执行scripts/script.sh脚本进行创建mychannel通道,加入通道,部署chaincode,调用和查询chaincode等。
在系统channel中添加org
参考configtxlator工具的文档。
启动configtxlator服务
$ configtxlator start
获取系统通道的配置
设置MSP为Orderer
$ export CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/users/Admin\@example.com/msp/
$ export CORE_PEER_LOCALMSPID=OrdererMSP
获取通道
# peer channel fetch config config_block.pb -o orderer.example.com:7050 -c testchainid
生成添加组织的增量文件
- 将配置信息区块转换为可读的json文件
$ curl -X POST --data-binary @config_block.pb http://127.0.0.1:7059/protolator/decode/common.Block > config_block.json
- 获取config区域
$ jq .data.data[0].payload.data.config config_block.json > config.json
- 修改config.json,添加org3信息
这一步可以利用configtxgen工具生成org3的配置信息,并将配置信息添加到config.json文件中,修改后的文件保存为updated_config.json,部分内容如图:
updated-config- 将original config和updated config打包成proto文件
$ curl -X POST --data-binary @config.json http://127.0.0.1:7059/protolator/encode/common.Config > config.pb
和
$ curl -X POST --data-binary @updated_config.json http://127.0.0.1:7059/protolator/encode/common.Config > updated_config.pb
- 生成增量文件
$ curl -X POST -F original=@config.pb -F updated=@updated_config.pb http://127.0.0.1:7059/configtxlator/compute/update-from-configs -F channel=testchainid > config_update.pb
至此,更新通道的数据已经准备好了。利用SDK可以签名和打包此消息,发送更新通道交易。值得注意的是,这个交易需要所有通道中已存在的org进行签名。
由于系统channel中只有一个组织——OrdererMSP,因此也可以直接通过命令行发送交易。
更新通道
- 将增量文件转换为pb格式
$ curl -X POST --data-binary @config_update.pb http://127.0.0.1:7059/protolator/decode/common.ConfigUpdate > config_update.json
- 打包数据
$ echo '{"payload":{"header":{"channel_header":{"channel_id":"testchainid", "type":2}},"data":{"config_update":'$(cat config_update.json)'}}}' > config_update_as_envelope.json
- 转换为pb文件
$ curl -X POST --data-binary @config_update_as_envelope.json http://127.0.0.1:7059/protolator/encode/common.Envelope > config_update_as_envelope.pb
- 进入cli,更新通道
root@d96f70c3b3ab:/#
root@d96f70c3b3ab:/# peer channel update -f config_update_as_envelope.pb -c testchainid -o 127.0.0.1:7050
此时系统channel——testchainid中则拥有了org3的信息。启动org3,则其可以进入fabric网络。但是org3无法加入mychannel通道,只能新建通道。
向mychannel添加org
向mychannel中添加org和向系统channel中添加org流程上是相同的,不同的是需要用所有PeerOrg进行签名。
生成增量pb文件
通过上述流程,生成增量pb文件,步骤省略。
发送更新通道交易
由于mychannel中有两个org,发送更新通道交易需要两个组织进行对更新交易进行多重签名,而通过执行peer channel update命令无法实现多重签名,因此需要通过SDK发送交易。
本文采用nodejs-sdk,创建更新交易js脚本,部分内容为
var signatures = [];
//读取增量pb文件
var config_proto = fs.readFileSync(path.join(__dirname, 'mychannel_config_update.pb'));
return Client.newDefaultKeyValueStore({
path: 'kvs_' + org
}).then((store) => {
client.setStateStore(store);
client._userContext = null;
return getPeerAdmin(client, 'org1');
}).then((admin) => {
logger.info('Successfully enrolled user \'admin\' for org1');
the_user = admin;
//org1对config_proto进行签名
var signature = client.signChannelConfig(config_proto);
logger.info('Successfully signed config update by org1');
signatures.push(signature);
client._userContext = null;
return getPeerAdmin(client, 'org2');
}).then((admin) => {
logger.info('Successfully enrolled user \'admin\' for org2');
the_user = admin;
//org2对config_proto进行签名
var signature = client.signChannelConfig(config_proto);
logger.info('Successfully signed config update by org2');
signatures.push(signature);
client._userContext = null;
return getOrdererAdmin(client);
}).then((admin) => {
logger.info('Successfully enrolled user \'admin\' for orderer');
the_user = admin;
//orderer对config_proto进行签名
var signature = client.signChannelConfig(config_proto);
logger.info('Successfully signed config update by org2');
signatures.push(signature);
let tx_id = client.newTransactionID();
request = {
config: config_proto,
signatures : signatures,
name : channelName,
orderer : orderer,
txId : tx_id
};
//更新通道
return client.updateChannel(request);
}).then((result) => {
if(result.status && result.status === 'SUCCESS') {
logger.info('Successfully updated the channel.');
return sleep(5000);
} else {
logger.error('Failed to update the channel. ');
Promise.reject('Failed to update the channel');
}
}).then((nothing) => {
logger.info('Successfully waited to make sure new channel was updated.');
执行js脚本文件,更新通道。
此时org3则能成功加入mychannel通道。
总结
从流程来看,动态添加组织过程还是比较复杂的,涉及到文件的多次转换,多重签名等步骤。
更重要的是,更新交易需要多个组织进行签名,而在实际运用过程中,一个组织不可能获取所有组织的私钥,因此需要增量数据在各个组织间进行审核、流转,这个过程也是非常繁琐的。因此,未来需要开发在线审核流转工具,协助对数据签名。
by. xuyuzhuang
date. 2017-08-22
网友评论
[2017-12-13 20:46:34.925] [ERROR] invoke-chaincode - The balance transfer transaction was invalid, code = ENDORSEMENT_POLICY_FAILURE
[2017-12-13 20:46:34.925] [ERROR] invoke-chaincode - Failed to send transaction and get notifications within the timeout period.
[2017-12-13 20:46:34.925] [ERROR] invoke-chaincode - Failed to order the transaction. Error code: undefined
[2017-12-13 20:46:34.929] [DEBUG] Helper - [crypto_ecdsa_aes]: ecdsa signature: Signature {
r: <BN: b920b65a2f2a90f2f13c34a7a3ad5bb3ca91ac5a2d53522c6be6c2c9bbca6dc5>,
s: <BN: 45eb884fd2de0c2727756f54047a9766cdef68d3ec49bf0b43adeb37efb173b6>,
recoveryParam: 1 }
[2017-12-13 20:46:34.930] [ERROR] invoke-chaincode - The balance transfer transaction was invalid, code = ENDORSEMENT_POLICY_FAILURE
这个命令中的type:2是啥意思,为啥是2不是1或者3呢?
"groups": {
"Application": {
"groups": {
"CmbAmdPeerMSP": {},
"TebonPeerMSP": {}
},
"policies": {
"Admins": {},
"Readers": {},
"Writers": {}
},
"version": "1"
}
}
},
version明明就是1,不知道为什么orderer获取的是0,求解求解啊?