以太坊源码之『geth命令操作』

概念:

geth是go-ethereum中最主要的一个命令行工具,也是各种网络的接入点,支持全节点和轻节点模式,其它程序也可以通过暴露的JSON RPC接口调用访问以太访网络。

主要引用第三方的cli包实现

  • 源码地址:https://gopkg.in/urfave/cli.v1
  • 概念:一个基于go开发的用于在go里面构建命令行的应用程序

geth启动流程分析

  • 通过init做一个geth整体初始化 
// geth整体初始化
func init() {
	// 命令/行为,如果用户没有输入其它子命令,就调用这个字段指向的函数
	app.Action = geth
	app.HideVersion = true // we have a command to print the version
	app.Copyright = "Copyright 2013-2017 The go-ethereum Authors"
	// 所有支持的子命令
	app.Commands = []cli.Command{
		// See chaincmd.go:
		initCommand,
		importCommand,
		exportCommand,
		copydbCommand,
		removedbCommand,
		dumpCommand,
		monitorCommand,
		// 账号管理
		accountCommand,
		walletCommand,
		consoleCommand,
		attachCommand,
		javascriptCommand,
		makecacheCommand,
		makedagCommand,
		versionCommand,
		bugCommand,
		licenseCommand,
		// See config.go
		dumpConfigCommand,
	}
	// 通过sort函数对cli的所有子命令基于首字母进行排序
	sort.Sort(cli.CommandsByName(app.Commands))

	// 所有能够解析的options
	app.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 {
		// 设置用于当前程序的CPU上限
		runtime.GOMAXPROCS(runtime.NumCPU())
		if err := debug.Setup(ctx); err != nil {
			return err
		}
		// 启动专门监控协程收集正在运行的进程的各种指标,3s一次
		go metrics.CollectProcessMetrics(3 * time.Second)
		// 配置指定的网络(主网或者其它的测试网络)
		utils.SetupNetwork(ctx)
		return nil
	}

	app.After = func(ctx *cli.Context) error {
		debug.Exit()
		// 重置终端
		console.Stdin.Close() // Resets terminal mode.
		return nil
	}
}

func main() {
	if err := app.Run(os.Args); err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}
}
  • 通过geth函数默认启动(在没有调用其它的子命令的情况下默认启动geth)
  • 创建节点
  • 启动节点
  • 等待节点终止
// 如果没有指定其它子命令,那么geth就是默认的系统入口
// 主要是根据提供的参数创建一个默认的节点
// 以阻塞的方式来运行节点,直到节点被终止
func geth(ctx *cli.Context) error {
	// 创建一个节点
	node := makeFullNode(ctx)
	// 启动节点
	startNode(ctx, node)
	// 等待,直到节点停止
	node.Wait()
	return nil
}
  •  创建节点
// 创建一个节点
// 先创建节点,然后注册各种服务
func makeFullNode(ctx *cli.Context) *node.Node {
	// 根据配置创建node
	stack, cfg := makeConfigNode(ctx)
	// 把以太客户客户端添加到stack中
	utils.RegisterEthService(stack, &cfg.Eth)

	if ctx.GlobalBool(utils.DashboardEnabledFlag.Name) {
		utils.RegisterDashboardService(stack, &cfg.Dashboard)
	}
	// whisper主要用于加密通讯
	shhEnabled := enableWhisper(ctx)
	shhAutoEnabled := !ctx.GlobalIsSet(utils.WhisperEnabledFlag.Name) && ctx.GlobalIsSet(utils.DeveloperFlag.Name)
	if shhEnabled || shhAutoEnabled {
		if ctx.GlobalIsSet(utils.WhisperMaxMessageSizeFlag.Name) {
			cfg.Shh.MaxMessageSize = uint32(ctx.Int(utils.WhisperMaxMessageSizeFlag.Name))
		}
		if ctx.GlobalIsSet(utils.WhisperMinPOWFlag.Name) {
			cfg.Shh.MinimumAcceptedPOW = ctx.Float64(utils.WhisperMinPOWFlag.Name)
		}
		// 注册ssh服务
		utils.RegisterShhService(stack, &cfg.Shh)
	}
// 根据命令行参数以及一些特殊的配置来创建一个node
func makeConfigNode(ctx *cli.Context) (*node.Node, gethConfig) {
	// 加载默认配置
	cfg := gethConfig{
		Eth:       eth.DefaultConfig,
		Shh:       whisper.DefaultConfig,
		Node:      defaultNodeConfig(),
		Dashboard: dashboard.DefaultConfig,
	}
	if file := ctx.GlobalString(configFileFlag.Name); file != "" {
		if err := loadConfig(file, &cfg); err != nil {
			utils.Fatalf("%v", err)
		}
	}
	utils.SetNodeConfig(ctx, &cfg.Node)
	// 创建一个新的节点
	stack, err := node.New(&cfg.Node)
	if err != nil {
		utils.Fatalf("Failed to create the protocol stack: %v", err)
	}
	// 将与eth相关的命令应用于配置
	utils.SetEthConfig(ctx, stack, &cfg.Eth)
	if ctx.GlobalIsSet(utils.EthStatsURLFlag.Name) {
		cfg.Ethstats.URL = ctx.GlobalString(utils.EthStatsURLFlag.Name)
	}
	// 设置ssh配置
	utils.SetShhConfig(ctx, stack, &cfg.Shh)
	// 设置dashboard配置
	utils.SetDashboardConfig(ctx, &cfg.Dashboard)

	return stack, cfg
}

总结:

整个启动过程其实就是在解析参数,然后创建、启动节点,再把服务注入到节点中。所有与以太坊相关的功能都是以服务的形式存在。

猜你喜欢

转载自blog.csdn.net/super_lixiang/article/details/83512670