Channel提供了多賬本的功能姻几,我們創(chuàng)建Channel時首先就是要配置聯(lián)盟和Channel中包含的組織敛纲,之后使用configtxgen生成Channel文件,這個文件內(nèi)部其實就是創(chuàng)建賬本所需要的配置更新。
1.使用
從fabric源碼中復(fù)制一份configtx拜鹤,對其進(jìn)行修改
cp $GOPATH/src/github.com/hyperledger/fabric/sampleconfig/configtx.yaml .
設(shè)置一個生成Channe的配置闽巩,OrdererOrg/CoreOrg/SupplierOrg/BankOrg需要進(jìn)行配置钧舌,在此省略
TestTwoOrgsChannel:
Consortium: SampleConsortium
Application:
Organizations:
- *CoreOrg
- *SupplierOrg
- *BankOrg
最后,使用下面的命令就可以生成創(chuàng)世塊了
configtxgen -profile TestTwoOrgsChannel -outputCreateChannelTx ./mychannel.tx -channelID mychannel
2.程序分析
configtxgen的程序在common/tools/configtxgen/main.go
中涎跨,主要的功能是獲取配置文件洼冻,生成ConfigUpdate,包裝為一個ConfigUpdate的交易并寫入文件隅很。主流程是:
- factory.InitFactories(nil) 初始化BCCSP撞牢,用來為加密提供服務(wù)。
- 獲取指定profile的配置叔营,將其序列化為Profile類型屋彪。
- 我們設(shè)置了outputChannelCreateTx,因此會執(zhí)行doOutputChannelCreateTx方法绒尊。
- 創(chuàng)建一個用來創(chuàng)建Channel的交易畜挥,將其寫入文件。
2.1 創(chuàng)建Channel的交易文件
有了Profile配置婴谱,首先創(chuàng)建一個ConfigUpdate蟹但,將其包裝到ConfigUpdateEnvelope中,之后序列化作為Data勘究,添加Header后形成Payload矮湘,最后添加簽名,封裝為Envelope并返回口糕。
因此缅阳,我們需要將主要邏輯聚焦于ConfigUpdate的內(nèi)容。
2.2 ConfigGroup
NewChannelCreateConfigUpdate
方法會生成一個ConfigUpdate,ConfigUpdate會被發(fā)送到orderer來創(chuàng)建一個新的Channel十办,該方法根據(jù)指定的profile的配置中的Application秀撇,創(chuàng)建Application的ConfigGroup,ConfigGroup可以理解為一個配置樹型向族,Application中包含了Organizations呵燕,Organizations中是三個Org,因此件相,最終會形成一個Application的配置樹再扭。ConfigGroup的結(jié)構(gòu)可以參考ConfigGroup,Application的Groups中是組織的配置夜矗,在NewApplicationOrgGroup
中泛范,會對Org的配置組裝,讀取并驗證MSP的相關(guān)證書紊撕。
2.3 ConfigUpdate
上面只是將配置轉(zhuǎn)化為ConfigGroup組成的配置樹罢荡,接下來就是計算ConfigUpdate了,也就是計算配置有那些更新对扶。計算的程序如下区赵,首先會創(chuàng)建一個新的ConfigGroup,其Groups子配置有一個Application
浪南,對應(yīng)這我們之前生成的Application的Config笼才,這是因為在TestTwoOrgsChannel
中,Application是作為一個子級逞泄,需要將其放在一個Root配置下患整。
newChannelGroup = &cb.ConfigGroup{
Groups: map[string]*cb.ConfigGroup{
channelconfig.ApplicationGroupKey: ag,
},
}
template = proto.Clone(newChannelGroup).(*cb.ConfigGroup)
template.Groups[channelconfig.ApplicationGroupKey].Values = nil
template.Groups[channelconfig.ApplicationGroupKey].Policies = nil
之后,克隆了一份新創(chuàng)建的ConfigGroup喷众,將其Application
的子ConfigGroup的Value和Policy設(shè)置為nil各谚,之前我們在2.2節(jié)構(gòu)造ConfigGroup時,ConfigGroup會設(shè)置默認(rèn)的一些Ploicy到千,如果配置了Capabilities昌渤,已經(jīng)設(shè)置Value
addImplicitMetaPolicyDefaults(applicationGroup)
if len(conf.Capabilities) > 0 {
addValue(applicationGroup, channelconfig.CapabilitiesValue(conf.Capabilities), channelconfig.AdminsPolicyKey)
}
template的修改勢必會造成配置發(fā)生變化,因此下一步就是計算兩個ConfigGroup的更新了憔四,我們以template作為原來的配置膀息,newChannelGroup最為更新之后的配置,計算哪些配置發(fā)生了更新了赵。雖然這里我們還容易看出來發(fā)生了那些變化潜支,但是為了統(tǒng)一處理,還是進(jìn)行了計算(如果設(shè)置了orderingSystemChannelGroup的話柿汛,template的方式就不是這么簡單的克隆后修改了)冗酿。
計算方法
主要是遍歷原ConfigGroup的Policy,Value和ConfigGroup,將未發(fā)生變化的部分保存到sameSet裁替,發(fā)送變化后的配置保存到writeSet中且版本號加1项玛。最后,如果未發(fā)生變化弱判,返回的ConfigUpdate的ReadSet和WriteSet均為nil襟沮,如果發(fā)生了變化,將sameSet分別賦值給ReadSet和WriteSet昌腰,保證未發(fā)生變化的部分在兩個Set中都存在开伏。這樣我們就知道了發(fā)生變化前后的配置。
根據(jù)之前template的生成方式遭商,我們可以查看最后的讀寫集合
在上圖中硅则,ReadSet的Application的version為0,WriteSet中version為1,說明發(fā)生了變化,通過觀察株婴,我們看到ConfigGroup的Policies發(fā)生了變化,這與template的修改相符合暑认。其實最終的ConfigUpdate就是要通知困介,Application的Policy發(fā)生了變化,如果設(shè)置了某些配置參數(shù)的話蘸际,Value也會發(fā)生變化座哩。
計算出來ConfigUpdate,最后封裝為Envelope后粮彤,寫入文件中根穷,整個流程就結(jié)束了。