今天正式开始撸以太坊代码了。
以太坊入口代码位于cmd/geth/main.go,先看一下main()函数:
func main() {
if err := app.Run(os.Args); err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
}
显然,使用了urfave/cli库,具体可以参见之前一篇博文:
https://blog.csdn.net/turkeycock/article/details/80359654
这里有个疑问,为什么没有看到app的flag和command配置呢?我们了解一下Go语言的执行流程就明白了,借用网上的一张神图:
可以看到,main()并不是真正意义上的入口,在初始化完常量和变量以后,会先调用模块的init()函数,然后才是main()函数。所以初始化的工作是在init()函数里完成的:
func init() {
// Initialize the CLI app and start Geth
app.Action = geth
app.HideVersion = true // we have a command to print the version
app.Copyright = "Copyright 2013-2018 The go-ethereum Authors"
app.Commands = []cli.Command{
// See chaincmd.go:
initCommand,
……
}
sort.Sort(cli.CommandsByName(app.Commands))
app.Flags = append(app.Flags, nodeFlags...)
……
app.Before = func(ctx *cli.Context) error {
runtime.GOMAXPROCS(runtime.NumCPU())
if err := debug.Setup(ctx); err != nil {
return err
}
// Start system runtime metrics collection
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
}
}
可以看到:app.Action=geth,如果没有添加任何command参数的话,主入口是geth()函数。
flag的配置代码位于cmd/utils/flags.go,command的配置代码跟main.go在同一个包中,分散在不同的文件里。
在进入主入口之前,app.Before做了3件事情:
I. runtime.GOMAXPROCS():设置最大可用处理器数
II. metrics.CollectProcessMetrics():创建一个goroutine,每3秒监测一次系统的ram和disk状态
III. utils.SetupNetwork():配置gas limit值
下面开始看geth()函数:
func geth(ctx *cli.Context) error {
node := makeFullNode(ctx)
startNode(ctx, node)
node.Wait()
return nil
}
可以看到,主要做了3件事情:
I. 创建结点
II. 启动结点
III. 结点进入等待状态
下面一个一个的分析:
1. 创建结点
func makeFullNode(ctx *cli.Context) *node.Node {
stack, cfg := makeConfigNode(ctx)
utils.RegisterEthService(stack, &cfg.Eth)
……
return stack
}
中间一堆代码默认情况下不会走进去,先忽略~
所以这个函数就干了2件事:创建结点、注册EthService。
1.1 创建结点
先看makeConfigNode()函数:
func makeConfigNode(ctx *cli.Context) (*node.Node, gethConfig) {
// Load defaults.
cfg := gethConfig{
Eth: eth.DefaultConfig,
Shh: whisper.DefaultConfig,
Node: defaultNodeConfig(),
Dashboard: dashboard.DefaultConfig,
}
// Load config file.
if file := ctx.GlobalString(configFileFlag.Name); file != "" {
if err := loadConfig(file, &cfg); err != nil {
utils.Fatalf("%v", err)
}
}
// Apply flags.
utils.SetNodeConfig(ctx, &cfg.Node)
stack, err := node.New(&cfg.Node)
if err != nil {
utils.Fatalf("Failed to create the protocol stack: %v", err)
}
utils.SetEthConfig(ctx, stack, &cfg.Eth)
if ctx.GlobalIsSet(utils.EthStatsURLFlag.Name) {
cfg.Ethstats.URL = ctx.GlobalString(utils.EthStatsURLFlag.Name)
}
utils.SetShhConfig(ctx, stack, &cfg.Shh)
utils.SetDashboardConfig(ctx, &cfg.Dashboard)
return stack, cfg
}
主要是初始化和