一個超級帳本區塊鏈網絡裏每一個channel的共享配置都是存儲在一個配置交易裏。每一個配置交易一般被簡稱爲configtx。golang
Channel 配置有如下重要屬性:網絡
1、有版本標識:配置裏的全部元素都有一個關聯版本。每次更新配置,版本號都維持最新。另外,每一個提交的配置會得到一個序列號。app
2、有權限:配置裏的每一個元素都有一個關聯策略,用來管理是否容許對這個元素進行修改。每個保存有當前配置副本的實例,都會按照關聯策略的內容對新收到的配置改動進行驗證權限。區塊鏈
3、層次性:一個配置根組包含多個子組,而且層次中的每一個組都有關聯的值和策略。較低層次能夠獲取上層的策略。測試
配置分析ui
配置做爲一個HeaderType_CONFIG
類型的交易
存儲在一個不包含其餘交易的區塊中。這些區塊被稱爲Configuration Blocks,全部區塊中的第一個區塊稱爲genesis block。this
配置的樣例存儲在fabric/protos/common/configtx.proto
。
HeaderType_CONFIG
類型的
Env
elope
編碼
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;
}
seq
uence
的值在每次提交配置後加
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;
}
注意值、策略和組都有一個version和mod_policy字段。一個元素的version在每次更改後遞增。mod_policy用來管理修改元素的簽名。對於組,更改就是添加或者移除Values、Policies、或者組地圖(或者修改mod_policy)。對於Values和Policies,修改就是改變修改Value或者Policy字段(或者修改mod_policy)。每一個元素的mod_policy在當前當前元素中有效
下面是一個定義在Channel.Groups["Application"]
中的策略的示例(這裏用的是golang語法,所以Channel.Groups["Application"].Policies["policy1"]
表示根組Channel
的子組Application
的Policies
裏的policy1
對應的策略)
policy1
對應Channel.Groups["Application"].Policies["policy1"]
Org1/policy2
對應Channel.Groups["Application"].Groups["Org1"].Policies["policy2"]
/Channel/policy3
對應Channel.Policies["policy3"]
注意,若是mod_policy
引用了一個不存在的策略,那麼該元素不可修改。
更新配置是提交一個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.value
和ConfigPolicy.policy
等其餘字段不包含在read_set
中。ConfigGroup
會map字段組成的子集,以便引用配置樹的深層元素。例如,爲使Application
group包含到read_set
,它的上層(Channel
group)也必須包含到read_set
中,但沒必要將Channel
group中全部的key都包括進去,好比Orderer``group
或者任何values
或policies
。
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
結果:
校驗channel_id
和read_set
,read_set
中全部元素必須存在對應的版本。
收集read_set
與write_set
中版本不一致的元素,計算更新集。
校驗更新集中的元素的版本號是否遞增1
校驗更新集中每一個元素,ConfigUpdateEnvelope
的簽名知足mod_policy
。
經過將更新集應用於當前配置,計算該配置的完整新版本
將新配置寫成ConfigEnvelope
做爲CONFIG_UPDATE
賦給last_update
字段,新的配置賦給config
字段,sequence
字段自增。
將ConfigEnvelope
寫成CONFIG
類型的Envelope
,最終將此做爲惟一交易寫入配置區塊。
當peer(或者任意其餘接收Deliver
者)接收到這個配置區塊後,就會經過將last_update
信息應用到當前配置並校驗orderer計算的config
字段是否包含正確的新配置,來驗證該配置是否被正確校驗。
有效的配置都是下面配置的子集。在此,用peer.<MSG>
表示一個ConfigValue
,其value
字段是稱爲<MSG>
的序列化後的信息,定義在fabric/protos/peer/configuration.proto
。common.<MSG>
,msp.<MSG>
和orderer.<MSG>
分別定義在fabric/protos/common/configuration.proto
,fabric/protos/msp/mspconfig.proto
和fabric/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,
},
}
ordering系統channel定義了建立channel的ordering參數和consortiums。ordering 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來標識系統channel。consortiums組結構以下。
&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建立更信息的內容,請參閱文檔後面的內容。
應用程序配置用於爲應用類型交易設計的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
部分。但從應用角度看,這會在很大程度上被忽略。
當Orderer 接收到對一個不存在的channel的CONFIG_UPDATE
信息時,orderer就會假設這是個建立channel的請求並執行如下操做:
經過查看高層組中的Consortium
值,orderer標識所要執行建立channel請求的consortium(譯註:這個詞暫時不知翻譯成什麼好)。
orderer驗證Application組中的組織是對應的consortium中組織的一部分,並驗證ApplicationGroup
的版本是1。
orderer驗證consortium是否有成員,新的channel也會有application成員(建立沒有成員的consortiums和channel只用於測試)。
orderer從ordering系統channel取得Orderer
組,並建立一個包含新指定成員的Application
組,並將其mod_policy
指定爲在consortium config中指定的ChannelCreationPolicy
,從而建立一個模板配置。注意,這個策略(mod_policy)是基於新配置的上下文的,所以須要全部成員的策略就是要須要新channel中全部成員的簽名,而不是consortium中的全部成員。
orderer用CONFIG_UPDATE
更新這個模板配置。由於CONFIG_UPDATE
用於Application
組(其版本是1)的修改,因此配置碼根據ChannelCreationPolicy
驗證這些更新。若是channel建立包含任何其它修改,例如修改單個組織的錨節點,則調用該元素的相應mod策略。
帶有新channel配置的CONFIG
交易被包裝並經過order系統channel發送到ordering,ordering以後channel就建立完成。