兄弟连Go语言+区链技术培训以太坊源码分析(39)geth启动流程分析geth是我们的go-ethereum最主要的一个命令行工具。也是我们的各种网络的接入点(主网络main-net测试网络test-net和私有网络)。支持运行在全节点模式或者轻量级节点模式。其他程序可以通过它暴露的JSONRPC调用来访问以太坊网络的功能。如果什么命令都不输入直接运行geth。就会默认启动一个全节点模式的节点。连接到主网络。我们看看启动的主要流程是什么,涉及到了那些组件。##启动的main函数cmd/geth/main.go看到main函数一上来就直接运行了。最开始看的时候是有点懵逼的。后面发现go语言里面有两个默认的函数,一个是main()函数。一个是init()函数。go语言会自动按照一定的顺序先调用所有包的init()函数。然后才会调用main()函数。funcmain(){iferr:=app.Run(os.Args);err!=nil{fmt.Fprintln(os.Stderr,err)os.Exit(1)}}main.go的init函数app是一个三方包gopkg.in/urfave/cli.v1的实例。这个三方包的用法大致就是首先构造这个app对象。通过代码配置app对象的行为,提供一些回调函数。然后运行的时候直接在main函数里面运行app.Run(os.Args)就行了。import(..."gopkg.in/urfave/cli.v1")var(app=utils.NewApp(gitCommit,"thego-ethereumcommandlineinterface")//flagsthatconfigurethenodenodeFlags=[]cli.Flag{utils.IdentityFlag,1/9utils.UnlockedAccountFlag,utils.PasswordFileFlag,utils.BootnodesFlag,...}rpcFlags=[]cli.Flag{utils.RPCEnabledFlag,utils.RPCListenAddrFlag,...}whisperFlags=[]cli.Flag{utils.WhisperEnabledFlag,...})funcinit(){//InitializetheCLIappandstartGeth//Action字段表示如果用户没有输入其他的子命令的情况下,会调用这个字段指向的函数。app.Action=gethapp.HideVersion=true//wehaveacommandtoprinttheversionapp.Copyright="Copyright2013-2017Thego-ethereumAuthors"//Commands是所有支持的子命令app.Commands=[]cli.Command{//Seechaincmd.go:initCommand,importCommand,exportCommand,removedbCommand,dumpCommand,//Seemonitorcmd.go:monitorCommand,//Seeaccountcmd.go:accountCommand,walletCommand,//Seeconsolecmd.go:consoleCommand,attachCommand,javascriptCommand,2/9//Seemisccmd.go:makecacheCommand,makedagCommand,versionCommand,bugCommand,licenseCommand,//Seeconfig.godumpConfigCommand,}sort.Sort(cli.CommandsByName(app.Commands))//所有能够解析的Optionsapp.Flags=append(app.Flags,nodeFlags...)app.Flags=append(app.Flags,rpcFlags...)app.Flags=append(app.Flags,consoleFlags...)app.Flags=append(app.Flags,debug.Flags...)app.Flags=append(app.Flags,whisperFlags...)app.Before=func(ctx*cli.Context)error{runtime.GOMAXPROCS(runtime.NumCPU())iferr:=debug.Setup(ctx);err!=nil{returnerr}//Startsystemruntimemetricscollectiongometrics.CollectProcessMetrics(3*time.Second)utils.SetupNetwork(ctx)returnnil}app.After=func(ctx*cli.Context)error{debug.Exit()console.Stdin.Close()//Resetsterminalmode.returnnil}}如果我们没有输入任何的参数,那么会自动调用geth方法。//gethisthemainentrypointintothesystemifnospecialsubcommandisran.//Itcreatesadefaultnodebasedonthecommandlineargumentsandrunsitin//blockingmode,waitingforittobeshutdown.3/9//如果没有指定特殊的子命令,那么geth是系统主要的入口。//它会根据提供的参数创建一个默认的节点。并且以阻塞的模式运行这个节点,等待着节点被终止。funcgeth(ctx*cli.Context)error{node:=makeFullNode(ctx)startNode(ctx,node)node.Wait()returnnil}makeFullNode函数,funcmakeFullNode(ctx*cli.Context)*node.Node{//根据命令行参数和一些特殊的配置来创建一个nodestack,cfg:=makeConfigNode(ctx)//把eth的服务注册到这个节点上面。eth服务是以太坊的主要的服务。是以太坊功能的提供者。utils.RegisterEthService(stack,&cfg.Eth)//Whispermustbeexplicitlyenabl...