都2021年了,fabric 2.2.x fabric java sdk 动态添加组织案例和源码要有了吧
2021 年了没有可以直接复制粘贴用fabric 2.2.x 简单代码?那就自己写,并且分享一下偷懒configtx.yaml配置,首先确保你搭建的联盟链channel的配置是这个样子,
这个配置文件名字叫 configtx.yaml
################################################################################ # # CHANNEL # # This section defines the values to encode into a config transaction or # genesis block for channel related parameters. # ################################################################################ Channel: &ChannelDefaults # Policies defines the set of policies at this level of the config tree # For Channel policies, their canonical path is # /Channel/<PolicyName> Policies: # Who may invoke the 'Deliver' API Readers: Type: ImplicitMeta Rule: "ANY Readers" # Who may invoke the 'Broadcast' API Writers: Type: ImplicitMeta Rule: "ANY Writers" # By default, who may modify elements at this config level Admins: Type: ImplicitMeta Rule: "ANY Admins" # 这点很重要,只有这样你安装链码单节点审批就行了,建议全部偷懒全部ANY ,只要有Admin签名就行 # Capabilities describes the channel level capabilities, see the # dedicated Capabilities section elsewhere in this file for a full # description Capabilities: <<: *ChannelCapabilities
搭建联盟链这种有其他简单教程,这里不再赘述。
生成加密材料,先生成crypto-config.yaml 然后使用命令生成加密材料
@Test void add() throws IOException { PeerOrgsTemplate peerOrgsTemplate = new PeerOrgsTemplate(); PeerOrg peerOrg = new PeerOrg(); peerOrg.setName("org4") .setDomain("org4.example.com") .setEnableNodeOUs(true) .setTemplate(2) .setCA("CN", "BJ", "LY") .setUsers(1); peerOrgsTemplate.add(peerOrg); // YamlReader yamlReader = new YamlReader(peerOrgsTemplate) // // YamlWriter yamlWriter = new YamlWriter(new FileWriter("/home/ct/Workspace/java/sdk2x/src/test/fix/output.yaml")); // // yamlWriter.write(peerOrgsTemplate); // yamlWriter.close(); peerOrgsTemplate.writeFile(Paths.get("/home/ct/Workspace/java/sdk2x/src/test/fix/","output.yaml")); } /* 生成加密材料 /home/ct/Workspace/fabric/package/bin/2.2.1/cryptogen \ generate --config=/home/ct/Workspace/java/sdk2x/src/test/fix/output.yaml \ --output="organizations" */
根据加密材料生成组织信息configtx.yaml,然后使用命令生成org4.json
@Test void writeFile() throws IOException { OrganizationsTemplate ot = new OrganizationsTemplate(); Organization og = new Organization(); og.setName("Org4MSP"); og.setID("Org4MSP"); og.setMSPDir("/home/ct/Workspace/java/sdk2x/src/test/fix/organizations/peerOrganizations/org4.example.com/msp"); Policies pl = new Policies(new Readers(Rule.SIGNATURE,Rule.adminPeerClient(og.ID)), new Writers(Rule.SIGNATURE,Rule.adminClient(og.ID)), new Admins(Rule.SIGNATURE,Rule.admin(og.ID))); // System.out.println(pl.Writers.Rule); og.setPolicies( pl); og.addAnchorPeer(new AnchorPeer("peer0.org4.example.com",7051)); ot.addOrganization(og); ot.writeFile(Paths.get("/home/ct/Workspace/java/sdk2x/src/test/fix","configtx.yaml")); } /* 生成 org4.json // /home/ct/Workspace/fabric/package/bin/2.2.1/configtxgen -printOrg Org4MSP > ./org4.json /home/ct/Workspace/fabric/package/bin/2.2.1/configtxlator proto_decode --input config_block.pb --type common.Config > config.json jq -s '.[0] * {"channel_group":{"groups":{"Application":{"groups": {"Org4MSP":.[1]}}}}}' config.json ./org4.json > modified_config.json */
直接贴代码分析一下,看注释就行了
@Test void channelConfig() throws Exception {
// 这是路径,就是fabric加密材料的地方,默认读取的路径自己会拼接crypto-config
String cryptoConfig = "/home/ct/Workspace/fabric/outdir";
// OrgManage om = new OrgManage("","example.com"); OrgManage om = new OrgManage(cryptoConfig, "example.com"); om.initHFClient(); //Peer peer =; 选择一个你要使用的用户 OrgManage.UserContext user = om.newUser("Admin", "Org1MSP", "org1"); om.hfClientAddUser(user); om.initChannel("mychannel"); om.channelAddOrderer(om.newOrderer("orderer", "orderer.example.com", "7050")); om.channelAddPeer(om.newPeer("peer0", "org1", "peer0.org1.example.com", "7051")); om.build(); Channel channel = om.getChannel(); HFClient hfClient = om.getHfClient(); // 到这里就创建好 channel 客户端和 HFClient 客户端了 byte[] configPB = channel.getChannelConfigurationBytes(); // 获取channel配置 // configPB 写入文件检测 InputStream isConfigPb = new ByteArrayInputStream(configPB); InUtils.writeStream(isConfigPb,"/home/ct/Workspace/java/sdk2x/src/test/fix/config.pb"); // 添加的新组织 String orgMSP = "Org4MSP"; // 实例化Forest配置对象 ForestConfiguration configuration = ForestConfiguration.configuration(); // 通过Forest配置对象实例化Forest请求接口 ConfigtxlatorClient myClient = configuration.createInstance(ConfigtxlatorClient.class); // 调用Forest请求接口,并获取响应返回结果 这里使用 Configtxlator 解析 PB 文件 JSONObject configJson = myClient.decodeCommonConfig("47.105.36.27:7059", configPB, "c.pb"); // 需要获取的数据 byte[] jsonByte = configJson.toString().getBytes(); InputStream inputStream = new ByteArrayInputStream(jsonByte); // 写入文件 InUtils.writeStream(inputStream, "/home/ct/Workspace/java/sdk2x/src/test/fix/config2.json"); // 读取 org.json , 这个文件是通过脚本生成,可以去看源码 doc 里面的脚本,就是生成的组织4的加密材料和 configtx.yaml 文件通过
// configtxgen -printOrg Org3MSP > ./org3.json 源码里有如何生成 configtx.yaml 的摸板
JSONObject orgJson = readJson("/home/ct/Workspace/java/sdk2x/src/test/fix/org4.json"); // 文件进行拼接产生新的 modifiedConfig String modifiedConfigStr = configJson.toJSONString(); // jq -s '.[0] * {"channel_group":{"groups":{"Application":{"groups": {"Org3MSP":.[1]}}}}}' config.json ../channel-artifacts/org3.json > modified_config.json JSONObject modifiedConfig = JSONObject.parseObject(modifiedConfigStr); modifiedConfig.getJSONObject("channel_group").getJSONObject("groups").getJSONObject("Application").getJSONObject("groups").put(orgMSP,orgJson); // 把 modifiedConfig 写入文件检测是否写入 modifiedConfigStr = modifiedConfig.toString(); InUtils.writeStream("/home/ct/Workspace/java/sdk2x/src/test/fix/modified_config.json",modifiedConfigStr); // 把 modifiedConfig 转换成 ProtoBuffer 文件 byte[] modifiedConfigJsonPB = myClient.encodeCommonConfig("47.105.36.27:7059", modifiedConfigStr.getBytes(), "c.pb"); // 写入文件检测 InputStream isModifiedConfigJsonPB = new ByteArrayInputStream(modifiedConfigJsonPB); InUtils.writeStream(isModifiedConfigJsonPB,"/home/ct/Workspace/java/sdk2x/src/test/fix/modified_config.pb"); ConfigtxlatorHttpClient configtxlatorHttpClient = new ConfigtxlatorHttpClient(); String channelName = "mychannel"; // org4_update.pb byte[] orgUpdatePb = configtxlatorHttpClient.computeUpdate("47.105.36.27:7059",channelName,configPB,modifiedConfigJsonPB); InUtils.writeStream(new ByteArrayInputStream(orgUpdatePb),"/home/ct/Workspace/java/sdk2x/src/test/fix/org4_update.pb"); // 创建 update -f org3_update_in_envelope.pb UpdateChannelConfiguration updateChannelConfiguration = new UpdateChannelConfiguration(orgUpdatePb); // 创建 OrdererMSP 用户 , 实际生产自己肯定没有保存这么多证书,可以通过 p2p 网络发过来 Signature 而不是证书 OrgManage.UserContext ordererAdmin = om.newUser("Admin", "OrdererMSP"); // 创建 adminOrg2 OrgManage.UserContext adminOrg2 = om.newUser("Admin", "Org2MSP", "org2"); // 创建 adminOrg3 OrgManage.UserContext adminOrg3 = om.newUser("Admin", "Org3MSP", "org3"); // 提交签名,这里确实会自己添加头部 '{"payload":{"header":{"channel_header":{"channel_id":...
// 超过半数签名 channel.updateChannelConfiguration(updateChannelConfiguration, hfClient.getUpdateChannelConfigurationSignature(updateChannelConfiguration,ordererAdmin), // hfClient.getUpdateChannelConfigurationSignature(updateChannelConfiguration,user), hfClient.getUpdateChannelConfigurationSignature(updateChannelConfiguration,adminOrg2), hfClient.getUpdateChannelConfigurationSignature(updateChannelConfiguration,adminOrg3)); byte[] configPBNew = channel.getChannelConfigurationBytes(); // configPB 写入文件检测 InputStream isConfigPbNew = new ByteArrayInputStream(configPBNew); InUtils.writeStream(isConfigPbNew,"/home/ct/Workspace/java/sdk2x/src/test/fix/configAddOrg4.pb"); }
详细代码直接去源码test里找就好了