今天讲fabric的创世块的源码 主要围绕这个命令 :export FABRIC_CFG_PATH=$PWD ../bin/configtxgen -profile TwoOrgsOrdererGenesis -outputBlock ./channel-artifacts/genesis.block 生成创世块
main的方法在 /fabric/common/tools/configtxgen包下的
func main() {
//定义变量用户接受命令参数
var outputBlock, outputChannelCreateTx, profile, configPath, channelID, inspectBlock, inspectChannelCreateTx, outputAnchorPeersUpdate, asOrg, printOrg string
flag.StringVar(&outputBlock, "outputBlock", "", "The path to write the genesis block to (if set)")
flag.StringVar(&channelID, "channelID", "", "The channel ID to use in the configtx")
flag.StringVar(&outputChannelCreateTx, "outputCreateChannelTx", "", "The path to write a channel creation configtx to (if set)")
flag.StringVar(&profile, "profile", genesisconfig.SampleInsecureSoloProfile, "The profile from configtx.yaml to use for generation.")
flag.StringVar(&configPath, "configPath", "", "The path containing the configuration to use (if set)")
flag.StringVar(&inspectBlock, "inspectBlock", "", "Prints the configuration contained in the block at the specified path")
flag.StringVar(&inspectChannelCreateTx, "inspectChannelCreateTx", "", "Prints the configuration contained in the transaction at the specified path")
flag.StringVar(&outputAnchorPeersUpdate, "outputAnchorPeersUpdate", "", "Creates an config update to update an anchor peer (works only with the default channel creation, and only for the first update)")
flag.StringVar(&asOrg, "asOrg", "", "Performs the config generation as a particular organization (by name), only including values in the write set that org (likely) has privilege to set")
flag.StringVar(&printOrg, "printOrg", "", "Prints the definition of an organization as JSON. (useful for adding an org to a channel manually)")
version := flag.Bool("version", false, "Show version information")
flag.Parse()//接收到的参数,解析,然后上面所有的变量都会获得相对应的值
if channelID == "" {
channelID = genesisconfig.TestChainID//设置channelId
logger.Warningf("Omitting the channel ID for configtxgen is deprecated. Explicitly passing the channel ID will be required in the future, defaulting to '%s'.", channelID)
}
// show version
if *version {
printVersion()//打印版本信息
os.Exit(exitCode)
}
logging.SetLevel(logging.INFO, "")
// don't need to panic when running via command line
defer func() {
if err := recover(); err != nil {
if strings.Contains(fmt.Sprint(err), "Error reading configuration: Unsupported Config Type") {
logger.Error("Could not find configtx.yaml. " +
"Please make sure that FABRIC_CFG_PATH or --configPath is set to a path " +
"which contains configtx.yaml")
os.Exit(1)
}
if strings.Contains(fmt.Sprint(err), "Could not find profile") {
logger.Error(fmt.Sprint(err) + ". " +
"Please make sure that FABRIC_CFG_PATH or --configPath is set to a path " +
"which contains configtx.yaml with the specified profile")
os.Exit(1)
}
logger.Panic(err)
}
}()
logger.Info("Loading configuration")
factory.InitFactories(nil)//初始化算法工厂
var profileConfig *genesisconfig.Profile
if outputBlock != "" || outputChannelCreateTx != "" || outputAnchorPeersUpdate != "" {
if configPath != "" {
profileConfig = genesisconfig.Load(profile, configPath)//load配置文件
} else {
profileConfig = genesisconfig.Load(profile)
}
}
var topLevelConfig *genesisconfig.TopLevel
if configPath != "" {
topLevelConfig = genesisconfig.LoadTopLevel(configPath)
} else {
topLevelConfig = genesisconfig.LoadTopLevel()
}
//生成创世块
if outputBlock != "" {
if err := doOutputBlock(profileConfig, channelID, outputBlock); err != nil {
logger.Fatalf("Error on outputBlock: %s", err)
}
}
//创建通道配置文件
if outputChannelCreateTx != "" {
if err := doOutputChannelCreateTx(profileConfig, channelID, outputChannelCreateTx); err != nil {
logger.Fatalf("Error on outputChannelCreateTx: %s", err)
}
}
//验证创世块
if inspectBlock != "" {
if err := doInspectBlock(inspectBlock); err != nil {
logger.Fatalf("Error on inspectBlock: %s", err)
}
}
//验证通道配置文件
if inspectChannelCreateTx != "" {
if err := doInspectChannelCreateTx(inspectChannelCreateTx); err != nil {
logger.Fatalf("Error on inspectChannelCreateTx: %s", err)
}
}
//更新Peer节点
if outputAnchorPeersUpdate != "" {
if err := doOutputAnchorPeersUpdate(profileConfig, channelID, outputAnchorPeersUpdate, asOrg); err != nil {
logger.Fatalf("Error on inspectChannelCreateTx: %s", err)
}
}
//打印org
if printOrg != "" {
if err := doPrintOrg(topLevelConfig, printOrg); err != nil {
logger.Fatalf("Error on printOrg: %s", err)
}
}
}
flag 和kingpin的包作用一样,不知道为什么一个源码会有两种命令的生成方式。
我们看一下genesisconfig 这个是在 configtxgen/localconfig/config.go中
func LoadTopLevel(configPaths ...string) *TopLevel {
config := viper.New()//创建一个Viper对象
if len(configPaths) > 0 {
for _, p := range configPaths {
config.AddConfigPath(p)
}
config.SetConfigName(configName)//设置configName
} else {
cf.InitViper(config, configName)如果没有传路径,那就生成一个。
}
// For environment variables
config.SetEnvPrefix(Prefix)//设置环境变量
config.AutomaticEnv()
replacer := strings.NewReplacer(".", "_")//替换
config.SetEnvKeyReplacer(replacer)//设置key
err := config.ReadInConfig()//读取配置文件
if err != nil {
logger.Panic("Error reading configuration: ", err)
}
logger.Debugf("Using config file: %s", config.ConfigFileUsed())
var uconf TopLevel
err = viperutil.EnhancedExactUnmarshal(config, &uconf)//构件DecoderConfig对象
if err != nil {
logger.Panic("Error unmarshaling config into struct: ", err)
}
(&uconf).completeInitialization(filepath.Dir(config.ConfigFileUsed()))//初始化
logger.Infof("Loaded configuration: %s", config.ConfigFileUsed())
return &uconf//返回配置文件
}
再看doOutputBlock()方法
func doOutputBlock(config *genesisconfig.Profile, channelID string, outputBlock string) error {
pgen := encoder.New(config)//配置文件加密
logger.Info("Generating genesis block")
if config.Consortiums == nil {
logger.Warning("Genesis block does not contain a consortiums group definition. This block cannot be used for orderer bootstrap.")
}
genesisBlock := pgen.GenesisBlockForChannel(channelID)//根据通道id生成block.
logger.Info("Writing genesis block")
err := ioutil.WriteFile(outputBlock, utils.MarshalOrPanic(genesisBlock), 0644)//把创世块保存到文件
if err != nil {
return fmt.Errorf("Error writing genesis block: %s", err)
}
return nil
}
然后看一下 encoder.New(config) 方法
func New(config *genesisconfig.Profile) *Bootstrapper {
channelGroup, err := NewChannelGroup(config)//创建一个通道的数组
if err != nil {
logger.Panicf("Error creating channel group: %s", err)
}
return &Bootstrapper{//返回bootstrapper对象
channelGroup: channelGroup,
}
}
然后看一下 NewChannelGroup()方法(生成一个通道分组)
func NewChannelGroup(conf *genesisconfig.Profile) (*cb.ConfigGroup, error) {
if conf.Orderer == nil {//conf配置文件的orderer
return nil, errors.New("missing orderer config section")
}
channelGroup := cb.NewConfigGroup()//创建一个新的对象
if len(conf.Policies) == 0 {
logger.Warningf("Default policy emission is deprecated, please include policy specificiations for the channel group in configtx.yaml")
addImplicitMetaPolicyDefaults(channelGroup)
} else {
if err := addPolicies(channelGroup, conf.Policies, channelconfig.AdminsPolicyKey); err != nil {
return nil, errors.Wrapf(err, "error adding policies to channel group")
}
}
addValue(channelGroup, channelconfig.HashingAlgorithmValue(), channelconfig.AdminsPolicyKey)
addValue(channelGroup, channelconfig.BlockDataHashingStructureValue(), channelconfig.AdminsPolicyKey)
addValue(channelGroup, channelconfig.OrdererAddressesValue(conf.Orderer.Addresses), ordererAdminsPolicyName)
if conf.Consortium != "" {
addValue(channelGroup, channelconfig.ConsortiumValue(conf.Consortium), channelconfig.AdminsPolicyKey)
}
if len(conf.Capabilities) > 0 {
addValue(channelGroup, channelconfig.CapabilitiesValue(conf.Capabilities), channelconfig.AdminsPolicyKey)
}
var err error
channelGroup.Groups[channelconfig.OrdererGroupKey], err = NewOrdererGroup(conf.Orderer)
if err != nil {
return nil, errors.Wrap(err, "could not create orderer group")
}
if conf.Application != nil {
channelGroup.Groups[channelconfig.ApplicationGroupKey], err = NewApplicationGroup(conf.Application)
if err != nil {
return nil, errors.Wrap(err, "could not create application group")
}
}
if conf.Consortiums != nil {
channelGroup.Groups[channelconfig.ConsortiumsGroupKey], err = NewConsortiumsGroup(conf.Consortiums)
if err != nil {
return nil, errors.Wrap(err, "could not create consortiums group")
}
}
channelGroup.ModPolicy = channelconfig.AdminsPolicyKey
return channelGroup, nil
}
我们看一下GenesisBlockForChannel()方法,为通道创建初始化块
func (bs *Bootstrapper) GenesisBlockForChannel(channelID string) *cb.Block {
block, err := genesis.NewFactoryImpl(bs.channelGroup).Block(channelID)
if err != nil {
logger.Panicf("Error creating genesis block from channel group: %s", err)
}
return block
}
这个方法的实现在 、common/genesis/genesis.go中
// NewFactoryImpl creates a new Factory.
func NewFactoryImpl(channelGroup *cb.ConfigGroup) Factory {
return &factory{channelGroup: channelGroup}
}
// Block constructs and returns a genesis block for a given channel ID.
func (f *factory) Block(channelID string) (*cb.Block, error) {
payloadChannelHeader := utils.MakeChannelHeader(cb.HeaderType_CONFIG, msgVersion, channelID, epoch)//创建通道header
payloadSignatureHeader := utils.MakeSignatureHeader(nil, utils.CreateNonceOrPanic())//创建签名header
utils.SetTxID(payloadChannelHeader, payloadSignatureHeader)//设置TXId
payloadHeader := utils.MakePayloadHeader(payloadChannelHeader, payloadSignatureHeader)
payload := &cb.Payload{Header: payloadHeader, Data: utils.MarshalOrPanic(&cb.ConfigEnvelope{Config: &cb.Config{ChannelGroup: f.channelGroup}})}
envelope := &cb.Envelope{Payload: utils.MarshalOrPanic(payload), Signature: nil}
block := cb.NewBlock(0, nil)//生成创世块
block.Data = &cb.BlockData{Data: [][]byte{utils.MarshalOrPanic(envelope)}}
block.Header.DataHash = block.Data.Hash()
block.Metadata.Metadata[cb.BlockMetadataIndex_LAST_CONFIG] = utils.MarshalOrPanic(&cb.Metadata{
Value: utils.MarshalOrPanic(&cb.LastConfig{Index: 0}),
})
return block, nil
}
先讲到证书的创世块的生成。里面有很多不是很明了的东西,后面我们会再做一个详细的讲解。