Fabric 1.0原始碼分析(32) Peer #peer node start命令實現
# Fabric 1.0原始碼筆記 之 Peer #peer node start命令實現
## 1、peer node載入子命令start和status
peer node載入子命令start和status,程式碼如下:
```go
func Cmd() *cobra.Command {
nodeCmd.AddCommand(startCmd()) //載入子命令start
nodeCmd.AddCommand(statusCmd()) //載入子命令status
return nodeCmd
}
var nodeCmd = &cobra.Command{
Use: nodeFuncName,
Short: fmt.Sprint(shortDes),
Long: fmt.Sprint(longDes),
}
//程式碼在peer/node/node.go
```
startCmd()程式碼如下:
其中serve(args)為peer node start的實現程式碼,比較複雜,本文將重點講解。
另statusCmd()程式碼與startCmd()相近,暫略。
```go
func startCmd() *cobra.Command {
flags := nodeStartCmd.Flags()
flags.BoolVarP(&chaincodeDevMode, "peer-chaincodedev", "", false, "Whether peer in chaincode development mode")
flags.BoolVarP(&peerDefaultChain, "peer-defaultchain", "", false, "Whether to start peer with chain testchainid")
flags.StringVarP(&orderingEndpoint, "orderer", "o", "orderer:7050", "Ordering service endpoint") //orderer
return nodeStartCmd
}
var nodeStartCmd = &cobra.Command{
Use: "start",
Short: "Starts the node.",
Long: `Starts a node that interacts with the network.`,
RunE: func(cmd *cobra.Command, args []string) error {
return serve(args) //serve(args)為peer node start的實現程式碼
},
}
//程式碼在peer/node/start.go
```
**注:如下內容均為serve(args)的程式碼,即peer node start命令執行流程。**
## 2、初始化Ledger(賬本)
初始化賬本,即如下一條程式碼:
```go
ledgermgmt.Initialize()
//程式碼在peer/node/start.go
```
ledgermgmt.Initialize()程式碼展開如下:
```go
func initialize() {
openedLedgers = make(map[string]ledger.PeerLedger) //openedLedgers為全域性變數,儲存目前使用的賬本列表
provider, err := kvledger.NewProvider() //建立賬本Provider例項
ledgerProvider = provider
}
//程式碼在core/ledger/ledgermgmt/ledger_mgmt.go
```
kvledger.NewProvider()程式碼如下:
```go
func NewProvider() (ledger.PeerLedgerProvider, error) {
idStore := openIDStore(ledgerconfig.GetLedgerProviderPath()) //開啟idStore
//建立並初始化blkstorage
attrsToIndex := []blkstorage.IndexableAttr{
blkstorage.IndexableAttrBlockHash,
blkstorage.IndexableAttrBlockNum,
blkstorage.IndexableAttrTxID,
blkstorage.IndexableAttrBlockNumTranNum,
blkstorage.IndexableAttrBlockTxID,
blkstorage.IndexableAttrTxValidationCode,
}
indexConfig := &blkstorage.IndexConfig{AttrsToIndex: attrsToIndex}
blockStoreProvider := fsblkstorage.NewProvider(
fsblkstorage.NewConf(ledgerconfig.GetBlockStorePath(), ledgerconfig.GetMaxBlockfileSize()),
indexConfig)
//建立並初始化statedb
var vdbProvider statedb.VersionedDBProvider
if !ledgerconfig.IsCouchDBEnabled() {
vdbProvider = stateleveldb.NewVersionedDBProvider()
} else {
vdbProvider, err = statecouchdb.NewVersionedDBProvider()
}
//建立並初始化historydb
var historydbProvider historydb.HistoryDBProvider
historydbProvider = historyleveldb.NewHistoryDBProvider()
//構造Provider
provider := &Provider{idStore, blockStoreProvider, vdbProvider, historydbProvider}
provider.recoverUnderConstructionLedger()
return provider, nil
}
//程式碼在core/ledger/kvledger/kv_ledger_provider.go
```
Ledger更詳細內容,參考:[Fabric 1.0原始碼筆記 之 Ledger(賬本)](../ledger/README.md)
## 3、配置及建立PeerServer、建立EventHubServer(事件中心伺服器)
```go
//初始化全域性變數localAddress和peerEndpoint
err := peer.CacheConfiguration()
peerEndpoint, err := peer.GetPeerEndpoint() //獲取peerEndpoint
listenAddr := viper.GetString("peer.listenAddress") //PeerServer監聽地址
secureConfig, err := peer.GetSecureConfig() //獲取PeerServer安全配置,是否啟用TLS、公鑰、私鑰、根證書
//以監聽地址和安全配置,建立Peer GRPC Server
peerServer, err := peer.CreatePeerServer(listenAddr, secureConfig)
//建立EventHubServer(事件中心伺服器)
ehubGrpcServer, err := createEventHubServer(secureConfig)
//程式碼在peer/node/start.go
```
func createEventHubServer(secureConfig comm.SecureServerConfig) (comm.GRPCServer, error)程式碼如下:
```go
var lis net.Listener
var err error
lis, err = net.Listen("tcp", viper.GetString("peer.events.address")) //建立Listen
grpcServer, err := comm.NewGRPCServerFromListener(lis, secureConfig) //從Listen建立GRPCServer
ehServer := producer.NewEventsServer(
uint(viper.GetInt("peer.events.buffersize")), //最大進行緩衝的訊息數
viper.GetDuration("peer.events.timeout")) //緩衝已滿的情況下,往緩衝中傳送訊息的超時
pb.RegisterEventsServer(grpcServer.Server(), ehServer) //EventHubServer註冊至grpcServer
return grpcServer, nil
//程式碼在peer/node/start.go
```
pb.RegisterEventsServer(grpcServer.Server(), ehServer)程式碼如下:
```go
func RegisterEventsServer(s *grpc.Server, srv EventsServer) {
s.RegisterService(&_Events_serviceDesc, srv)
}
//程式碼在protos/peer/events.pb.go
```
events(事件服務)更詳細內容,參考:[Fabric 1.0原始碼筆記 之 events(事件服務)](../events/README.md)
## 4、建立並啟動Chaincode Server,並註冊系統鏈碼
程式碼如下:
```go
ccprovider.EnableCCInfoCache() //ccInfoCacheEnabled = true
//建立Chaincode Server
//如果peer.chaincodeListenAddress,沒有定義或者定義和peerListenAddress相同,均直接使用peerServer
//否則另行建立NewGRPCServer用於Chaincode Server
ccSrv, ccEpFunc := createChaincodeServer(peerServer, listenAddr)
//Chaincode service註冊到grpcServer,並註冊系統鏈碼
registerChaincodeSupport(ccSrv.Server(), ccEpFunc)
go ccSrv.Start() //啟動grpcServer
//程式碼在peer/node/start.go
```
ccSrv, ccEpFunc := createChaincodeServer(peerServer, listenAddr)程式碼如下:建立Chaincode Server。
```go
func createChaincodeServer(peerServer comm.GRPCServer, peerListenAddress string) (comm.GRPCServer, ccEndpointFunc) {
//peer.chaincodeListenAddress,鏈碼容器連線時的監聽地址
cclistenAddress := viper.GetString("peer.chaincodeListenAddress")
var srv comm.GRPCServer
var ccEpFunc ccEndpointFunc
//如果peer.chaincodeListenAddress,沒有定義或者定義和peerListenAddress相同,均直接使用peerServer
//否則另行建立NewGRPCServer用於Chaincode Server
if cclistenAddress == "" {
ccEpFunc = peer.GetPeerEndpoint
srv = peerServer
} else if cclistenAddress == peerListenAddress {
ccEpFunc = peer.GetPeerEndpoint
srv = peerServer
} else {
config, err := peer.GetSecureConfig()
srv, err = comm.NewGRPCServer(cclistenAddress, config)
ccEpFunc = getChaincodeAddressEndpoint
}
return srv, ccEpFunc
}
//程式碼在peer/node/start.go
```
registerChaincodeSupport(ccSrv.Server(), ccEpFunc)程式碼如下:Chaincode service註冊到grpcServer。
```go
func registerChaincodeSupport(grpcServer *grpc.Server, ccEpFunc ccEndpointFunc) {
userRunsCC := chaincode.IsDevMode() //是否開發模式
ccStartupTimeout := viper.GetDuration("chaincode.startuptimeout") //啟動鏈碼容器的超時
if ccStartupTimeout < time.Duration(5)*time.Second { //至少5秒
ccStartupTimeout = time.Duration(5) * time.Second
} else {
}
//構造ChaincodeSupport
ccSrv := chaincode.NewChaincodeSupport(ccEpFunc, userRunsCC, ccStartupTimeout)
scc.RegisterSysCCs() //註冊系統鏈碼
pb.RegisterChaincodeSupportServer(grpcServer, ccSrv) //service註冊到grpcServer
}
//程式碼在peer/node/start.go
```
ccSrv := chaincode.NewChaincodeSupport(ccEpFunc, userRunsCC, ccStartupTimeout)程式碼如下:構造ChaincodeSupport。
```go
var theChaincodeSupport *ChaincodeSupport
func NewChaincodeSupport(getCCEndpoint func() (*pb.PeerEndpoint, error), userrunsCC bool, ccstartuptimeout time.Duration) *ChaincodeSupport {
//即/var/hyperledger/production/chaincodes
ccprovider.SetChaincodesPath(config.GetPath("peer.fileSystemPath") + string(filepath.Separator) + "chaincodes")
pnid := viper.GetString("peer.networkId") //網路ID
pid := viper.GetString("peer.id") //節點ID
//構造ChaincodeSupport
theChaincodeSupport = &ChaincodeSupport{runningChaincodes: &runningChaincodes{chaincodeMap: make(map[string]*chaincodeRTEnv), launchStarted: make(map[string]bool)}, peerNetworkID:
pnid, peerID: pid}
ccEndpoint, err := getCCEndpoint() //此處傳入ccEpFunc
if err != nil {
theChaincodeSupport.peerAddress = viper.GetString("chaincode.peerAddress")
} else {
theChaincodeSupport.peerAddress = ccEndpoint.Address
}
if theChaincodeSupport.peerAddress == "" {
theChaincodeSupport.peerAddress = peerAddressDefault
}
theChaincodeSupport.userRunsCC = userrunsCC //是否開發模式
theChaincodeSupport.ccStartupTimeout = ccstartuptimeout //啟動鏈碼容器的超時
theChaincodeSupport.peerTLS = viper.GetBool("peer.tls.enabled") //是否啟用TLS
if theChaincodeSupport.peerTLS {
theChaincodeSupport.peerTLSCertFile = config.GetPath("peer.tls.cert.file")
theChaincodeSupport.peerTLSKeyFile = config.GetPath("peer.tls.key.file")
theChaincodeSupport.peerTLSSvrHostOrd = viper.GetString("peer.tls.serverhostoverride")
}
kadef := 0
// Peer和鏈碼之間的心跳超時,小於或等於0意味著關閉
if ka := viper.GetString("chaincode.keepalive"); ka == "" {
theChaincodeSupport.keepalive = time.Duration(kadef) * time.Second //0
} else {
t, terr := strconv.Atoi(ka)
if terr != nil {
t = kadef //0
} else if t <= 0 {
t = kadef //0
}
theChaincodeSupport.keepalive = time.Duration(t) * time.Second //非0
}
execto := time.Duration(30) * time.Second
//invoke和initialize命令執行超時
if eto := viper.GetDuration("chaincode.executetimeout"); eto <= time.Duration(1)*time.Second {
//小於1秒時,預設30秒
} else {
execto = eto
}
theChaincodeSupport.executetimeout = execto
viper.SetEnvPrefix("CORE")
viper.AutomaticEnv()
replacer := strings.NewReplacer(".", "_")
viper.SetEnvKeyReplacer(replacer)
theChaincodeSupport.chaincodeLogLevel = getLogLevelFromViper("level")
theChaincodeSupport.shimLogLevel = getLogLevelFromViper("shim")
theChaincodeSupport.logFormat = viper.GetString("chaincode.logging.format")
return theChaincodeSupport
}
//程式碼在core/chaincode/chaincode_support.go
```
scc.RegisterSysCCs()程式碼如下:註冊系統鏈碼。
```go
func RegisterSysCCs() {
//cscc、lscc、escc、vscc、qscc
for _, sysCC := range systemChaincodes {
RegisterSysCC(sysCC)
}
}
程式碼在core/scc/importsysccs.go
```
## 5、註冊Admin server和Endorser server
程式碼如下:
```go
//s.RegisterService(&_Admin_serviceDesc, srv)
//var _Admin_serviceDesc = grpc.ServiceDesc{...}
//core.NewAdminServer()構造ServerAdmin結構體,ServerAdmin結構體實現type AdminServer interface介面
pb.RegisterAdminServer(peerServer.Server(), core.NewAdminServer())
//構造結構體Endorser,Endorser結構體實現type EndorserServer interface介面
serverEndorser := endorser.NewEndorserServer()
//s.RegisterService(&_Endorser_serviceDesc, srv)
//var _Endorser_serviceDesc = grpc.ServiceDesc{...}
pb.RegisterEndorserServer(peerServer.Server(), serverEndorser)
//程式碼在peer/node/start.go
```
附type AdminServer interface介面定義:
```go
type AdminServer interface {
GetStatus(context.Context, *google_protobuf.Empty) (*ServerStatus, error)
StartServer(context.Context, *google_protobuf.Empty) (*ServerStatus, error)
GetModuleLogLevel(context.Context, *LogLevelRequest) (*LogLevelResponse, error)
SetModuleLogLevel(context.Context, *LogLevelRequest) (*LogLevelResponse, error)
RevertLogLevels(context.Context, *google_protobuf.Empty) (*google_protobuf.Empty, error)
}
//程式碼在protos/peer/admin.pb.go
```
附type EndorserServer interface介面定義:
```go
type EndorserServer interface {
ProcessProposal(context.Context, *SignedProposal) (*ProposalResponse, error)
}
//程式碼在protos/peer/peer.pb.go
```
## 6、初始化Gossip服務
```go
bootstrap := viper.GetStringSlice("peer.gossip.bootstrap") //啟動節點後gossip連線的初始節點
serializedIdentity, err := mgmt.GetLocalSigningIdentityOrPanic().Serialize() //獲取簽名身份
messageCryptoService := peergossip.NewMCS( //構造mspMessageCryptoService(訊息加密服務)
peer.NewChannelPolicyManagerGetter(), //構造type channelPolicyManagerGetter struct{}
localmsp.NewSigner(), //構造type mspSigner struct {}
mgmt.NewDeserializersManager()) //構造type mspDeserializersManager struct{}
secAdv := peergossip.NewSecurityAdvisor(mgmt.NewDeserializersManager()) //構造mspSecurityAdvisor(安全顧問)
secureDialOpts := func() []grpc.DialOption {
var dialOpts []grpc.DialOption
dialOpts = append(dialOpts, grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(comm.MaxRecvMsgSize()), //MaxRecvMsgSize
grpc.MaxCallSendMsgSize(comm.MaxSendMsgSize()))) //MaxSendMsgSize
dialOpts = append(dialOpts, comm.ClientKeepaliveOptions()...) //ClientKeepaliveOptions
if comm.TLSEnabled() {
tlsCert := peerServer.ServerCertificate()
dialOpts = append(dialOpts, grpc.WithTransportCredentials(comm.GetCASupport().GetPeerCredentials(tlsCert)))
} else {
dialOpts = append(dialOpts, grpc.WithInsecure())
}
return dialOpts
}
err = service.InitGossipService(serializedIdentity, peerEndpoint.Address, peerServer.Server(),
messageCryptoService, secAdv, secureDialOpts, bootstrap...) //構造gossipServiceImpl
defer service.GetGossipService().Stop()
//程式碼在peer/node/start.go
```
Gossip更詳細內容參考:[Fabric 1.0原始碼筆記 之 gossip(流言演算法)](../gossip/README.md)
## 7、初始化、部署並執行系統鏈碼(scc)
程式碼如下:
```go
initSysCCs() //初始化系統鏈碼,呼叫scc.DeploySysCCs("")
peer.Initialize(func(cid string) { //初始化所有鏈
scc.DeploySysCCs(cid) //按chain id部署並執行系統鏈碼
})
//程式碼在peer/node/start.go
```
func Initialize(init func(string))程式碼如下:
```go
func Initialize(init func(string)) {
chainInitializer = init
var cb *common.Block
var ledger ledger.PeerLedger
ledgermgmt.Initialize()
ledgerIds, err := ledgermgmt.GetLedgerIDs()
for _, cid := range ledgerIds {
ledger, err = ledgermgmt.OpenLedger(cid)
cb, err = getCurrConfigBlockFromLedger(ledger) //獲取最新的配置塊
err = createChain(cid, ledger, cb)
InitChain(cid) //即呼叫chainInitializer(cid),即scc.DeploySysCCs(cid)
}
}
//程式碼在core/peer/peer.go
```
createChain(cid, ledger, cb)程式碼如下:
```go
func createChain(cid string, ledger ledger.PeerLedger, cb *common.Block) error {
envelopeConfig, err := utils.ExtractEnvelope(cb, 0) //獲取配置交易
configtxInitializer := configtx.NewInitializer() //構造initializer
gossipEventer := service.GetGossipService().NewConfigEventer() //獲取gossipServiceInstance,並構造configEventer
gossipCallbackWrapper := func(cm configtxapi.Manager) {
ac, ok := configtxInitializer.ApplicationConfig()
gossipEventer.ProcessConfigUpdate(&chainSupport{
Manager: cm,
Application: ac,
})
//驗證可疑節點身份,並關閉無效連結
service.GetGossipService().SuspectPeers(func(identity api.PeerIdentityType) bool {
return true
})
}
trustedRootsCallbackWrapper := func(cm configtxapi.Manager) {
updateTrustedRoots(cm)
}
configtxManager, err := configtx.NewManagerImpl(
envelopeConfig,
configtxInitializer,
[]func(cm configtxapi.Manager){gossipCallbackWrapper, trustedRootsCallbackWrapper},
)
mspmgmt.XXXSetMSPManager(cid, configtxManager.MSPManager())
ac, ok := configtxInitializer.ApplicationConfig()
cs := &chainSupport{
Manager: configtxManager,
Application: ac, // TODO, refactor as this is accessible through Manager
ledger: ledger,
}
c := committer.NewLedgerCommitterReactive(ledger, txvalidator.NewTxValidator(cs), func(block *common.Block) error {
chainID, err := utils.GetChainIDFromBlock(block)
if err != nil {
return err
}
return SetCurrConfigBlock(block, chainID)
})
ordererAddresses := configtxManager.ChannelConfig().OrdererAddresses()
service.GetGossipService().InitializeChannel(cs.ChainID(), c, ordererAddresses)
chains.Lock()
defer chains.Unlock()
chains.list[cid] = &chain{
cs: cs,
cb: cb,
committer: c,
}
return nil
}
//程式碼在core/peer/peer.go
```
scc更詳細內容參考:[Fabric 1.0原始碼筆記 之 scc(系統鏈碼)](../scc/README.md)
## 8、啟動peerServer和ehubGrpcServer,並監控系統訊號,以及啟動Go自帶的profiling支援進行除錯
程式碼如下:
```go
serve := make(chan error)
sigs := make(chan os.Signal, 1)
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
go func() {
sig := <-sigs //接收系統訊號
serve <- nil
}
go func() {
var grpcErr error
grpcErr = peerServer.Start() //啟動peerServer
serve <- grpcErr
}
err := writePid(config.GetPath("peer.fileSystemPath")+"/peer.pid", os.Getpid()) //寫入pid
go ehubGrpcServer.Start() //啟動ehubGrpcServer
if viper.GetBool("peer.profile.enabled") {
go func() { //啟動Go自帶的profiling支援進行除錯
profileListenAddress := viper.GetString("peer.profile.listenAddress")
profileErr := http.ListenAndServe(profileListenAddress, nil)
}
}
return <-serve //等待serve
//程式碼在peer/node/start.go
```
## 9、按配置檔案重新更新模組日誌級別
```go
overrideLogModules := []string{"msp", "gossip", "ledger", "cauthdsl", "policies", "grpc"}
for _, module := range overrideLogModules {
err = common.SetLogLevelFromViper(module)
}
flogging.SetPeerStartupModulesMap()
//程式碼在peer/node/start.go
```
網址: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原始碼分析(32)Peer #peer根命令入口及載入子命令原始碼
- Fabric 1.0原始碼分析(34) Peer #peer chaincode命令及子命令實現原始碼AI
- 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原始碼分析(40) Proposal(提案)原始碼
- Jaeger tchannel-go原始碼閱讀——PeerGo原始碼
- Fabric 1.0原始碼分析(3)Chaincode(鏈碼)原始碼AI
- Fabric 1.0原始碼分析(18) Ledger(賬本)原始碼
- Fabric 1.0原始碼分析(43) Tx(Transaction 交易)原始碼
- Fabric 1.0原始碼分析(47)Fabric 1.0.4 go程式碼量統計原始碼Go
- Node.js 應用 peer dependency 的用法Node.js
- 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原始碼分析(15)gossip(流言演算法)原始碼Go演算法
- Fabric 1.0原始碼分析(23)LevelDB(KV資料庫)原始碼資料庫
- Fabric 1.0原始碼分析(44)Tx #RWSet(讀寫集)原始碼
- Fabric 1.0原始碼分析(14) flogging(Fabric日誌系統)原始碼
- Fabric 1.0原始碼分析(10)consenter(共識外掛)原始碼
- Fabric 1.0原始碼分析(29) Orderer #multichain(多鏈支援包)原始碼AI
- Fabric 1.0原始碼分析(41)putils(protos/utils工具包)原始碼
- Fabric 1.0原始碼分析(45)gRPC(Fabric中註冊的gRPC Service)原始碼RPC
- Fabric 1.0原始碼分析(5)Chaincode(鏈碼)體系總結原始碼AI
- Fabric 1.0原始碼分析(2) blockfile(區塊檔案儲存)原始碼BloC
- Fabric 1.0原始碼分析(19) Ledger #statedb(狀態資料庫)原始碼資料庫
- Fabric 1.0原始碼分析(21)Ledger #historydb(歷史資料庫)原始碼資料庫
- Fabric 1.0原始碼分析(22)Ledger #blkstorage(block檔案儲存)原始碼BloC
- Fabric 1.0原始碼分析(42)scc(系統鏈碼) #cscc(通道相關)原始碼