Hyperledger Fabric channel配置交易

一個超級帳本區塊鏈網絡裏每一個channel的共享配置都是存儲在一個配置交易裏。每一個配置交易一般被簡稱爲configtxgolang

Channel 配置有如下重要屬性:網絡

1、有版本標識:配置裏的全部元素都有一個關聯版本。每次更新配置,版本號都維持最新。另外,每一個提交的配置會得到一個序列號。app

2、有權限:配置裏的每一個元素都有一個關聯策略,用來管理是否容許對這個元素進行修改。每個保存有當前配置副本的實例,都會按照關聯策略的內容對新收到的配置改動進行驗證權限。區塊鏈

3、層次性:一個配置根組包含多個子組,而且層次中的每一個組都有關聯的值和策略。較低層次能夠獲取上層的策略。測試


配置分析ui

配置做爲一個HeaderType_CONFIG類型的交易存儲在一個不包含其餘交易的區塊中。這些區塊被稱爲Configuration Blocks,全部區塊中的第一個區塊稱爲genesis blockthis

配置的樣例存儲在fabric/protos/common/configtx.protoHeaderType_CONFIG類型的Envelope編碼ConfigEnvelop信息做爲Payload data的值。ConfigEnvelop定義以下:編碼

message ConfigEnvelope {
    Config config = 1;
    Envelope last_update = 2;
}

last_update字段在下面的更新配置中有定義,該字段僅用於驗證配置。當前提交的配置存在config字段,包含一個Config消息。加密

message Config {
    uint64 sequence = 1;
    ConfigGroup channel_group = 2;
}

sequence的值在每次提交配置後加1,channel_group字段是包含該配置的根組。ConfigGroup是一個遞歸定義的結構,生成一個gruops樹,每一個組都包含值和策略。ConfigGroup的定義以下:spa

message ConfigGroup {
    uint64 version = 1;
    map<string,ConfigGroup> groups = 2;
    map<string,ConfigValue> values = 3;
    map<string,ConfigPolicy> policies = 4;
    string mod_policy = 5;
}

由於ConfigGroup是一個遞歸結構,有層次概念。接下來咱們用go語言例子來表示。


// Assume the following groups are defined
var root, child1, child2, grandChild1, grandChild2, grandChild3 *ConfigGroup

// Set the following values
root.Groups["child1"] = child1
root.Groups["child2"] = child2
child1.Groups["grandChild1"] = grandChild1
child2.Groups["grandChild2"] = grandChild2
child2.Groups["grandChild3"] = grandChild3

// The resulting config structure of groups looks like:
// root:
// child1:
// grandChild1
// child2:
// grandChild2
// grandChild3

config層次結構中,每一個組定義了一個層次,每一個組有一系列關聯的值和策略。值的定義以下:

message ConfigValue {
    uint64 version = 1;
    bytes value = 2;
    string mod_policy = 3;
}

策略的定義以下:

message ConfigPolicy {
    uint64 version = 1;
    Policy policy = 2;
    string mod_policy = 3;
}

注意值、策略和組都有一個versionmod_policy字段。一個元素的version在每次更改後遞增。mod_policy用來管理修改元素的簽名。對於組,更改就是添加或者移除ValuesPolicies、或者組地圖(或者修改mod_policy)。對於ValuesPolicies,修改就是改變修改Value或者Policy字段(或者修改mod_policy)。每一個元素的mod_policy在當前當前元素中有效

下面是一個定義在Channel.Groups["Application"]中的策略的示例(這裏用的是golang語法,所以Channel.Groups["Application"].Policies["policy1"]表示根組Channel的子組ApplicationPolicies裏的policy1對應的策略)

  • policy1對應Channel.Groups["Application"].Policies["policy1"]

  • Org1/policy2對應Channel.Groups["Application"].Groups["Org1"].Policies["policy2"]

  • /Channel/policy3對應Channel.Policies["policy3"]

注意,若是mod_policy引用了一個不存在的策略,那麼該元素不可修改。

Configuration updates / 更新配置

更新配置是提交一個HeaderType_CONFIG_UPDATE類型的Envelope消息,交易的Payload.data字段是序列化的ConfigUpdateEnvelope,其定義以下:

message ConfigUpdateEnvelope {
bytes config_update = 1; // A marshaled ConfigUpdate structure
repeated ConfigSignature signatures = 2; // Signatures over the config_update
}

其中signatures字段包含了受權更新配置的簽名集,定義以下:

message ConfigSignature {
bytes signature_header = 1; // A marshaled SignatureHeader
bytes signature = 2; // Signature over the concatenation signatureHeader bytes and config bytes
}

signature_header如標準交易所定義,而簽名則是signature_header字節和ConfigUpdateEnvelope中的config_update字節的拼接。

ConfigUpdateEnvelope中的config_update字段是序列化的ConfigUpdate,其定義爲:

message ConfigUpdate {
string channel_id = 1; // Which channel this config update is for
ConfigGroup read_set = 2; // ReadSet explicitly lists the portion of the config which was read, this should be sparse with only Version set
ConfigGroup write_set = 3; // WriteSet lists the portion of the config which was written, this should included updated Versions
}

其中channel_id是配置更新所對應的channel ID,該字段是必要,由於它界定了支持本次配置更新的所需的簽名範圍。

read_set是現有配置的一個子集,其中僅含version字段,ConfigValue.valueConfigPolicy.policy等其餘字段不包含在read_set中。ConfigGroupmap字段組成的子集,以便引用配置樹的深層元素。例如,爲使Applicationgroup包含到read_set,它的上層(Channelgroup)也必須包含到read_set中,但沒必要將Channelgroup中全部的key都包括進去,好比Orderer``group或者任何valuespolicies

write_set指定了要被修改的那部分配置。因爲配置的分層特性,修改深層元素就必須在write_set中包含其上層元素。write_set中的任意元素都會在read_set中指定相同版本的該元素。

例如,給出以下配置:

Channel: (version 0)
Orderer (version 0)
Appplication (version 3)
Org1 (version 2)

修改Org1提交的read_set應爲:

Channel: (version 0)
Application: (version 3)

對應的write_set應是:

Channel: (version 0)
Application: (version 3)
Org1 (version 3)

When the CONFIG_UPDATE is received, the orderer computes the resulting CONFIG by doing the following:

接收到CONFIG_UPDATE後,orderer會經過如下步驟計算CONFIG結果:

  1. 校驗channel_idread_setread_set中全部元素必須存在對應的版本。

  2. 收集read_setwrite_set中版本不一致的元素,計算更新集。

  3. 校驗更新集中的元素的版本號是否遞增1

  4. 校驗更新集中每一個元素,ConfigUpdateEnvelope的簽名知足mod_policy

  5. 經過將更新集應用於當前配置,計算該配置的完整新版本

  6. 將新配置寫成ConfigEnvelope做爲CONFIG_UPDATE賦給last_update字段,新的配置賦給config字段,sequence字段自增。

  7. ConfigEnvelope寫成CONFIG類型的Envelope,最終將此做爲惟一交易寫入配置區塊。

peer(或者任意其餘接收Deliver者)接收到這個配置區塊後,就會經過將last_update信息應用到當前配置並校驗orderer計算的config字段是否包含正確的新配置,來驗證該配置是否被正確校驗。

Permitted configuration groups and values / 組和值得配置許可

有效的配置都是下面配置的子集。在此,用peer.<MSG>表示一個ConfigValue,其value字段是稱爲<MSG>的序列化後的信息,定義在fabric/protos/peer/configuration.protocommon.<MSG>msp.<MSG>orderer.<MSG>分別定義在fabric/protos/common/configuration.protofabric/protos/msp/mspconfig.protofabric/protos/orderer/configuration.proto

Note, that the keys {{org_name}} and {{consortium_name}} represent arbitrary names, and indicate an element which may be repeated with different names.

注意,下面的{{org_name}} {{consortium_name}}是任意的名字,表示能夠重複使用不一樣名稱的元素。

&ConfigGroup{
Groups: map<string, *ConfigGroup> {
"Application":&ConfigGroup{
Groups:map<String, *ConfigGroup> {
{{org_name}}:&ConfigGroup{
Values:map<string, *ConfigValue>{
"MSP":msp.MSPConfig,
"AnchorPeers":peer.AnchorPeers,
},
},
},
},
"Orderer":&ConfigGroup{
Groups:map<String, *ConfigGroup> {
{{org_name}}:&ConfigGroup{
Values:map<string, *ConfigValue>{
"MSP":msp.MSPConfig,
},
},
},

Values:map<string, *ConfigValue> {
"ConsensusType":orderer.ConsensusType,
"BatchSize":orderer.BatchSize,
"BatchTimeout":orderer.BatchTimeout,
"KafkaBrokers":orderer.KafkaBrokers,
},
},
"Consortiums":&ConfigGroup{
Groups:map<String, *ConfigGroup> {
{{consortium_name}}:&ConfigGroup{
Groups:map<string, *ConfigGroup> {
{{org_name}}:&ConfigGroup{
Values:map<string, *ConfigValue>{
"MSP":msp.MSPConfig,
},
},
},
Values:map<string, *ConfigValue> {
"ChannelCreationPolicy":common.Policy,
}
},
},
},
},

Values: map<string, *ConfigValue> {
"HashingAlgorithm":common.HashingAlgorithm,
"BlockHashingDataStructure":common.BlockDataHashingStructure,
"Consortium":common.Consortium,
"OrdererAddresses":common.OrdererAddresses,
},
}

Orderer system channel configuration / Order channel 配置

ordering系統channel定義了建立channelordering參數和consortiumsordering service必須有一個ordering系統channel,這是被建立的第一個channel。建議不要在ordering系統channel初始配置中定義application部分,可是測試是能夠這麼作。注意,任何對ordering系統channel有讀權限的成員均可以查看全部channel建立,所以channel的訪問應受限制。

The ordering parameters are defined as the following subset of config:

ordering參數定義以下:

&ConfigGroup{
Groups: map<string, *ConfigGroup> {
"Orderer":&ConfigGroup{
Groups:map<String, *ConfigGroup> {
{{org_name}}:&ConfigGroup{
Values:map<string, *ConfigValue>{
"MSP":msp.MSPConfig,
},
},
},

Values:map<string, *ConfigValue> {
"ConsensusType":orderer.ConsensusType,
"BatchSize":orderer.BatchSize,
"BatchTimeout":orderer.BatchTimeout,
"KafkaBrokers":orderer.KafkaBrokers,
},
},
},

ordering中的每一個組織都在Orderer組下有一個組元素,這個組定義了一個MSP參數,這個參數包含該組織的加密身份信息。Orderer組中的Values決定了ordering節點的功能。他們存在於每一個channel中,因此像orderer.BatchTimeout就可在不一樣channel中指定不一樣值。

啓動時,orderer面對含有不少channel信息的文件系統,orderer經過識別帶有consortiums組定義的channel來標識系統channelconsortiums組結構以下。

&ConfigGroup{
Groups: map<string, *ConfigGroup> {
"Consortiums":&ConfigGroup{
Groups:map<String, *ConfigGroup> {
{{consortium_name}}:&ConfigGroup{
Groups:map<string, *ConfigGroup> {
{{org_name}}:&ConfigGroup{
Values:map<string, *ConfigValue>{
"MSP":msp.MSPConfig,
},
},
},
Values:map<string, *ConfigValue> {
"ChannelCreationPolicy":common.Policy,
}
},
},
},
},
},

注意,每一個consortium定義一組成員,就行ordering組織的組織成員同樣。每一個consortium也都定義了一個ChannelCreationPolicy,它是一種應用於受權channel建立請求的策略,一般這個值設爲ImplicitMetaPolicy,要求channel的新成員簽名受權channel建立。有關channel建立更信息的內容,請參閱文檔後面的內容。

Application channel configuration / APP channel 配置

應用程序配置用於爲應用類型交易設計的channel。其定義以下:

&ConfigGroup{
Groups: map<string, *ConfigGroup> {
"Application":&ConfigGroup{
Groups:map<String, *ConfigGroup> {
{{org_name}}:&ConfigGroup{
Values:map<string, *ConfigValue>{
"MSP":msp.MSPConfig,
"AnchorPeers":peer.AnchorPeers,
},
},
},
},
},
}

就像Orderer部分,每一個組織被編碼爲一個組。然而,app channel不只有MSP身份信息,每一個組織都附加了一個AnchorPeers列表。這個列表容許不一樣組織的節點彼此聯繫。

應用程序channel經過對orderer組織和共識選項的編碼,以容許對這些參數進行肯定性更新,所以包含了orderer系統channel配置的相同Orderer部分。但從應用角度看,這會在很大程度上被忽略。

Channel creation / 建立channel

Orderer 接收到對一個不存在的channelCONFIG_UPDATE信息時,orderer就會假設這是個建立channel的請求並執行如下操做:

  1. 經過查看高層組中的Consortium值,orderer標識所要執行建立channel請求的consortium(譯註:這個詞暫時不知翻譯成什麼好)

  2. orderer驗證Application組中的組織是對應的consortium中組織的一部分,並驗證ApplicationGroup的版本是1

  3. orderer驗證consortium是否有成員,新的channel也會有application成員(建立沒有成員的consortiumschannel只用於測試)。

  4. ordererordering系統channel取得Orderer組,並建立一個包含新指定成員的Application組,並將其mod_policy指定爲在consortium config中指定的ChannelCreationPolicy,從而建立一個模板配置。注意,這個策略(mod_policy)是基於新配置的上下文的,所以須要全部成員的策略就是要須要新channel中全部成員的簽名,而不是consortium中的全部成員。

  5. ordererCONFIG_UPDATE更新這個模板配置。由於CONFIG_UPDATE用於Application組(其版本是1)的修改,因此配置碼根據ChannelCreationPolicy驗證這些更新。若是channel建立包含任何其它修改,例如修改單個組織的錨節點,則調用該元素的相應mod策略。

  6. 帶有新channel配置的CONFIG交易被包裝並經過order系統channel發送到orderingordering以後channel就建立完成。

相關文章
相關標籤/搜索