准备参数
cli参数:
node --proxy_app=dummy --home "C:\Users\Administrator\datadir\tendermint"
Tendermint的cli解析使用cobra库!
flags vs args
让我们将程序定格在(c *Command) ExecuteC【/vendor/github.com/spf13/cobra/command.go#】中的下面这一行:
err=cmd.execute(flags)
我们可以看出,从命令行传进来的所有“命令”都算作参数,而标记是“- -”开头的参数。换句话说,标记是去掉不带“- -”开头的参数!
梦开始的地方
代码位置:/vendor/github.com/spf13/cobra/command.go#(c *Command) execute
if c.RunE != nil {
if err := c.RunE(c, argWoFlags); err != nil {
return err
}
} else {
c.Run(c, argWoFlags)
}
c.RunE(c, argWoFlags)是引发node启动服务的根。一切有意思的事情从这里开始。c.RunE(c, argWoFlags)是调用匿名函数RunE,而RunE的赋值则是在NewRunNodeCmd函数(/cmd/tendermints/commands/run_node.go):
// NewRunNodeCmd returns the command that allows the CLI to start a
// node. It can be used with a custom PrivValidator and in-process ABCI application.
func NewRunNodeCmd(nodeProvider nm.NodeProvider) *cobra.Command {
cmd := &cobra.Command{
Use: "node",
Short: "Run the tendermint node",
RunE: func(cmd *cobra.Command, args []string) error { //匿名函数
// Create & start node
n, err := nodeProvider(config, logger)
if err != nil {
return fmt.Errorf("Failed to create node: %v", err)
}
if err := n.Start(); err != nil {
return fmt.Errorf("Failed to start node: %v", err)
} else {
logger.Info("Started node", "nodeInfo", n.Switch().NodeInfo()) //节点启动完毕打印日志Started node
}
// Trap signal, run forever.
n.RunForever()
return nil
},
}
AddNodeFlags(cmd)
return cmd
}
这个匿名函数有三个功能:
1、创建node(nodeProvider(config, logger))
2、启动node(n.Start())
3、监听停止node的信号(n.RunForever())
下面我们一个功能往下走!我么先看创建node!
创建node
nodeProvider(config,logger)具体执行DefaultNewNode函数(/node/node.go#DefaultNewNode)。DefaultNewNode函数会返回一个Node全局变量。
// DefaultNewNode returns a Tendermint node with default settings for the
// PrivValidator, ClientCreator, GenesisDoc, and DBProvider.
// It implements NodeProvider.
func DefaultNewNode(config *cfg.Config, logger log.Logger) (*Node, error) {
return NewNode(config,
types.LoadOrGenPrivValidatorFS(config.PrivValidatorFile()),
proxy.DefaultClientCreator(config.ProxyApp, config.ABCI, config.DBDir()),
DefaultGenesisDocProviderFunc(config),
DefaultDBProvider,
logger)
}
DefaultNewNode的第一个实参为config。config的定义在/cmd/tendermint/commands/root.go:
var (
config = cfg.DefaultConfig()
)
注意:用户在命令行传入的参数,那只是启动节点所需的非常小的一部分参数。大多数参数都是需要从默认配置中加载的。config全局变量加载了node所需的所有默认参数(主要是默认基础配置、默认RPC配置、默认P2P配置、内存池配置、共识配置和交易索引配置)。
DefaultNewNode的第二个实参为types.LoadOrGenPrivValidatorFS(config.PrivValidatorFile()),该函数会返回一个PrivValidatorFS实例。
DefaultNewNode的第三个实参为proxy.DefaultClientCreator(config.ProxyApp,config.ABCI,config.DBDir()),其中DefaultClientCreator函数(/proxy/client.go#DefaultClientCreator)的第一个实参config.ProxyApp=“dummy”;
第二个实参config.ABCI=“socket”;第三个实参config.DBDir()
=“C:\Users\Administrator\datadir\tendermint\data”。
但是具体负责创建这个全局变量的函数走的是NewNode函数。代码在/node/node.go#NewNode。
// NewNode returns a new, ready to go, Tendermint Node.
func NewNode(config *cfg.Config,
privValida