fabric源码阅读第一篇下

上次讲到了TlsCA证书的生成。下面我们继续向下来,在回到

main.go 中的generatePeerOrg()方法,
err = msp.GenerateVerifyingMSP(mspDir, signCA, tlsCA, orgSpec.EnableNodeOUs)
if err != nil {
   fmt.Printf("Error generating MSP for org %s:\n%v\n", orgName, err)
   os.Exit(1)
}

GenerateVerifyingMSP()方法,把msp的目录,singCA,tlsCa org的描述参数,出入进去。

func GenerateVerifyingMSP(baseDir string, signCA *ca.CA, tlsCA *ca.CA, nodeOUs bool) error {

   // create folder structure and write artifacts to proper locations
   err := createFolderStructure(baseDir, false)//创建目录
   if err == nil {
      // the signing CA certificate goes into cacerts
      err = x509Export(filepath.Join(baseDir, "cacerts", x509Filename(signCA.Name)), signCA.SignCert)//导出为pem根式的签名证书
      if err != nil {
         return err
      }
      // the TLS CA certificate goes into tlscacerts
      err = x509Export(filepath.Join(baseDir, "tlscacerts", x509Filename(tlsCA.Name)), tlsCA.SignCert)//导出为pem格式的tlsCA证书
      if err != nil {
         return err
      }
   }

   // generate config.yaml if required
   if nodeOUs {//如果为真,那么久导出配置文件到基本目录
      exportConfig(baseDir, "cacerts/"+x509Filename(signCA.Name), true)
   }

   // create a throwaway cert to act as an admin cert
   // NOTE: the admincerts folder is going to be
   // cleared up anyway by copyAdminCert, but
   // we leave a valid admin for now for the sake
   // of unit tests
   factory.InitFactories(nil)//工厂初始化
   bcsp := factory.GetDefault()//获得默认的算法csp
   priv, err := bcsp.KeyGen(&bccsp.ECDSAP256KeyGenOpts{Temporary: true})//生成临时的私钥
   ecPubKey, err := csp.GetECPublicKey(priv)//获得公钥
   if err != nil {
      return err
   }
//用这对临时的key签名admincerts的证书,这就是JDK为什么enroll的时候会在数据库中certs表中增加一个证书,应为签发的是临时证书。
   _, err = signCA.SignCertificate(filepath.Join(baseDir, "admincerts"), signCA.Name,
      nil, nil, ecPubKey, x509.KeyUsageDigitalSignature, []x509.ExtKeyUsage{})
   if err != nil {
      return err
   }

   return nil
}
返回之后 如果没有错误,那么我们到处了ca证书,tls证书,生成了admin的临时证书,然后调用generateNodes()方法
generateNodes(peersDir, orgSpec.Specs, signCA, tlsCA, msp.PEER, orgSpec.EnableNodeOUs)//msp.PEER表明的类型
func generateNodes(baseDir string, nodes []NodeSpec, signCA *ca.CA, tlsCA *ca.CA, nodeType int, nodeOUs bool) {

   for _, node := range nodes {//循环所有的nodes
      nodeDir := filepath.Join(baseDir, node.CommonName)//产生路径
      if _, err := os.Stat(nodeDir); os.IsNotExist(err) {/判断这个文件夹是否存在
         err := msp.GenerateLocalMSP(nodeDir, node.CommonName, node.SANS, signCA, tlsCA, nodeType, nodeOUs)//然后给每个组织生成admin临时证书
         if err != nil {
            fmt.Printf("Error generating local MSP for %s:\n%v\n", node, err)
            os.Exit(1)//如果错误,退出
         }
      }
   }
}

然后生成用户的名称。

users := []NodeSpec{}
for j := 1; j <= orgSpec.Users.Count; j++ {
   user := NodeSpec{
      CommonName: fmt.Sprintf("%s%d@%s", userBaseName, j, orgName),
   }

   users = append(users, user)
}

//生成admin的用户

adminUser := NodeSpec{
   CommonName: fmt.Sprintf("%s@%s", adminBaseName, orgName),
}
users = append(users, adminUser)//把admin用户添加到users中
generateNodes(usersDir, users, signCA, tlsCA, msp.CLIENT, orgSpec.EnableNodeOUs)//生成的类型为msp.client

根据类型不同,最后生keyStore会区分是client 、还是server端,以及crt文件。

// copy the admin cert to the org's MSP admincerts
err = copyAdminCert(usersDir, adminCertsDir, adminUser.CommonName)//把不同的组织的域名的admin复制到自己所属的目录。
if err != nil {
   fmt.Printf("Error copying admin cert for org %s:\n%v\n",
      orgName, err)
   os.Exit(1)
}

我们来看一下copyAdminCert()方法

func copyAdminCert(usersDir, adminCertsDir, adminUserName string) error {
   if _, err := os.Stat(filepath.Join(adminCertsDir,
      adminUserName+"-cert.pem")); err == nil {//copyadmin的cert.pem证书
      return nil
   }
   // delete the contents of admincerts
   err := os.RemoveAll(adminCertsDir)//删除adminCertsDir下的所有的东西
   if err != nil {
      return err
   }
   // recreate the admincerts directory
   err = os.MkdirAll(adminCertsDir, 0755)//创建目录
   if err != nil {
      return err
   }
   err = copyFile(filepath.Join(usersDir, adminUserName, "msp", "signcerts",
      adminUserName+"-cert.pem"), filepath.Join(adminCertsDir,
      adminUserName+"-cert.pem"))//把msp目中G的签名证书中的admin的证书,赋值到adminCertDir的目录中。
   if err != nil {
      return err
   }
   return nil

}

再回到 generatePeerOrg()方法中 调用

for _, spec := range orgSpec.Specs {//循环所有的OrgSpec.Specs
   err = copyAdminCert(usersDir,
      filepath.Join(peersDir, spec.CommonName, "msp", "admincerts"), adminUser.CommonName)//复制peer的证书到msp中。
   if err != nil {
      fmt.Printf("Error copying admin cert for org %s peer %s:\n%v\n",
         orgName, spec.CommonName, err)
      os.Exit(1)
   }
}

要循环的内容如下:

# Specs:
#   - Hostname: foo # implicitly "foo.org1.example.com"
#     CommonName: foo27.org5.example.com # overrides Hostname-based FQDN set above
#     SANS:
#       - "bar.{{.Domain}}"
#       - "altfoo.{{.Domain}}"
#       - "{{.Hostname}}.org6.net"
#       - 172.16.10.31
#   - Hostname: bar
#   - Hostname: baz

此段内容做什么尚未搞清楚,等搞清楚我会详细的说明一下

到此 generatePeerOrg()方法讲完。我们再回到 generate()方法,我们继续看一个方法

for _, orgSpec := range config.OrdererOrgs {//然后循环所有的Order标签
   err = renderOrgSpec(&orgSpec, "orderer")//生成配置文件
   if err != nil {
      fmt.Printf("Error processing orderer configuration: %s", err)
      os.Exit(-1)
   }
   generateOrdererOrg(*outputDir, orgSpec)//然后生成OrderOrg证书
}

我们看一下 generateOrdererOrg()方法和  generatePeerOrg()方法的区别,为什么要写成两个

func generateOrdererOrg(baseDir string, orgSpec OrgSpec) {

   orgName := orgSpec.Domain

   // generate CAs
   orgDir := filepath.Join(baseDir, "ordererOrganizations", orgName)//目录不一样
   caDir := filepath.Join(orgDir, "ca")
   tlsCADir := filepath.Join(orgDir, "tlsca")
   mspDir := filepath.Join(orgDir, "msp")
   orderersDir := filepath.Join(orgDir, "orderers")
   usersDir := filepath.Join(orgDir, "users")
   adminCertsDir := filepath.Join(mspDir, "admincerts")
   // generate signing CA
   signCA, err := ca.NewCA(caDir, orgName, orgSpec.CA.CommonName, orgSpec.CA.Country, orgSpec.CA.Province, orgSpec.CA.Locality, orgSpec.CA.OrganizationalUnit, orgSpec.CA.StreetAddress, orgSpec.CA.PostalCode)//一样生成证书
   if err != nil {
      fmt.Printf("Error generating signCA for org %s:\n%v\n", orgName, err)
      os.Exit(1)
   }
   // generate TLS CA
   tlsCA, err := ca.NewCA(tlsCADir, orgName, "tls"+orgSpec.CA.CommonName, orgSpec.CA.Country, orgSpec.CA.Province, orgSpec.CA.Locality, orgSpec.CA.OrganizationalUnit, orgSpec.CA.StreetAddress, orgSpec.CA.PostalCode)//一样生成TLS证书
   if err != nil {
      fmt.Printf("Error generating tlsCA for org %s:\n%v\n", orgName, err)
      os.Exit(1)
   }

   err = msp.GenerateVerifyingMSP(mspDir, signCA, tlsCA, false)//这里直接设置成了false.只是把证书主题中的OrganizationalUnit字段的值不一样。无其他作用
   if err != nil {
      fmt.Printf("Error generating MSP for org %s:\n%v\n", orgName, err)
      os.Exit(1)
   }

   generateNodes(orderersDir, orgSpec.Specs, signCA, tlsCA, msp.ORDERER, false)//这里也是类似上面的作用

//这里只有添加admin用户的
   adminUser := NodeSpec{
      CommonName: fmt.Sprintf("%s@%s", adminBaseName, orgName),
   }

   // generate an admin for the orderer org
   users := []NodeSpec{}
   // add an admin user
   users = append(users, adminUser)//把admin用户添加到user
   generateNodes(usersDir, users, signCA, tlsCA, msp.CLIENT, false)//生成证书

   // copy the admin cert to the org's MSP admincerts
   err = copyAdminCert(usersDir, adminCertsDir, adminUser.CommonName)//复制admin的证书
   if err != nil {
      fmt.Printf("Error copying admin cert for org %s:\n%v\n",
         orgName, err)
      os.Exit(1)
   }

   // copy the admin cert to each of the org's orderers's MSP admincerts
   for _, spec := range orgSpec.Specs {//类似 generatePeerOrg中的方法,这里不做多做详解
      err = copyAdminCert(usersDir,
         filepath.Join(orderersDir, spec.CommonName, "msp", "admincerts"), adminUser.CommonName)
      if err != nil {
         fmt.Printf("Error copying admin cert for org %s orderer %s:\n%v\n",
            orgName, spec.CommonName, err)
         os.Exit(1)
      }
   }

}

到此 generate()方法解析完毕,对应的文档上的命令是:../bin/cryptogen generate --config=./crypto-config.yaml

================================================================================================下面讲解 ../bin/cryptogen extend --config=./crypto-config.yaml 命令,增加组织的配置文件

main方法中 extend()方法 
func extend() {
   config, err := getConfig()//获得配置文件 类似generate()方法
   if err != nil {
      fmt.Printf("Error reading config: %s", err)
      os.Exit(-1)
   }

   for _, orgSpec := range config.PeerOrgs {//循环所有的PeerOrgs,只不过这里设置了start参数。
      err = renderOrgSpec(&orgSpec, "peer")//同generate()方法一样
      if err != nil {
         fmt.Printf("Error processing peer configuration: %s", err)
         os.Exit(-1)
      }
      extendPeerOrg(orgSpec)//扩展组织
   }

   for _, orgSpec := range config.OrdererOrgs {//循环OrderOrg
      err = renderOrgSpec(&orgSpec, "orderer")
      if err != nil {
         fmt.Printf("Error processing orderer configuration: %s", err)
         os.Exit(-1)
      }
      extendOrdererOrg(orgSpec)//货站Order
   }

}

我们来看一下 extendPeerOrg()方法

func extendPeerOrg(orgSpec OrgSpec) {
   orgName := orgSpec.Domain
   orgDir := filepath.Join(*inputDir, "peerOrganizations", orgName)
   if _, err := os.Stat(orgDir); os.IsNotExist(err) {
      generatePeerOrg(*inputDir, orgSpec)
      return
   }

   peersDir := filepath.Join(orgDir, "peers")
   usersDir := filepath.Join(orgDir, "users")
   caDir := filepath.Join(orgDir, "ca")
   tlscaDir := filepath.Join(orgDir, "tlsca")

   signCA := getCA(caDir, orgSpec, orgSpec.CA.CommonName)//获得Ca证书
   tlsCA := getCA(tlscaDir, orgSpec, "tls"+orgSpec.CA.CommonName)//获得TlsCa证书

   generateNodes(peersDir, orgSpec.Specs, signCA, tlsCA, msp.PEER, orgSpec.EnableNodeOUs)//上面已经讲过了

   adminUser := NodeSpec{//admin用户
      CommonName: fmt.Sprintf("%s@%s", adminBaseName, orgName),
   }
   // copy the admin cert to each of the org's peer's MSP admincerts
   for _, spec := range orgSpec.Specs {//
      err := copyAdminCert(usersDir,
         filepath.Join(peersDir, spec.CommonName, "msp", "admincerts"), adminUser.CommonName)
      if err != nil {
         fmt.Printf("Error copying admin cert for org %s peer %s:\n%v\n",
            orgName, spec.CommonName, err)
         os.Exit(1)
      }
   }

   // TODO: add ability to specify usernames
   users := []NodeSpec{}
   for j := 1; j <= orgSpec.Users.Count; j++ {
      user := NodeSpec{
         CommonName: fmt.Sprintf("%s%d@%s", userBaseName, j, orgName),
      }

      users = append(users, user)
   }

   generateNodes(usersDir, users, signCA, tlsCA, msp.CLIENT, orgSpec.EnableNodeOUs)//生成临时证书 类型为MSP.Client
}

我们看一下getCa()方法

func getCA(caDir string, spec OrgSpec, name string) *ca.CA {
   _, signer, _ := csp.LoadPrivateKey(caDir)//根据证书额加载私钥,获得签名
   cert, _ := ca.LoadCertificateECDSA(caDir)//获得ECDSA证书

   return &ca.CA{//返回证书对象
      Name:               name,
      Signer:             signer,
      SignCert:           cert,
      Country:            spec.CA.Country,
      Province:           spec.CA.Province,
      Locality:           spec.CA.Locality,
      OrganizationalUnit: spec.CA.OrganizationalUnit,
      StreetAddress:      spec.CA.StreetAddress,
      PostalCode:         spec.CA.PostalCode,
   }
}

然后看一下LoadPrivateKey()方法

func LoadPrivateKey(keystorePath string) (bccsp.Key, crypto.Signer, error) {
   var err error
   var priv bccsp.Key
   var s crypto.Signer

   opts := &factory.FactoryOpts{//初始化算法工厂的参数
      ProviderName: "SW",
      SwOpts: &factory.SwOpts{
         HashFamily: "SHA2",
         SecLevel:   256,

         FileKeystore: &factory.FileKeystoreOpts{
            KeyStorePath: keystorePath,
         },
      },
   }

   csp, err := factory.GetBCCSPFromOpts(opts)//获得csp
   if err != nil {
      return nil, nil, err
   }

   walkFunc := func(path string, info os.FileInfo, err error) error {
      if strings.HasSuffix(path, "_sk") {
         rawKey, err := ioutil.ReadFile(path)
         if err != nil {
            return err
         }//读取keyStore的文件

         block, _ := pem.Decode(rawKey)//pem格式解密
         priv, err = csp.KeyImport(block.Bytes, &bccsp.ECDSAPrivateKeyImportOpts{Temporary: true})//导入key,设置为临时的
         if err != nil {
            return err
         }

         s, err = signer.New(csp, priv)//重新签名返回证书
         if err != nil {
            return err
         }

         return nil
      }
      return nil
   }

   err = filepath.Walk(keystorePath, walkFunc)
   if err != nil {
      return nil, nil, err
   }

   return priv, s, err
}

然后返回到 getCA()方法中 我们查看 LoadCertificateECDSA()方法

func LoadCertificateECDSA(certPath string) (*x509.Certificate, error) {
   var cert *x509.Certificate
   var err error

   walkFunc := func(path string, info os.FileInfo, err error) error {
      if strings.HasSuffix(path, ".pem") {
         rawCert, err := ioutil.ReadFile(path)
         if err != nil {
            return err
         }//读取证书
         block, _ := pem.Decode(rawCert)
         cert, err = utils.DERToX509Certificate(block.Bytes)//使用DER申城证书
      }
      return nil
   }

   err = filepath.Walk(certPath, walkFunc)
   if err != nil {
      return nil, err
   }

   return cert, err//返回证书
}

我们再回到 extend()方法中 查看一下extendOrdererOrg()方法

func extendOrdererOrg(orgSpec OrgSpec) {
   orgName := orgSpec.Domain

   orgDir := filepath.Join(*inputDir, "ordererOrganizations", orgName)
   caDir := filepath.Join(orgDir, "ca")
   usersDir := filepath.Join(orgDir, "users")
   tlscaDir := filepath.Join(orgDir, "tlsca")
   orderersDir := filepath.Join(orgDir, "orderers")
   if _, err := os.Stat(orgDir); os.IsNotExist(err) {
      generateOrdererOrg(*inputDir, orgSpec)//不做说明
      return
   }

   signCA := getCA(caDir, orgSpec, orgSpec.CA.CommonName)//上面已经说过了
   tlsCA := getCA(tlscaDir, orgSpec, "tls"+orgSpec.CA.CommonName)//上面已近说过了

   generateNodes(orderersDir, orgSpec.Specs, signCA, tlsCA, msp.ORDERER, false)

   adminUser := NodeSpec{
      CommonName: fmt.Sprintf("%s@%s", adminBaseName, orgName),
   }

   for _, spec := range orgSpec.Specs {
      err := copyAdminCert(usersDir,
         filepath.Join(orderersDir, spec.CommonName, "msp", "admincerts"), adminUser.CommonName)
      if err != nil {
         fmt.Printf("Error copying admin cert for org %s orderer %s:\n%v\n",
            orgName, spec.CommonName, err)
         os.Exit(1)
      }
   }
}

到此命令../bin/cryptogen extend--config=./crypto-config.yaml的方法已经讲解完毕,我们明天讲解初始块的生成。

猜你喜欢

转载自blog.csdn.net/qq_15693861/article/details/81172533