Fabric源码分析-生成创世块

Orderer节点启动时,需要为其指定创世块,创世块其实就是我们在配置文件中设置的相关配置,将其组装为树型的ConfigGroup后,再封装为Enveloper,最后生成Block,保存到指定的文件中。

1.使用

从fabric源码中复制一份configtx,对其进行修改

cp $GOPATH/src/github.com/hyperledger/fabric/sampleconfig/configtx.yaml .

设置一个生成Genesis的配置,OrdererOrg/CoreOrg/SupplierOrg/BankOrg需要进行配置,在此省略

TestTwoOrgsOrdererGenesis:
        Orderer:
            <<: *OrdererDefaults
            Organizations:
                - *OrdererOrg
        Consortiums:
            SampleConsortium:
                Organizations:
                    - *CoreOrg
                    - *SupplierOrg
                    - *BankOrg

最后,使用下面的命令就可以生成创世块了

configtxgen -profile TestTwoOrgsOrdererGenesis -outputBlock ./orderer.genesis.block

2.程序分析

configtxgen的入口在common/tools/configtxgen/main.go中,在main方法中,

  1. 首先会 使用factory.InitFactories(nil)获取bccsp服务,bccsp用于后续的加密。
  2. 使用genesisconfig.Load(profile)加载指定的profile的配置,放在local.Profile中保存。
  3. 使用genesisconfig.LoadTopLevel()获取顶层的所有配置。
  4. 使用doOutputBlock生成创世块。

2.1 ChannelGroup

有了相关的配置之后,需要将配置保存在common.ChannelGroup中,ChannelGroup是一个树形的结构,每个节点有若干子ChannelGroup,ChannelGroup的结构如下。所以我们首先要做的就是创建一个Root根ChannelGroup。

type ConfigGroup struct {
    Version   uint64                   
    Groups    map[string]*ConfigGroup  
    Values    map[string]*ConfigValue  
    Policies  map[string]*ConfigPolicy 
    ModPolicy string                   
}

其中,Version是配置的版本号;Groups是所有的子配置,也是ConfigGroup类型,Values是配置的值,ConfigPolicy是策略,ModPolicy是修改策略。
对于ConfigValue和ConfigPolicy来说,他们是字符串和Policy的包装,因为每个value和policy都需要有自己的版本号和ModPolicy。

type ConfigValue struct {
    Version   uint64 
    Value     []byte 
    ModPolicy string 
}
type ConfigPolicy struct {
    Version   uint64  
    Policy    *Policy 
    ModPolicy string  
}

Policy包含Type和一个Value,Type的目的是为了预留,后续可能需要多个策略引擎。

ChannelGroup创建后,有默认的一些配置,如Policies属性会先添加三个默认的Policy,Value分别为AdminReaderWriters,这三个ConfigPolicy的ModPolicy均为Admins
除此之外,还有三个Values,分别是

HashingAlgorithm  SHA256  // HASH算法,修改策略为`Admins`
BlockDataHashingStructure   math.MaxUint32 //区块的最大大小,修改策略为`Admins`
OrdererAddresses  conf.Orderer.Addresses  // Orderer的地址,/Channel/Orderer/Admins,只有channel的orderer的admin可以修改

最后,会根据我们的配置文件,为ChannelGroup添加Orderer,Application和Consortiums的子ChannelGroup,即,这三个key下都有自己的配置,根据配置会生成各自的ChannelGroup子树。例如,对于

Orderer -> 
  key = {string} "Orderer"
     Version = {uint64} 0
     Groups = 
        0 = OrdererMSP ->  里面还是ChannelGroup
     Values = 
        0 = ConsensusType -> 
        1 = BatchSize -> 
        2 = BatchTimeout -> 
        3 = ChannelRestrictions -> 
     Policies =  
     ModPolicy = {string} "Admins"

2.2 生成Block

有了 ChannelGroup之后,将其封装到Bootstrapper中,然后GenesisBlockForChannel生成Block,生成过程就是将ChannelGroup封装为Envelope,然后生成Block。

Fabric源码分析-生成创世块_第1张图片
创世块结构

Block
Block就代表了一个区块,Block的结构定义在protos/common/common.pb.go

type Block struct {
  Header   *BlockHeader   
  Data     *BlockData     
  Metadata *BlockMetadata 
}

其中BlockHeader中包含了区块编号,上一个区块的Hash值,当前区块Data的Hash值。

type BlockHeader struct {
  Number       uint64 
  PreviousHash []byte 
  DataHash     []byte 
}

BlockData中包含了一个字符串数组,每个元素可以认为是一个交易,但是内部的数据需要根据不同场景进行反序列化。

type BlockData struct {
  Data [][]byte 
}

BlockMetadata也是一个字符串数组,保存区块的元数据

type BlockMetadata struct {
    Metadata [][]byte 
}

Envelope
Envelope的意思是将数据加密后,添加签名,因此其结构很简单,Payload是信封里的内容,Signature是发送者的签名

type Envelope struct {
  Payload []byte 
  Signature []byte 
}

Payload
Payload的意思是有效负载,就是我们需要放入的内容,包括Header和data

type Payload struct {
  Header *Header `protobuf:"bytes,1,opt,name=header" json:"header,omitempty"`
  Data []byte `protobuf:"bytes,2,opt,name=data,proto3" json:"data,omitempty"`
}

对header来说,由两个部分组成,分别是ChannelHeader和SignatureHeader

type Header struct {
  ChannelHeader   []byte 
  SignatureHeader []byte 
}

其中,ChannelHeader用来保存Channel和版本,类型,此处的类型是Config

type ChannelHeader struct {
  Type int32 
  Version int32 
  Timestamp *google_protobuf.Timestamp 
  ChannelId string
  Epoch uint64 
  Extension []byte 
  TlsCertHash []byte 
}

所有的HeaderType如下,用于反序列化Envelope中的内容,类型不同,反序列化后的结构也不相同。

const (
    HeaderType_MESSAGE              HeaderType = 0
    HeaderType_CONFIG               HeaderType = 1
    HeaderType_CONFIG_UPDATE        HeaderType = 2
    HeaderType_ENDORSER_TRANSACTION HeaderType = 3
    HeaderType_ORDERER_TRANSACTION  HeaderType = 4
    HeaderType_DELIVER_SEEK_INFO    HeaderType = 5
    HeaderType_CHAINCODE_PACKAGE    HeaderType = 6
    HeaderType_PEER_RESOURCE_UPDATE HeaderType = 7
)

SignatureHeader内部保存了创建者和nonce

type SignatureHeader struct {
  Creator []byte 
  Nonce []byte 
}

ConfigEnvelope
ConfigEnvelope是对config的包装,config内部包含了我们生成的ConfigGroup树

type ConfigEnvelope struct {
  Config     *Config   
  LastUpdate *Envelope 
}
type Config struct {
  Sequence     uint64       
  ChannelGroup *ConfigGroup 
  Type         int32        
}

你可能感兴趣的:(Fabric源码分析-生成创世块)