如何创建一个Hyperledger Fabric channel

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何创建一个Hyperledger Fabric channel相关的知识,希望对你有一定的参考价值。

创建channel的步骤:

  1. 执行configtxgen tool来生成genesis block;
  2. 执行configtxgen tool来生成初始二进制配置定义;
  3. 通过以下两种方式获取sign-able channel定义:1)使用初始二进制channel配置定义—使用fabric-client SDK从初始二进制配置定义中解析出sign-able channel定义;2)建立一个定制的定义—使用configtxlator将初始二进制channel配置定义转换成可读文本—编辑可读文本—使用configtxlator将可读文本转换成sign-able channel定义。
  4. 使用fabric-client SDK签署sign-able channel定义;
  5. 使用fabric-client SDK将签名与sign-able channel定义发送给orderer;
  6. 使用fabric-client SDK将peer加入到channel;
  7. 新channel可以使用。

使用初始定义来建立sign-able channel定义

初始二进制channel配置定义由configtxgen tool生成,是包含Hyperledger Fabric配置protobuf common.Envelope的二进制元素,在这个元素里面的是common.ConfigUpdate protobuf元素。这个配置元素是必须被签署的元素之一。configtx.yaml中的元素轮廓是初始化二进制channel配置定义的源(由configtxgen tool生成)。

../../../bin/configtxgen -channelID mychannel -outputCreateChannelTX mychannel.tx -profile TwoOrgsChannel

令fabric-client SDK解析对channel.tx文件的配置更新元素:

//首先读取文件,获得二进制配置信封
let envelope_bytes = fs.readFileSync(path.join(__dirname, ‘fabric-samples/balance-tranfer/artifacts/channel/mychannel.tx‘));
//令nodeSDK解析此配置更新
var config_update = client.extractChannelConfig(envelope_bytes);

此二进制config_update现在可以被用于签署过程并被发送到orderer,用于创建channel。

common.ConfigUpdate对于创建与更新执行相同的过程,只不过创建对应于系统channel,而更新对应于channel。提交的common.ConfigUpdate对象只会包含创建与更新的变化。

创建定制的sign-able channel定义

最简单的方式上手创建定制的channel配置的方式是使用configtxlator将一个已存在的二进制转换为可读的JSON文件。使用你建立Hyperledger Fabric网络时采用的configtx.yaml文件,使用configtxgen tool生成新channel的初始二进制配置定义。然后通过将该二进制发送给configtxlator来转换为JSON。此JSON也可以作为创建其他新channel的模板,一个新的channel会继承系统channel的设置,且任何organization加入新的channel必须在系统channel中定义为一个consortium,因此拿到可读的系统channel定义对于创建新channel很有帮助。还可以将genesis.block发送给configtxlator得到JSON文件来作为参考。

使用configtxgen tool来生产二进制配置文件。例如对于样例目录fabric-samples/balance-transfer/artifacts/channel

export FABRIC_CFG_PATH=$PWD
../../../bin/configtxgen -outputBlock genesis.block -profile TwoOrgsOrdererGenesis
../../../bin/configtxgen -channelID mychannel -outputCreateChannelTx mychannel.tx -profile TwoOrgsChannel

将这两个二进制文件发送至configtxlator服务,由于这一步只会进行一次且不需要Nodejs应用,我们使用cURL进行简化并加速以获得结果。注意configtxlator服务路径具有decode(将二进制转换为JSON),这个路径必须包含二进制对象的类型,在第一种情况下,它是common.Block。“decode”与“encode”可以被fabric-client/lib/protos目录下protobuf文件的任何protobuf消息对象类型完成。首先在fabric-samples/bin启动configtxlator服务:

curl -X POST --data-binary @genesis.block http://127.0.0.1:7059/protolator/decode/common.Block > genesis.json
curl -X POST --data-binary @mychannel.tx http://127.0.0.1:7059/protolator/decode/common.Envelope > mychannel.json

解码mychannel.tx的是一个common.Envelope,解码后包含一个common.ConfigUpdate对象。此对象位于“payload.data”的名为“config_update”的JSON对象。是作为创建新channel模板的源需要的对象。common.ConfigUpdate会被所有organization签署并提交给orderer来创建新的channel。

接下来是从TwoOrgsChannel解析的JSON“config_update”(common.ConfigUpdate)对象:

{
  "channel_id": "mychannel",
  "read_set": {
    "groups": {
      "Application": {
        "groups": {
          "Org1MSP": {}
        }
      }
    },
    "values": {
      "Consortium": {
        "value": {
          "name": "SampleConsortium"
        }
      }
    }
  },
  "write_set": {
    "groups": {
      "Application": {
        "groups": {
          "Org1MSP": {}
        },
        "mod_policy": "Admins",
        "policies": {
          "Admins": {
            "policy": {
              "type": 3,
              "value": {
                "rule": "MAJORITY",
                "sub_policy": "Admins"
              }
            }
          },
          "Readers": {
            "policy": {
              "type": 3,
              "value": {
                "sub_policy": "Readers"
              }
            }
          },
          "Writers": {
            "policy": {
              "type": 3,
              "value": {
                "sub_policy": "Writers"
              }
            }
          }
        },
        "version": "1"
      }
    },
    "values": {
      "Consortium": {
        "value": {
          "name": "SampleConsortium"
        }
      }
    }
  }
}

 使用的Consortium名字必须存在于系统channel。所有想要加入新channel的organization必须定义在Consortium名下。使用解码后的genesis.block来验证所有值,例如查看上文生成的genesis.json,要想加入一个organization,其必须被放在“Application”下的“group”下,可见Org1MSP是Application.groups的一个属性。此节中所有关于organization Org1MSP的设置都会继承自系统channel(organization属性的空对象{})要查看当前organization的设置的话查看系统channel中Consortium下的SampleConsortium(系统channel的genesis block)。

当你有了你channel的JSON配置文件后,将其发送给configtxlator编码为配置二进制。下面的例子是使用Nodejs包superagent(http请求比较容易)发送一个REST request给configtxlator。

var response = superagent.post(‘http://127.0.0.1:7059/protolator/encode/common.ConfigUpdate‘, config_json.toString())
  .buffer()
  .end((err, res) => {
    if(err) {
      logger.error(err);
      return;
    }
    config_proto = res.body;
  });

签署并提交channel更新

二进制配置必须被所有organization签署。应用需要保存此二进制配置并令其能够被所有签名签署并收集且保存所有签名。因此当签名结束时,应用将二进制配置与所有签名一起发送给orderer通过fabric-client SDK API createChannel()。

首先签署,假设client fabric-client SDK对象在已知organization中有一个有效用户:

var signature = client.signChannelConfig(config_proto);
signatures.push(signature);

现在是时候进行channel创建了,假设client.signChannelConfig()方法返回的signature对象是common.ConfigSignature的一个排列。

注意:orderer必须起始于genesis.block

//创建一个orderer对象代表网络中的orderer
var orderer = client.newOrderer(url,opts);

// 令SDK生成一个交易id
let tx_id = client.newTransactionID();

request = {
  config: config_proto, //二进制配置
  signatures : signatures, // 收集的签名
  name : ‘mychannel‘, // channel名
  orderer : orderer, //上文的orderer
  txId  : tx_id //生成的交易id
};

// 此调用返回一个Promise
client.createChannel(request)

createChannel API返回一个Promise来返回提交的状态码。创建channel的过程会在orderer中异步发生。

一小段时间后channel会被成功创建且可以加入peers。channel要求向peers发布以下内容,这是一个两步的过程:第一步获取channel的genesis block,然后将其发送给peer。下面的例子中genesis block既可以从orderer中提取,也可以从文件加载:

// 为网络节点启动channel
var orderer  = client.newOrderer(orderer_url,orderer_opts);
channel.addOrderer(orderer);
var peer = client.newPeer(peer_url,peer_opts);
channel.addPeer(peer);

tx_id = client.newTransactionID();
let g_request = {
  txId :     tx_id
};

// 从orderer中获取genesis block
channel.getGenesisBlock(g_request).then((block) =>{
  genesis_block = block;
  tx_id = client.newTransactionID();
  let j_request = {
    targets : targets,
    block : genesis_block,
    txId :     tx_id
  };

  // 将genesis block发送给peer
  return channel.joinChannel(j_request);
}).then((results) =>{
  if(results && results.response && results.response.status == 200) {
    // 加入成功
  } else {
    // 不成功
  }
});

 

以上是关于如何创建一个Hyperledger Fabric channel的主要内容,如果未能解决你的问题,请参考以下文章

如何编写一个企业级Hyperledger Fabric开源框架

Hyperledger Fabric - 第一个网络示例 - 创建通道时出错

Hyperledger Fabric:fabric private data技术官方文档翻译

Hyperledger Fabric 1.0 从零开始——创建Fabric多节点集群

Hyperledger-fabric 手动操作第一次运行简单网络

初识Hyperledger Fabric