1. 程式人生 > >如何創建一個Hyperledger Fabric channel

如何創建一個Hyperledger Fabric channel

gets 樣例目錄 extract 包含 其他 putc yaml sign 進制

創建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