Fabric源码分析之三启动流程代码Peer分析

一、安装启动方式

Fabric的启动有几种方法,一种是使用Docker从官方下载相应的版本然后启动,一种是直接源码编译启动,这两种方式没有本质的不同。同时,最新的Fabric提供了Solo和Raft两种共识服务机制(不讨论旧版本的KAFKA等),在数据的保存机制上提供了LevelDB和CouchDB两种方式。
因此,有必要把这些环境都指定下来,才能更好的分析源码。这里主要以Raft共识为主,leveldb数据库为基础进行分析。安装启动的方式以源码编译为主。
之所以选取这种形式,主要是这种形式更容易理解,把相关复杂的与源码无关的环境配置选项从中摘除,以便清晰的展现代码运行的路径。

二、启动流程

重点是Peer和Orderer两个模块,先分析Peer:
1、入口函数:

//cobra是一个开源Golang命令包,可以快速创建命令行界面,在以太坊中用的CLI这个包
var mainCmd = &cobra.Command{
	Use: "peer"}

func main() {
  //下面这段代码,主要是用来处理环境变量的处理方式
	viper.SetEnvPrefix(common.CmdRoot)
	viper.AutomaticEnv()
	replacer := strings.NewReplacer(".", "_")
	viper.SetEnvKeyReplacer(replacer)

  //处理命令格式,包括所有的peer相关的命令
	mainFlags := mainCmd.PersistentFlags()

	mainFlags.String("logging-level", "", "Legacy logging level flag")
	viper.BindPFlag("logging_level", mainFlags.Lookup("logging-level"))
	mainFlags.MarkHidden("logging-level")

  //添加相关的命令,如版本、通道等
	mainCmd.AddCommand(version.Cmd())
	mainCmd.AddCommand(node.Cmd())
	mainCmd.AddCommand(chaincode.Cmd(nil))
	mainCmd.AddCommand(clilogging.Cmd(nil))
	mainCmd.AddCommand(channel.Cmd(nil))

	// 执行并处理异常,主要的任务由cobra完成,此处仅在错误时返回一个非零值
	if mainCmd.Execute() != nil {
		os.Exit(1)
	}
}

看代码,这太简单了,简单的简直不像话。可是,一般来说,话少事大,同理,代码少,估计背后的服务啥的启动的少不了。挑一个常用的比如node.Cmd,进去看看:

func startCmd() *cobra.Command {
	// Set the flags on the node start command.
	flags := nodeStartCmd.Flags()
	flags.BoolVarP(&chaincodeDevMode, "peer-chaincodedev", "", false,
		"Whether peer in chaincode development mode")

	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 {
		if len(args) != 0 {
			return fmt.Errorf("trailing args detected")
		}
		// Parsing of the command line is done so silence cmd usage
		cmd.SilenceUsage = true
		return serve(args)
	},
}

这个里头有一个Command结构体:

type Command struct {
	// Use is the one-line usage message.
	Use string

	// Aliases is an array of aliases that can be used instead of the first word in Use.
	Aliases []string

	// SuggestFor is an array of command names for which this command will be suggested -
	// similar to aliases but only suggests.
	SuggestFor []string

	// Short is the short description shown in the 'help' output.
	Short string

	// Long is the long message shown in the 'help <this-command>' output.
	Long string

	// Example is examples of how to use the command.
	Example string

	// ValidArgs is list of all valid non-flag arguments that are accepted in bash completions
	ValidArgs []string

	// Expected arguments
	Args PositionalArgs

	// ArgAliases is List of aliases for ValidArgs.
	// These are not suggested to the user in the bash completion,
	// but accepted if entered manually.
	ArgAliases []string

	// BashCompletionFunction is custom functions used by the bash autocompletion generator.
	BashCompletionFunction string

	// Deprecated defines, if this command is deprecated and should print this string when used.
	Deprecated string

	// Hidden defines, if this command is hidden and should NOT show up in the list of available commands.
	Hidden bool
......

	// commands is the list of commands supported by this program.
	commands []*Command
	// parent is a parent command for this command.
	parent *Command
	// Max lengths of commands' string lengths for use in padding.
	commandsMaxUseLen         int
	commandsMaxCommandPathLen int
	commandsMaxNameLen        int
	// commandsAreSorted defines, if command slice are sorted or not.
	commandsAreSorted bool
	// commandCalledAs is the name or alias value used to call this command.
	commandCalledAs struct {
		name   string
		called bool
	}

	// args is actual args parsed from flags.
	args []string
	// flagErrorBuf contains all error messages from pflag.
	flagErrorBuf *bytes.Buffer
	// flags is full set of flags.
	flags *flag.FlagSet
	// pflags contains persistent flags.
	pflags *flag.FlagSet
	// lflags contains local flags.
	lflags *flag.FlagSet
	// iflags contains inherited flags.
	iflags *flag.FlagSet
	// parentsPflags is all persistent flags of cmd's parents.
	parentsPflags *flag.FlagSet
	// globNormFunc is the global normalization function
	// that we can use on every pflag set and children commands
	globNormFunc func(f *flag.FlagSet, name string) flag.NormalizedName

	// output is an output writer defined by user.
	output io.Writer
	// usageFunc is usage func defined by user.
	usageFunc func(*Command) error
......
	helpCommand *Command
	// versionTemplate is the version template defined by user.
	versionTemplate string
}

有一点吓人的长,不过有注释,再加上命名还是挺规范的,所以看看也没啥难度,就是有点多,估计经常得来回切换着看。现在只关心和Run有关系的Action,其它暂时可以放一下。
看一下命令的执行过程:

func main() {
......
  //将相关加入的命令执行
	if mainCmd.Execute() != nil {
		os.Exit(1)
	}
}
//调用
func (c *Command) Execute() error {
	_, err := c.ExecuteC()
	return err
}
func (c *Command) ExecuteC() (cmd *Command, err error) {
	// 仅运行根命令
	if c.HasParent() {
		return c.Root().ExecuteC()
	}

	//预处理函数
	if preExecHookFn != nil {
		preExecHookFn(c)
	}

	// 默认初始化帮助
	c.InitDefaultHelpCmd()
......
  //关键是这里
	err = cmd.execute(flags)
......
	return cmd, err
}

func (c *Command) execute(a []string) (err error) {
......
  //初始化默认的帮助和版本标记
	c.InitDefaultHelpFlag()
	c.InitDefaultVersionFlag()

	//分析输入的标记
	err = c.ParseFlags(a)
	if err != nil {
		return c.FlagErrorFunc()(c, err)
	}
......

	//判断执行函数是否存在
	if !c.Runnable() {
		return flag.ErrHelp
	}

	c.preRun()

	//解析参数
	argWoFlags := c.Flags().Args()
	if c.DisableFlagParsing {
		argWoFlags = a
	}

	if err := c.ValidateArgs(argWoFlags); err != nil {
		return err
	}

  //下来就是一大票各种执行,包括父子命令和不同的命令格式情况下调用不同的命令形式运行
	for p := c; p != nil; p = p.Parent() {
		if p.PersistentPreRunE != nil {
			if err := p.PersistentPreRunE(c, argWoFlags); err != nil {
				return err
			}
			break
		} else if p.PersistentPreRun != nil {
			p.PersistentPreRun(c, argWoFlags)
			break
		}
	}
	if c.PreRunE != nil {
		if err := c.PreRunE(c, argWoFlags); err != nil {
			return err
		}
	} else if c.PreRun != nil {
		c.PreRun(c, argWoFlags)
	}

	if err := c.validateRequiredFlags(); err != nil {
		return err
	}
	if c.RunE != nil {
		if err := c.RunE(c, argWoFlags); err != nil {
			return err
		}
	} else {
		c.Run(c, argWoFlags)
	}
	if c.PostRunE != nil {
		if err := c.PostRunE(c, argWoFlags); err != nil {
			return err
		}
	} else if c.PostRun != nil {
		c.PostRun(c, argWoFlags)
	}
	for p := c; p != nil; p = p.Parent() {
		if p.PersistentPostRunE != nil {
			if err := p.PersistentPostRunE(c, argWoFlags); err != nil {
				return err
			}
			break
		} else if p.PersistentPostRun != nil {
			p.PersistentPostRun(c, argWoFlags)
			break
		}
	}

	return nil
}

看到最后大片的if…else了吧,就是一开始命令中的设置。这样就明白了,一个命令执行,比如"peer node start -o 127.0.0.1:7091 --peer-chaincodedev=true",就可以从这里分析。
后面的AddCommand都是如此,包括日志,链码和通道相关,再看一下通道相关的命令:

func Cmd(cf *ChannelCmdFactory) *cobra.Command {
	AddFlags(channelCmd)

	channelCmd.AddCommand(createCmd(cf))
	channelCmd.AddCommand(fetchCmd(cf))
	channelCmd.AddCommand(joinCmd(cf))
	channelCmd.AddCommand(listCmd(cf))
	channelCmd.AddCommand(updateCmd(cf))
	channelCmd.AddCommand(signconfigtxCmd(cf))
	channelCmd.AddCommand(getinfoCmd(cf))

	return channelCmd
}
func createCmd(cf *ChannelCmdFactory) *cobra.Command {
	createCmd := &cobra.Command{
		Use:   "create",
		Short: "Create a channel",
		Long:  "Create a channel and write the genesis block to a file.",
		RunE: func(cmd *cobra.Command, args []string) error {
			return create(cmd, args, cf)
		},
	}
	flagList := []string{
		"channelID",
		"file",
		"outputBlock",
		"timeout",
	}
	attachFlags(createCmd, flagList)

	return createCmd
}

好,流程明白了,回头看一下Start命令最后启动的server(args)。

2、服务启动

func serve(args []string) error {
	// MSP的处理,只支持标准
	mspType := mgmt.GetLocalMSP().GetType()
	if mspType != msp.FABRIC {
		panic("Unsupported msp type " + msp.ProviderTypeToString(mspType))
	}
......
	//使用ACL启动aclmgmt,创建ACL访问控制列表
	aclProvider := aclmgmt.NewACLProvider(
		aclmgmt.ResourceGetter(peer.GetStableChannelConfig),
	)

  //注册平台相关语言
	pr := platforms.NewRegistry(
		&golang.Platform{},
		&node.Platform{},
		&java.Platform{},
		&car.Platform{},
	)

  //定义链码提供者实例
	deployedCCInfoProvider := &lscc.DeployedCCInfoProvider{}
  //获取通道管理者
	identityDeserializerFactory := func(chainID string) msp.IdentityDeserializer {
		return mgmt.GetManagerForChain(chainID)
	}

  //处理相关环境操作保存相关地址、端口、证书及TLS等。
	opsSystem := newOperationsSystem()
	err := opsSystem.Start()
	if err != nil {
		return errors.WithMessage(err, "failed to initialize operations subystems")
	}
	defer opsSystem.Stop()
  //监控实例,监控相关节点信息并记录
	metricsProvider := opsSystem.Provider
	logObserver := floggingmetrics.NewObserver(metricsProvider)
	flogging.Global.SetObserver(logObserver)
  //保存连接成员信息,方便应用
	membershipInfoProvider := privdata.NewMembershipInfoProvider(createSelfSignedData(), identityDeserializerFactory)
	//initialize resource management exit
	//此处是调用对帐本的处理也就是数据存储相关的服务
	ledgermgmt.Initialize(
		&ledgermgmt.Initializer{
			//交易相关
			CustomTxProcessors:            peer.ConfigTxProcessors,
			PlatformRegistry:              pr,
			//链码相关
			DeployedChaincodeInfoProvider: deployedCCInfoProvider,
			//节点间交互
			MembershipInfoProvider:        membershipInfoProvider,
			MetricsProvider:               metricsProvider,
			//健康检查
			HealthCheckRegistry:           opsSystem,
		},
	)
......//处理参数部分省略

  //下面拿到缓存的节点信息(主要是地址)后开始网络服务
	peerEndpoint, err := peer.GetPeerEndpoint()
	if err != nil {
		err = fmt.Errorf("Failed to get Peer Endpoint: %s", err)
		return err
	}

	peerHost, _, err := net.SplitHostPort(peerEndpoint.Address)
	if err != nil {
		return fmt.Errorf("peer address is not in the format of host:port: %v", err)
	}

	listenAddr := viper.GetString("peer.listenAddress")
	serverConfig, err := peer.GetServerConfig()
	if err != nil {
		logger.Fatalf("Error loading secure config for peer (%s)", err)
	}

  //限流,最大2500
	throttle := comm.NewThrottle(grpcMaxConcurrency)
	serverConfig.Logger = flogging.MustGetLogger("core.comm").With("server", "PeerServer")
	serverConfig.ServerStatsHandler = comm.NewServerStatsHandler(metricsProvider)
	//设置拦截器,监控和RPC
	serverConfig.UnaryInterceptors = append(
		serverConfig.UnaryInterceptors,
		grpcmetrics.UnaryServerInterceptor(grpcmetrics.NewUnaryMetrics(metricsProvider)),
		grpclogging.UnaryServerInterceptor(flogging.MustGetLogger("comm.grpc.server").Zap()),
		throttle.UnaryServerIntercptor,
	)
	serverConfig.StreamInterceptors = append(
		serverConfig.StreamInterceptors,
		grpcmetrics.StreamServerInterceptor(grpcmetrics.NewStreamMetrics(metricsProvider)),
		grpclogging.StreamServerInterceptor(flogging.MustGetLogger("comm.grpc.server").Zap()),
		throttle.StreamServerInterceptor,
	)
  //创建节点RPC服务
	peerServer, err := peer.NewPeerServer(listenAddr, serverConfig)
	if err != nil {
		logger.Fatalf("Failed to create peer server (%s)", err)
	}

  //处理TLS
	if serverConfig.SecOpts.UseTLS {
		logger.Info("Starting peer with TLS enabled")
		// set up credential support
		cs := comm.GetCredentialSupport()
		roots, err := peer.GetServerRootCAs()
		if err != nil {
			logger.Fatalf("Failed to set TLS server root CAs: %s", err)
		}
		cs.ServerRootCAs = roots

		// set the cert to use if client auth is requested by remote endpoints
		clientCert, err := peer.GetClientCertificate()
		if err != nil {
			logger.Fatalf("Failed to set TLS client certificate: %s", err)
		}
		comm.GetCredentialSupport().SetClientCertificate(clientCert)
	}

	mutualTLS := serverConfig.SecOpts.UseTLS && serverConfig.SecOpts.RequireClientCert
	//策略柱果木榄果,对通道ID和变量等
	policyCheckerProvider := func(resourceName string) deliver.PolicyCheckerFunc {
		return func(env *cb.Envelope, channelID string) error {
			return aclProvider.CheckACL(resourceName, channelID, env)
		}
	}

  //创建分发和过滤区块事件服务
	abServer := peer.NewDeliverEventsServer(mutualTLS, policyCheckerProvider, &peer.DeliverChainManager{}, metricsProvider)
	pb.RegisterDeliverServer(peerServer.Server(), abServer)

	// Initialize chaincode service
	//设置本地链码安装位置;创建自签名CA,启动GRPC服务
	chaincodeSupport, ccp, sccp, packageProvider := startChaincodeServer(peerHost, aclProvider, pr, opsSystem)

	logger.Debugf("Running peer")

	// Start the Admin server-这个是重点,管理员可以管理通道等
	startAdminServer(listenAddr, peerServer.Server(), serverConfig)

	privDataDist := func(channel string, txID string, privateData *transientstore.TxPvtReadWriteSetWithConfigInfo, blkHt uint64) error {
		//分发私有数据
		return service.GetGossipService().DistributePrivateData(channel, txID, privateData, blkHt)
	}

  //获得本地签名的身份信息,包括节点的功能,如背书和验证等
	signingIdentity := mgmt.GetLocalSigningIdentityOrPanic()
	serializedIdentity, err := signingIdentity.Serialize()
	if err != nil {
		logger.Panicf("Failed serializing self identity: %v", err)
	}

  //获得相关配置信息(上面的背书和签名)并初始化注册
	libConf := library.Config{}
	if err = viperutil.EnhancedExactUnmarshalKey("peer.handlers", &libConf); err != nil {
		return errors.WithMessage(err, "could not load YAML config")
	}
	reg := library.InitRegistry(libConf)

	authFilters := reg.Lookup(library.Auth).([]authHandler.Filter)
	endorserSupport := &endorser.SupportImpl{
		SignerSupport:    signingIdentity,
		Peer:             peer.Default,
		PeerSupport:      peer.DefaultSupport,
		ChaincodeSupport: chaincodeSupport,
		SysCCProvider:    sccp,
		ACLProvider:      aclProvider,
	}
	endorsementPluginsByName := reg.Lookup(library.Endorsement).(map[string]endorsement2.PluginFactory)
	validationPluginsByName := reg.Lookup(library.Validation).(map[string]validation.PluginFactory)
	signingIdentityFetcher := (endorsement3.SigningIdentityFetcher)(endorserSupport)
	channelStateRetriever := endorser.ChannelStateRetriever(endorserSupport)
	pluginMapper := endorser.MapBasedPluginMapper(endorsementPluginsByName)
	pluginEndorser := endorser.NewPluginEndorser(&endorser.PluginSupport{
		ChannelStateRetriever:   channelStateRetriever,
		TransientStoreRetriever: peer.TransientStoreFactory,
		PluginMapper:            pluginMapper,
		SigningIdentityFetcher:  signingIdentityFetcher,
	})
	endorserSupport.PluginEndorser = pluginEndorser
	serverEndorser := endorser.NewEndorserServer(privDataDist, endorserSupport, pr, metricsProvider)

	expirationLogger := flogging.MustGetLogger("certmonitor")
	crypto.TrackExpiration(
		serverConfig.SecOpts.UseTLS,
		serverConfig.SecOpts.Certificate,
		comm.GetCredentialSupport().GetClientCertificate().Certificate,
		serializedIdentity,
		expirationLogger.Warnf, // This can be used to piggyback a metric event in the future
		time.Now(),
		time.AfterFunc)

	policyMgr := peer.NewChannelPolicyManagerGetter()

	// Initialize gossip component--初始化网络间通信的Gossip协议服务
	err = initGossipService(policyMgr, metricsProvider, peerServer, serializedIdentity, peerEndpoint.Address)
	if err != nil {
		return err
	}
	defer service.GetGossipService().Stop()

	// register prover grpc service
	// FAB-12971 disable prover service before v1.4 cut. Will uncomment after v1.4 cut
	// err = registerProverService(peerServer, aclProvider, signingIdentity)
	// if err != nil {
	// 	return err
	// }

	// initialize system chaincodes

	// deploy system chaincodes--部署系统链码
	sccp.DeploySysCCs("", ccp)
	logger.Infof("Deployed system chaincodes")

	installedCCs := func() ([]ccdef.InstalledChaincode, error) {
		//查看当前安装链码
		return packageProvider.ListInstalledChaincodes()
	}
	//生命周期控制
	lifecycle, err := cc.NewLifeCycle(cc.Enumerate(installedCCs))
	if err != nil {
		logger.Panicf("Failed creating lifecycle: +%v", err)
	}
	//链码的元数据更新
	onUpdate := cc.HandleMetadataUpdate(func(channel string, chaincodes ccdef.MetadataSet) {
		service.GetGossipService().UpdateChaincodes(chaincodes.AsChaincodes(), gossipcommon.ChainID(channel))
	})
	//添加对更新的监听
	lifecycle.AddListener(onUpdate)

	// this brings up all the channels--初始化通道相关信息
	peer.Initialize(func(cid string) {
		logger.Debugf("Deploying system CC, for channel <%s>", cid)
		sccp.DeploySysCCs(cid, ccp)
		sub, err := lifecycle.NewChannelSubscription(cid, cc.QueryCreatorFunc(func() (cc.Query, error) {
			return peer.GetLedger(cid).NewQueryExecutor()
		}))
		if err != nil {
			logger.Panicf("Failed subscribing to chaincode lifecycle updates")
		}
		//通道监听器注册
		cceventmgmt.GetMgr().Register(cid, sub)
	}, ccp, sccp, txvalidator.MapBasedPluginMapper(validationPluginsByName),
		pr, deployedCCInfoProvider, membershipInfoProvider, metricsProvider)

	if viper.GetBool("peer.discovery.enabled") {
		registerDiscoveryService(peerServer, policyMgr, lifecycle)
	}

	networkID := viper.GetString("peer.networkId")

	logger.Infof("Starting peer with ID=[%s], network ID=[%s], address=[%s]", peerEndpoint.Id, networkID, peerEndpoint.Address)

	// Get configuration before starting go routines to avoid
	// racing in tests是否定义配置文件
	profileEnabled := viper.GetBool("peer.profile.enabled")
	profileListenAddress := viper.GetString("peer.profile.listenAddress")

	// 创建GRPC服务协程
	serve := make(chan error)

	// Start profiling http endpoint if enabled-如定义配置文件,启动RPC服务
	if profileEnabled {
		go func() {
			logger.Infof("Starting profiling server with listenAddress = %s", profileListenAddress)
			if profileErr := http.ListenAndServe(profileListenAddress, nil); profileErr != nil {
				logger.Errorf("Error starting profiler: %s", profileErr)
			}
		}()
	}

  //处理事件消息
	go handleSignals(addPlatformSignals(map[os.Signal]func(){
		syscall.SIGINT:  func() { serve <- nil },
		syscall.SIGTERM: func() { serve <- nil },
	}))

	logger.Infof("Started peer with ID=[%s], network ID=[%s], address=[%s]", peerEndpoint.Id, networkID, peerEndpoint.Address)

	// 检查帐本是否重置check to see if the peer ledgers have been reset
	preResetHeights, err := kvledger.LoadPreResetHeight()
	if err != nil {
		return fmt.Errorf("error loading prereset height: %s", err)
	}
	for cid, height := range preResetHeights {
		logger.Infof("Ledger rebuild: channel [%s]: preresetHeight: [%d]", cid, height)
	}
......

	// 下面启动节点服务
	auth := authHandler.ChainFilters(serverEndorser, authFilters...)
	// Register the Endorser server
	pb.RegisterEndorserServer(peerServer.Server(), auth)

	go func() {
		var grpcErr error
		if grpcErr = peerServer.Start(); grpcErr != nil {
			grpcErr = fmt.Errorf("grpc server exited with error: %s", grpcErr)
		}
		serve <- grpcErr
	}()

	// Block until grpc server exits-//通道一直在此阻塞服务
	return <-serve
}

又一大片,从刚开始接触Golang就发现这个语言的一个特点,稍微复杂的一点功能,就是一片代码,不像c++啥的拆来拆去。吐槽完毕,代码还得分析:

func (gServer *GRPCServer) Start() error {
	return gServer.server.Serve(gServer.listener)
}
func (s *Server) Serve(lis net.Listener) error {
	s.mu.Lock()
	s.printf("serving")
	s.serve = true
	if s.lis == nil {
		// Serve called after Stop or GracefulStop.
		s.mu.Unlock()
		lis.Close()
		return ErrServerStopped
	}

	s.serveWG.Add(1)
	defer func() {
		s.serveWG.Done()
		select {
		// Stop or GracefulStop called; block until done and return nil.
		case <-s.quit:
			<-s.done
		default:
		}
	}()

	ls := &listenSocket{Listener: lis}
	s.lis[ls] = true

	if channelz.IsOn() {
		ls.channelzID = channelz.RegisterListenSocket(ls, s.channelzID, "")
	}
	s.mu.Unlock()

	defer func() {
		s.mu.Lock()
		if s.lis != nil && s.lis[ls] {
			ls.Close()
			delete(s.lis, ls)
		}
		s.mu.Unlock()
	}()

	var tempDelay time.Duration // how long to sleep on accept failure

	for {
		rawConn, err := lis.Accept()
		if err != nil {
			if ne, ok := err.(interface {
				Temporary() bool
			}); ok && ne.Temporary() {
				if tempDelay == 0 {
					tempDelay = 5 * time.Millisecond
				} else {
					tempDelay *= 2
				}
				if max := 1 * time.Second; tempDelay > max {
					tempDelay = max
				}
				s.mu.Lock()
				s.printf("Accept error: %v; retrying in %v", err, tempDelay)
				s.mu.Unlock()
				timer := time.NewTimer(tempDelay)
				select {
				case <-timer.C:
				case <-s.quit:
					timer.Stop()
					return nil
				}
				continue
			}
			s.mu.Lock()
			s.printf("done serving; Accept = %v", err)
			s.mu.Unlock()

			select {
			case <-s.quit:
				return nil
			default:
			}
			return err
		}
		tempDelay = 0
		// Start a new goroutine to deal with rawConn so we don't stall this Accept
		// loop goroutine.
		//
		// Make sure we account for the goroutine so GracefulStop doesn't nil out
		// s.conns before this conn can be added.
		s.serveWG.Add(1)
		go func() {
			s.handleRawConn(rawConn)
			s.serveWG.Done()
		}()
	}
}

看到这里,才看到了熟悉的套路,熟悉的配方,网线监听,网络服务的处理。到此处,基本一个Peer整体的流程的主干就清晰了。

3、说明
需要说明的是,在Server函数中,没有重点分析系统链码和帐本相关的处理,可以看一下相关的代码注释即可。没有什么太复杂的内容。
其实Peer节点中的代码还有很多,不过这里只是分析其启动的流程,相关的代码会在后面的相关部分进行展开。抓住重点,暂时扔掉细节,先从宏观上把握脉络。总结一下:
获取msp类型
设置资源访问策略 aclmgmt.NewACLProvider,测试可RegisterACLProvider()
初始化本地账本管理器 ledgermgmt.Initialize(peer.ConfigTxProcessors)
创建grpc服务1:PeerServer
创建grpc服务2:DeliverEvents(分发事件),注册到peerServer上
创建grpc服务3:链码管理服务
创建grpc服务4 : Admin注册到PeerServer上
隐私数据处理: 使用goosip协议进行分发
启动发现服务5:registerDiscoveryService
创建grpc服务6:背书服务
初始化goosip连接与加密组件
registerProverService:根据版本1.4前后不同的处理。
安装系统连码 initSysCCs并初始化peer.Initialize(func(cid string) {}
启动PeerServer Grpc服务
设置日志模块
和代码对比着流程,一一的看代码,就可以把整个的peer的内容看得清清楚楚。

三、总结

Peer的代码是整个Fabric中很重要的一个部分,可以说,他是基础,他提供了一系列相关的操作命令和通信的细节,这都需要后面不断的详细分析。

发布了104 篇原创文章 · 获赞 12 · 访问量 11万+

猜你喜欢

转载自blog.csdn.net/fpcc/article/details/104150418