Fabric 1.0原始碼分析(32)Peer #peer根命令入口及載入子命令
# Fabric 1.0原始碼筆記 之 Peer #peer根命令入口及載入子命令
## 1、載入環境變數配置和配置檔案
Fabric支援通過環境變數對部分配置進行更新,如:CORE_LOGGING_LEVEL為輸出的日誌級別、CORE_PEER_ID為Peer的ID等。
此部分功能由第三方包viper來實現,viper除支援環境變數的配置方式外,還支援配置檔案方式。viper使用方法參考:https://github.com/spf13/viper。
如下程式碼為載入環境變數配置,其中cmdRoot為"core",即CORE_開頭的環境變數。
```go
viper.SetEnvPrefix(cmdRoot)
viper.AutomaticEnv()
replacer := strings.NewReplacer(".", "_")
viper.SetEnvKeyReplacer(replacer)
//程式碼在peer/main.go
```
載入配置檔案,同樣由第三方包viper來實現,具體程式碼如下:
其中cmdRoot為"core",即/etc/hyperledger/fabric/core.yaml。
```go
err := common.InitConfig(cmdRoot)
//程式碼在peer/main.go
```
如下程式碼為common.InitConfig(cmdRoot)的具體實現:
```go
config.InitViper(nil, cmdRoot)
err := viper.ReadInConfig()
//程式碼在peer/common/common.go
```
另附config.InitViper(nil, cmdRoot)的程式碼實現:
優先從環境變數FABRIC_CFG_PATH中獲取配置檔案路徑,其次為當前目錄、開發環境目錄(即:src/github.com/hyperledger/fabric/sampleconfig)、和OfficialPath(即:/etc/hyperledger/fabric)。
AddDevConfigPath是對addConfigPath的封裝,目的是通過GetDevConfigDir()調取sampleconfig路徑。
```go
var altPath = os.Getenv("FABRIC_CFG_PATH")
if altPath != "" {
addConfigPath(v, altPath)
} else {
addConfigPath(v, "./")
err := AddDevConfigPath(v)
addConfigPath(v, OfficialPath)
}
viper.SetConfigName(configName)
//程式碼在core/config/config.go
```
## 2、載入命令列工具和命令
Fabric支援類似peer node start、peer channel create、peer chaincode install這種命令、子命令、命令選項的命令列形式。
此功能由第三方包cobra來實現,以peer chaincode install -n test_cc -v 1.0 -p github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example02為例,
其中peer、chaincode、install、-n分別為命令、子命令、子命令的子命令、命令選項。
如下程式碼為mainCmd的初始化,其中Use為命令名稱,PersistentPreRunE先於Run執行用於初始化日誌系統,Run此處用於列印版本資訊或幫助資訊。cobra使用方法參考:https://github.com/spf13/cobra。
```go
var mainCmd = &cobra.Command{
Use: "peer",
PersistentPreRunE: func(cmd *cobra.Command, args []string) error {
loggingSpec := viper.GetString("logging_level")
if loggingSpec == "" {
loggingSpec = viper.GetString("logging.peer")
}
flogging.InitFromSpec(loggingSpec) //初始化flogging日誌系統
return nil
},
Run: func(cmd *cobra.Command, args []string) {
if versionFlag {
fmt.Print(version.GetInfo())
} else {
cmd.HelpFunc()(cmd, args)
}
},
}
//程式碼在peer/main.go
```
如下程式碼為新增命令列選項,-v, --version、--logging-level和--test.coverprofile分別用於版本資訊、日誌級別和測試覆蓋率分析。
```go
mainFlags := mainCmd.PersistentFlags()
mainFlags.BoolVarP(&versionFlag, "version", "v", false, "Display current version of fabric peer server")
mainFlags.String("logging-level", "", "Default logging level and overrides, see core.yaml for full syntax")
viper.BindPFlag("logging_level", mainFlags.Lookup("logging-level"))
testCoverProfile := ""
mainFlags.StringVarP(&testCoverProfile, "test.coverprofile", "", "coverage.cov", "Done")
//程式碼在peer/main.go
```
如下程式碼為逐一載入peer命令下子命令:node、channel、chaincode、clilogging、version。
```go
mainCmd.AddCommand(version.Cmd())
mainCmd.AddCommand(node.Cmd())
mainCmd.AddCommand(chaincode.Cmd(nil))
mainCmd.AddCommand(clilogging.Cmd(nil))
mainCmd.AddCommand(channel.Cmd(nil))
//程式碼在peer/main.go
```
mainCmd.Execute()為命令啟動。
## 3、初始化日誌系統(輸出物件、日誌格式、日誌級別)
如下為初始日誌系統程式碼入口,其中loggingSpec取自環境變數CORE_LOGGING_LEVEL或配置檔案中logging.peer,即:全域性的預設日誌級別。
```go
flogging.InitFromSpec(loggingSpec)
//程式碼在peer/main.go
```
flogging,即:fabric logging,為Fabric基於第三方包go-logging封裝的日誌包,go-logging使用方法參考:https://github.com/op/go-logging
如下程式碼為flogging包的初始化函式:
```go
func init() {
logger = logging.MustGetLogger(pkgLogID) //建立僅在flogging包內程式碼使用的logging.Logger物件
Reset() //全域性變數初始化為預設值
initgrpclogger() //初始化gRPC Logger,即建立logging.Logger物件,並用這個物件設定grpclog
}
//程式碼在common/flogging/logging.go
```
init()執行結束後,peer/main.go中呼叫flogging.InitFromSpec(loggingSpec),將再次初始化全域性日誌級別為loggingSpec,之前預設為logging.INFO。
func InitFromSpec(spec string) string程式碼如下。
其中spec格式為:[<module>[,<module>...]=]<level>[:[<module>[,<module>...]=]<level>...]。
此處傳入spec為"",將""模組日誌級別設定為defaultLevel,並會將modules初始化為defaultLevel。
```go
levelAll := defaultLevel //defaultLevel為logging.INFO
var err error
if spec != "" { //如果spec不為空,則按既定格式讀取
fields := strings.Split(spec, ":") //按:分割
for _, field := range fields {
split := strings.Split(field, "=") //按=分割
switch len(split) {
case 1: //只有level
if levelAll, err = logging.LogLevel(field); err != nil { //levelAll賦值為logging.LogLevel列舉中定義的Level級別
levelAll = defaultLevel // 如果沒有定義,則使用預設日誌級別
}
case 2: //針對module,module...=level,split[0]為模組集,split[1]為要設定的日誌級別
levelSingle, err := logging.LogLevel(split[1]) //levelSingle賦值為logging.LogLevel列舉中定義的Level級別
modules := strings.Split(split[0], ",") //按,分割獲取模組名
for _, module := range modules {
logging.SetLevel(levelSingle, module) //本條規則中所有模組日誌級別均設定為levelSingle
}
default:
//...
}
}
}
//程式碼在common/flogging/logging.go
```
flogging(Fabric日誌系統)更詳細資訊參考:[Fabric 1.0原始碼筆記 之 flogging(Fabric日誌系統)](../flogging/README.md)
## 4、初始化 MSP (Membership Service Provider會員服務提供者)
如下程式碼為初始化MSP,獲取peer.mspConfigPath路徑和peer.localMspId,分別表示MSP的本地路徑(/etc/hyperledger/fabric/msp/)和Peer所關聯的MSP ID,並初始化組織和身份資訊。
```go
var mspMgrConfigDir = config.GetPath("peer.mspConfigPath")
var mspID = viper.GetString("peer.localMspId")
err = common.InitCrypto(mspMgrConfigDir, mspID)
//程式碼在peer/main.go
```
/etc/hyperledger/fabric/msp/目錄下包括:admincerts、cacerts、keystore、signcerts、tlscacerts。其中:
* admincerts:為管理員證書的PEM檔案,如Admin@org1.example.com-cert.pem。
* cacerts:為根CA證書的PEM檔案,如ca.org1.example.com-cert.pem。
* keystore:為具有節點的簽名金鑰的PEM檔案,如91e54fccbb82b29d07657f6df9587c966edee6366786d234bbb8c96707ec7c16_sk。
* signcerts:為節點X.509證書的PEM檔案,如peer1.org1.example.com-cert.pem。
* tlscacerts:為TLS根CA證書的PEM檔案,如tlsca.org1.example.com-cert.pem。
如下程式碼為common.InitCrypto(mspMgrConfigDir, mspID)的具體實現,peer.BCCSP為密碼庫相關配置,包括演算法和檔案路徑等,格式如下:
```go
BCCSP:
Default: SW
SW:
Hash: SHA2
Security: 256
FileKeyStore:
KeyStore:
var bccspConfig *factory.FactoryOpts
err = viperutil.EnhancedExactUnmarshalKey("peer.BCCSP", &bccspConfig) //將peer.BCCSP配置資訊載入至bccspConfig中
err = mspmgmt.LoadLocalMsp(mspMgrConfigDir, bccspConfig, localMSPID) //從指定目錄中載入本地MSP
//程式碼在peer/common/common.go
```
factory.FactoryOpts定義為:
```go
type FactoryOpts struct {
ProviderName string `mapstructure:"default" json:"default" yaml:"Default"`
SwOpts *SwOpts `mapstructure:"SW,omitempty" json:"SW,omitempty" yaml:"SwOpts"`
}
//FactoryOpts程式碼在bccsp/factory/nopkcs11.go,本目錄下另有程式碼檔案pkcs11.go,在-tags "nopkcs11"條件下二選一編譯。
```
```go
type SwOpts struct {
// Default algorithms when not specified (Deprecated?)
SecLevel int `mapstructure:"security" json:"security" yaml:"Security"`
HashFamily string `mapstructure:"hash" json:"hash" yaml:"Hash"`
// Keystore Options
Ephemeral bool `mapstructure:"tempkeys,omitempty" json:"tempkeys,omitempty"`
FileKeystore *FileKeystoreOpts `mapstructure:"filekeystore,omitempty" json:"filekeystore,omitempty" yaml:"FileKeyStore"`
DummyKeystore *DummyKeystoreOpts `mapstructure:"dummykeystore,omitempty" json:"dummykeystore,omitempty"`
}
type FileKeystoreOpts struct {
KeyStorePath string `mapstructure:"keystore" yaml:"KeyStore"`
}
//SwOpts和FileKeystoreOpts程式碼均在bccsp/factory/swfactory.go
```
如下程式碼為viperutil.EnhancedExactUnmarshalKey("peer.BCCSP", &bccspConfig)的具體實現,getKeysRecursively為遞迴讀取peer.BCCSP配置資訊。
mapstructure為第三方包:github.com/mitchellh/mapstructure,用於將map[string]interface{}轉換為struct。
示例程式碼:https://godoc.org/github.com/mitchellh/mapstructure#example-Decode--WeaklyTypedInput
```go
func EnhancedExactUnmarshalKey(baseKey string, output interface{}) error {
m := make(map[string]interface{})
m[baseKey] = nil
leafKeys := getKeysRecursively("", viper.Get, m)
config := &mapstructure.DecoderConfig{
Metadata: nil,
Result: output,
WeaklyTypedInput: true,
}
decoder, err := mapstructure.NewDecoder(config)
return decoder.Decode(leafKeys[baseKey])
}
//程式碼在common/viperutil/config_util.go
```
如下程式碼為mspmgmt.LoadLocalMsp(mspMgrConfigDir, bccspConfig, localMSPID)的具體實現,從指定目錄中載入本地MSP。
```go
conf, err := msp.GetLocalMspConfig(dir, bccspConfig, mspID) //獲取本地MSP配置,序列化後寫入msp.MSPConfig,即conf
return GetLocalMSP().Setup(conf) //調取msp.NewBccspMsp()建立bccspmsp例項,調取bccspmsp.Setup(conf)解碼conf.Config並設定bccspmsp
//程式碼在msp/mgmt/mgmt.go
```
如下程式碼為msp.GetLocalMspConfig(dir, bccspConfig, mspID)的具體實現。
SetupBCCSPKeystoreConfig()核心程式碼為bccspConfig.SwOpts.FileKeystore = &factory.FileKeystoreOpts{KeyStorePath: keystoreDir},目的是在FileKeystore或KeyStorePath為空時設定預設值。
```go
signcertDir := filepath.Join(dir, signcerts) //signcerts為"signcerts",signcertDir即/etc/hyperledger/fabric/msp/signcerts/
keystoreDir := filepath.Join(dir, keystore) //keystore為"keystore",keystoreDir即/etc/hyperledger/fabric/msp/keystore/
bccspConfig = SetupBCCSPKeystoreConfig(bccspConfig, keystoreDir) //設定bccspConfig.SwOpts.Ephemeral = false和bccspConfig.SwOpts.FileKeystore = &factory.FileKeystoreOpts{KeyStorePath: keystoreDir}
//bccspConfig.SwOpts.Ephemeral是否短暫的
err := factory.InitFactories(bccspConfig) //初始化bccsp factory,並建立bccsp例項
signcert, err := getPemMaterialFromDir(signcertDir) //讀取X.509證書的PEM檔案
sigid := &msp.SigningIdentityInfo{PublicSigner: signcert[0], PrivateSigner: nil} //構造SigningIdentityInfo
return getMspConfig(dir, ID, sigid) //分別讀取cacerts、admincerts、tlscacerts檔案,以及config.yaml中組織資訊,構造msp.FabricMSPConfig,序列化後用於構造msp.MSPConfig
//程式碼在msp/configbuilder.go
```
factory.InitFactories(bccspConfig)及BCCSP(區塊鏈加密服務提供者)更詳細內容,參考:[Fabric 1.0原始碼筆記 之 BCCSP(區塊鏈加密服務提供者)](../bccsp/README.md)
至此,peer/main.go結束,接下來將進入peer/node/start.go中serve(args)函式。
網址:http://www.qukuailianxueyuan.io/
欲領取造幣技術與全套虛擬機器資料
區塊鏈技術交流QQ群:756146052 備註:CSDN
尹成學院微信:備註:CSDN
網址:http://www.qukuailianxueyuan.io/
欲領取造幣技術與全套虛擬機器資料
區塊鏈技術交流QQ群:756146052 備註:CSDN
尹成學院微信:備註:CSDN
相關文章
- Fabric 1.0原始碼分析(33) Peer #peer channel命令及子命令實現原始碼
- Fabric 1.0原始碼分析(34) Peer #peer chaincode命令及子命令實現原始碼AI
- Fabric 1.0原始碼分析(32) Peer #peer node start命令實現原始碼
- Fabric 1.0原始碼分析(31) Peer原始碼
- Fabric 1.0原始碼分析(35)Peer #EndorserServer(Endorser服務端)原始碼Server服務端
- Fabric 1.0原始碼分析(36) Peer #EndorserClient(Endorser客戶端)原始碼client客戶端
- Fabric 1.0原始碼分析(37) Peer #DeliverClient(Deliver客戶端)原始碼client客戶端
- Fabric 1.0原始碼分析(38) Peer #BroadcastClient(Broadcast客戶端)原始碼ASTclient客戶端
- 以太坊原始碼分析(32)eth-downloader-peer原始碼分析原始碼
- Fabric1.4原始碼解析:Peer節點加入通道原始碼
- 以太坊原始碼分析(31)eth-downloader-peer原始碼分析原始碼
- 以太坊原始碼分析(46)p2p-peer.go原始碼分析原始碼Go
- Fabric 1.0原始碼分析(25) Orderer原始碼
- Fabric 1.0原始碼分析(3)Chaincode(鏈碼)原始碼AI
- Fabric 1.0原始碼分析(40) Proposal(提案)原始碼
- Jaeger tchannel-go原始碼閱讀——PeerGo原始碼
- Fabric 1.0原始碼分析(14) flogging(Fabric日誌系統)原始碼
- Fabric 1.0原始碼分析(18) Ledger(賬本)原始碼
- Fabric 1.0原始碼分析(43) Tx(Transaction 交易)原始碼
- Fabric 1.0原始碼分析(47)Fabric 1.0.4 go程式碼量統計原始碼Go
- Fabric 1.0原始碼分析(42)scc(系統鏈碼)原始碼
- Fabric 1.0原始碼分析(13)events(事件服務)原始碼事件
- Fabric 1.0原始碼分析(26)Orderer #ledger(Orderer Ledger)原始碼
- Fabric 1.0原始碼分析(39) policy(背書策略)原始碼
- Fabric 1.0原始碼分析(45)gRPC(Fabric中註冊的gRPC Service)原始碼RPC
- Fabric 1.0原始碼分析(10)consenter(共識外掛)原始碼
- Fabric 1.0原始碼分析(15)gossip(流言演算法)原始碼Go演算法
- Fabric 1.0原始碼分析(23)LevelDB(KV資料庫)原始碼資料庫
- Fabric 1.0原始碼分析(44)Tx #RWSet(讀寫集)原始碼
- Fabric 1.0原始碼分析(5)Chaincode(鏈碼)體系總結原始碼AI
- Fabric 1.0原始碼分析(6)configtx(配置交易) #ChannelConfig(通道配置)原始碼
- Fabric 1.0原始碼分析(20) Ledger #idStore(ledgerID資料庫)原始碼資料庫
- Fabric 1.0原始碼分析(29) Orderer #multichain(多鏈支援包)原始碼AI
- Fabric 1.0原始碼分析(30) Orderer #BroadcastServer(Broadcast服務端)原始碼ASTServer服務端
- Fabric 1.0原始碼分析(41)putils(protos/utils工具包)原始碼
- Fabric 1.0原始碼分析(2) blockfile(區塊檔案儲存)原始碼BloC
- Fabric 1.0原始碼分析(7)configtx(配置交易) #configtxgen(生成通道配置)原始碼
- Fabric 1.0原始碼分析(9)configtx(配置交易)體系介紹原始碼