fabric源码阅读第二篇上

今天讲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
}

先讲到证书的创世块的生成。里面有很多不是很明了的东西,后面我们会再做一个详细的讲解。

你可能感兴趣的:(fabric源码阅读第二篇上)