github.com/linapex/ethereum-go-chinese@v0.0.0-20190316121929-f8b7a73c3fa1/cmd/utils/flags.go (about)

     1  
     2  //<developer>
     3  //    <name>linapex 曹一峰</name>
     4  //    <email>linapex@163.com</email>
     5  //    <wx>superexc</wx>
     6  //    <qqgroup>128148617</qqgroup>
     7  //    <url>https://jsq.ink</url>
     8  //    <role>pku engineer</role>
     9  //    <date>2019-03-16 19:16:33</date>
    10  //</624450072452534272>
    11  
    12  
    13  //package utils包含用于go-ethereum命令的内部助手函数。
    14  package utils
    15  
    16  import (
    17  	"crypto/ecdsa"
    18  	"fmt"
    19  	"io/ioutil"
    20  	"math/big"
    21  	"os"
    22  	"path/filepath"
    23  	"strconv"
    24  	"strings"
    25  	"time"
    26  
    27  	"github.com/ethereum/go-ethereum/accounts"
    28  	"github.com/ethereum/go-ethereum/accounts/keystore"
    29  	"github.com/ethereum/go-ethereum/common"
    30  	"github.com/ethereum/go-ethereum/common/fdlimit"
    31  	"github.com/ethereum/go-ethereum/consensus"
    32  	"github.com/ethereum/go-ethereum/consensus/clique"
    33  	"github.com/ethereum/go-ethereum/consensus/ethash"
    34  	"github.com/ethereum/go-ethereum/core"
    35  	"github.com/ethereum/go-ethereum/core/state"
    36  	"github.com/ethereum/go-ethereum/core/vm"
    37  	"github.com/ethereum/go-ethereum/crypto"
    38  	"github.com/ethereum/go-ethereum/dashboard"
    39  	"github.com/ethereum/go-ethereum/eth"
    40  	"github.com/ethereum/go-ethereum/eth/downloader"
    41  	"github.com/ethereum/go-ethereum/eth/gasprice"
    42  	"github.com/ethereum/go-ethereum/ethdb"
    43  	"github.com/ethereum/go-ethereum/ethstats"
    44  	"github.com/ethereum/go-ethereum/les"
    45  	"github.com/ethereum/go-ethereum/log"
    46  	"github.com/ethereum/go-ethereum/metrics"
    47  	"github.com/ethereum/go-ethereum/metrics/influxdb"
    48  	"github.com/ethereum/go-ethereum/node"
    49  	"github.com/ethereum/go-ethereum/p2p"
    50  	"github.com/ethereum/go-ethereum/p2p/discv5"
    51  	"github.com/ethereum/go-ethereum/p2p/enode"
    52  	"github.com/ethereum/go-ethereum/p2p/nat"
    53  	"github.com/ethereum/go-ethereum/p2p/netutil"
    54  	"github.com/ethereum/go-ethereum/params"
    55  	whisper "github.com/ethereum/go-ethereum/whisper/whisperv6"
    56  	"gopkg.in/urfave/cli.v1"
    57  )
    58  
    59  var (
    60  	CommandHelpTemplate = `{{.cmd.Name}}{{if .cmd.Subcommands}} command{{end}}{{if .cmd.Flags}} [command options]{{end}} [arguments...]
    61  {{if .cmd.Description}}{{.cmd.Description}}
    62  {{end}}{{if .cmd.Subcommands}}
    63  SUBCOMMANDS:
    64  	{{range .cmd.Subcommands}}{{.Name}}{{with .ShortName}}, {{.}}{{end}}{{ "\t" }}{{.Usage}}
    65  	{{end}}{{end}}{{if .categorizedFlags}}
    66  {{range $idx, $categorized := .categorizedFlags}}{{$categorized.Name}} OPTIONS:
    67  {{range $categorized.Flags}}{{"\t"}}{{.}}
    68  {{end}}
    69  {{end}}{{end}}`
    70  )
    71  
    72  func init() {
    73  	cli.AppHelpTemplate = `{{.Name}} {{if .Flags}}[global options] {{end}}command{{if .Flags}} [command options]{{end}} [arguments...]
    74  
    75  VERSION:
    76     {{.Version}}
    77  
    78  COMMANDS:
    79     {{range .Commands}}{{.Name}}{{with .ShortName}}, {{.}}{{end}}{{ "\t" }}{{.Usage}}
    80     {{end}}{{if .Flags}}
    81  GLOBAL OPTIONS:
    82     {{range .Flags}}{{.}}
    83     {{end}}{{end}}
    84  `
    85  
    86  	cli.CommandHelpTemplate = CommandHelpTemplate
    87  }
    88  
    89  //newapp创建具有健全默认值的应用程序。
    90  func NewApp(gitCommit, usage string) *cli.App {
    91  	app := cli.NewApp()
    92  	app.Name = filepath.Base(os.Args[0])
    93  	app.Author = ""
    94  //
    95  	app.Email = ""
    96  	app.Version = params.VersionWithMeta
    97  	if len(gitCommit) >= 8 {
    98  		app.Version += "-" + gitCommit[:8]
    99  	}
   100  	app.Usage = usage
   101  	return app
   102  }
   103  
   104  //这些都是我们支持的命令行标志。
   105  //如果您添加到此列表,请记住包括
   106  //在适当的命令定义中标记。
   107  //
   108  //标记在这里定义,因此它们的名称和帮助文本
   109  //所有命令都相同。
   110  
   111  var (
   112  //常规设置
   113  	DataDirFlag = DirectoryFlag{
   114  		Name:  "datadir",
   115  		Usage: "Data directory for the databases and keystore",
   116  		Value: DirectoryString{node.DefaultDataDir()},
   117  	}
   118  	KeyStoreDirFlag = DirectoryFlag{
   119  		Name:  "keystore",
   120  		Usage: "Directory for the keystore (default = inside the datadir)",
   121  	}
   122  	NoUSBFlag = cli.BoolFlag{
   123  		Name:  "nousb",
   124  		Usage: "Disables monitoring for and managing USB hardware wallets",
   125  	}
   126  	NetworkIdFlag = cli.Uint64Flag{
   127  		Name:  "networkid",
   128  		Usage: "Network identifier (integer, 1=Frontier, 2=Morden (disused), 3=Ropsten, 4=Rinkeby)",
   129  		Value: eth.DefaultConfig.NetworkId,
   130  	}
   131  	TestnetFlag = cli.BoolFlag{
   132  		Name:  "testnet",
   133  		Usage: "Ropsten network: pre-configured proof-of-work test network",
   134  	}
   135  	RinkebyFlag = cli.BoolFlag{
   136  		Name:  "rinkeby",
   137  		Usage: "Rinkeby network: pre-configured proof-of-authority test network",
   138  	}
   139  	ConstantinopleOverrideFlag = cli.Uint64Flag{
   140  		Name:  "override.constantinople",
   141  		Usage: "Manually specify constantinople fork-block, overriding the bundled setting",
   142  	}
   143  	DeveloperFlag = cli.BoolFlag{
   144  		Name:  "dev",
   145  		Usage: "Ephemeral proof-of-authority network with a pre-funded developer account, mining enabled",
   146  	}
   147  	DeveloperPeriodFlag = cli.IntFlag{
   148  		Name:  "dev.period",
   149  		Usage: "Block period to use in developer mode (0 = mine only if transaction pending)",
   150  	}
   151  	IdentityFlag = cli.StringFlag{
   152  		Name:  "identity",
   153  		Usage: "Custom node name",
   154  	}
   155  	DocRootFlag = DirectoryFlag{
   156  		Name:  "docroot",
   157  		Usage: "Document Root for HTTPClient file scheme",
   158  		Value: DirectoryString{homeDir()},
   159  	}
   160  	defaultSyncMode = eth.DefaultConfig.SyncMode
   161  	SyncModeFlag    = TextMarshalerFlag{
   162  		Name:  "syncmode",
   163  		Usage: `Blockchain sync mode ("fast", "full", or "light")`,
   164  		Value: &defaultSyncMode,
   165  	}
   166  	GCModeFlag = cli.StringFlag{
   167  		Name:  "gcmode",
   168  		Usage: `Blockchain garbage collection mode ("full", "archive")`,
   169  		Value: "full",
   170  	}
   171  	LightServFlag = cli.IntFlag{
   172  		Name:  "lightserv",
   173  		Usage: "Maximum percentage of time allowed for serving LES requests (0-90)",
   174  		Value: 0,
   175  	}
   176  	LightPeersFlag = cli.IntFlag{
   177  		Name:  "lightpeers",
   178  		Usage: "Maximum number of LES client peers",
   179  		Value: eth.DefaultConfig.LightPeers,
   180  	}
   181  	LightKDFFlag = cli.BoolFlag{
   182  		Name:  "lightkdf",
   183  		Usage: "Reduce key-derivation RAM & CPU usage at some expense of KDF strength",
   184  	}
   185  	WhitelistFlag = cli.StringFlag{
   186  		Name:  "whitelist",
   187  		Usage: "Comma separated block number-to-hash mappings to enforce (<number>=<hash>)",
   188  	}
   189  //仪表板设置
   190  	DashboardEnabledFlag = cli.BoolFlag{
   191  		Name:  metrics.DashboardEnabledFlag,
   192  		Usage: "Enable the dashboard",
   193  	}
   194  	DashboardAddrFlag = cli.StringFlag{
   195  		Name:  "dashboard.addr",
   196  		Usage: "Dashboard listening interface",
   197  		Value: dashboard.DefaultConfig.Host,
   198  	}
   199  	DashboardPortFlag = cli.IntFlag{
   200  		Name:  "dashboard.host",
   201  		Usage: "Dashboard listening port",
   202  		Value: dashboard.DefaultConfig.Port,
   203  	}
   204  	DashboardRefreshFlag = cli.DurationFlag{
   205  		Name:  "dashboard.refresh",
   206  		Usage: "Dashboard metrics collection refresh rate",
   207  		Value: dashboard.DefaultConfig.Refresh,
   208  	}
   209  //乙烯利设置
   210  	EthashCacheDirFlag = DirectoryFlag{
   211  		Name:  "ethash.cachedir",
   212  		Usage: "Directory to store the ethash verification caches (default = inside the datadir)",
   213  	}
   214  	EthashCachesInMemoryFlag = cli.IntFlag{
   215  		Name:  "ethash.cachesinmem",
   216  		Usage: "Number of recent ethash caches to keep in memory (16MB each)",
   217  		Value: eth.DefaultConfig.Ethash.CachesInMem,
   218  	}
   219  	EthashCachesOnDiskFlag = cli.IntFlag{
   220  		Name:  "ethash.cachesondisk",
   221  		Usage: "Number of recent ethash caches to keep on disk (16MB each)",
   222  		Value: eth.DefaultConfig.Ethash.CachesOnDisk,
   223  	}
   224  	EthashDatasetDirFlag = DirectoryFlag{
   225  		Name:  "ethash.dagdir",
   226  		Usage: "Directory to store the ethash mining DAGs (default = inside home folder)",
   227  		Value: DirectoryString{eth.DefaultConfig.Ethash.DatasetDir},
   228  	}
   229  	EthashDatasetsInMemoryFlag = cli.IntFlag{
   230  		Name:  "ethash.dagsinmem",
   231  		Usage: "Number of recent ethash mining DAGs to keep in memory (1+GB each)",
   232  		Value: eth.DefaultConfig.Ethash.DatasetsInMem,
   233  	}
   234  	EthashDatasetsOnDiskFlag = cli.IntFlag{
   235  		Name:  "ethash.dagsondisk",
   236  		Usage: "Number of recent ethash mining DAGs to keep on disk (1+GB each)",
   237  		Value: eth.DefaultConfig.Ethash.DatasetsOnDisk,
   238  	}
   239  //事务池设置
   240  	TxPoolLocalsFlag = cli.StringFlag{
   241  		Name:  "txpool.locals",
   242  		Usage: "Comma separated accounts to treat as locals (no flush, priority inclusion)",
   243  	}
   244  	TxPoolNoLocalsFlag = cli.BoolFlag{
   245  		Name:  "txpool.nolocals",
   246  		Usage: "Disables price exemptions for locally submitted transactions",
   247  	}
   248  	TxPoolJournalFlag = cli.StringFlag{
   249  		Name:  "txpool.journal",
   250  		Usage: "Disk journal for local transaction to survive node restarts",
   251  		Value: core.DefaultTxPoolConfig.Journal,
   252  	}
   253  	TxPoolRejournalFlag = cli.DurationFlag{
   254  		Name:  "txpool.rejournal",
   255  		Usage: "Time interval to regenerate the local transaction journal",
   256  		Value: core.DefaultTxPoolConfig.Rejournal,
   257  	}
   258  	TxPoolPriceLimitFlag = cli.Uint64Flag{
   259  		Name:  "txpool.pricelimit",
   260  		Usage: "Minimum gas price limit to enforce for acceptance into the pool",
   261  		Value: eth.DefaultConfig.TxPool.PriceLimit,
   262  	}
   263  	TxPoolPriceBumpFlag = cli.Uint64Flag{
   264  		Name:  "txpool.pricebump",
   265  		Usage: "Price bump percentage to replace an already existing transaction",
   266  		Value: eth.DefaultConfig.TxPool.PriceBump,
   267  	}
   268  	TxPoolAccountSlotsFlag = cli.Uint64Flag{
   269  		Name:  "txpool.accountslots",
   270  		Usage: "Minimum number of executable transaction slots guaranteed per account",
   271  		Value: eth.DefaultConfig.TxPool.AccountSlots,
   272  	}
   273  	TxPoolGlobalSlotsFlag = cli.Uint64Flag{
   274  		Name:  "txpool.globalslots",
   275  		Usage: "Maximum number of executable transaction slots for all accounts",
   276  		Value: eth.DefaultConfig.TxPool.GlobalSlots,
   277  	}
   278  	TxPoolAccountQueueFlag = cli.Uint64Flag{
   279  		Name:  "txpool.accountqueue",
   280  		Usage: "Maximum number of non-executable transaction slots permitted per account",
   281  		Value: eth.DefaultConfig.TxPool.AccountQueue,
   282  	}
   283  	TxPoolGlobalQueueFlag = cli.Uint64Flag{
   284  		Name:  "txpool.globalqueue",
   285  		Usage: "Maximum number of non-executable transaction slots for all accounts",
   286  		Value: eth.DefaultConfig.TxPool.GlobalQueue,
   287  	}
   288  	TxPoolLifetimeFlag = cli.DurationFlag{
   289  		Name:  "txpool.lifetime",
   290  		Usage: "Maximum amount of time non-executable transaction are queued",
   291  		Value: eth.DefaultConfig.TxPool.Lifetime,
   292  	}
   293  //性能调整设置
   294  	CacheFlag = cli.IntFlag{
   295  		Name:  "cache",
   296  		Usage: "Megabytes of memory allocated to internal caching",
   297  		Value: 1024,
   298  	}
   299  	CacheDatabaseFlag = cli.IntFlag{
   300  		Name:  "cache.database",
   301  		Usage: "Percentage of cache memory allowance to use for database io",
   302  		Value: 50,
   303  	}
   304  	CacheTrieFlag = cli.IntFlag{
   305  		Name:  "cache.trie",
   306  		Usage: "Percentage of cache memory allowance to use for trie caching",
   307  		Value: 25,
   308  	}
   309  	CacheGCFlag = cli.IntFlag{
   310  		Name:  "cache.gc",
   311  		Usage: "Percentage of cache memory allowance to use for trie pruning",
   312  		Value: 25,
   313  	}
   314  	TrieCacheGenFlag = cli.IntFlag{
   315  		Name:  "trie-cache-gens",
   316  		Usage: "Number of trie node generations to keep in memory",
   317  		Value: int(state.MaxTrieCacheGen),
   318  	}
   319  //矿工设置
   320  	MiningEnabledFlag = cli.BoolFlag{
   321  		Name:  "mine",
   322  		Usage: "Enable mining",
   323  	}
   324  	MinerThreadsFlag = cli.IntFlag{
   325  		Name:  "miner.threads",
   326  		Usage: "Number of CPU threads to use for mining",
   327  		Value: 0,
   328  	}
   329  	MinerLegacyThreadsFlag = cli.IntFlag{
   330  		Name:  "minerthreads",
   331  		Usage: "Number of CPU threads to use for mining (deprecated, use --miner.threads)",
   332  		Value: 0,
   333  	}
   334  	MinerNotifyFlag = cli.StringFlag{
   335  		Name:  "miner.notify",
   336  		Usage: "Comma separated HTTP URL list to notify of new work packages",
   337  	}
   338  	MinerGasTargetFlag = cli.Uint64Flag{
   339  		Name:  "miner.gastarget",
   340  		Usage: "Target gas floor for mined blocks",
   341  		Value: eth.DefaultConfig.MinerGasFloor,
   342  	}
   343  	MinerLegacyGasTargetFlag = cli.Uint64Flag{
   344  		Name:  "targetgaslimit",
   345  		Usage: "Target gas floor for mined blocks (deprecated, use --miner.gastarget)",
   346  		Value: eth.DefaultConfig.MinerGasFloor,
   347  	}
   348  	MinerGasLimitFlag = cli.Uint64Flag{
   349  		Name:  "miner.gaslimit",
   350  		Usage: "Target gas ceiling for mined blocks",
   351  		Value: eth.DefaultConfig.MinerGasCeil,
   352  	}
   353  	MinerGasPriceFlag = BigFlag{
   354  		Name:  "miner.gasprice",
   355  		Usage: "Minimum gas price for mining a transaction",
   356  		Value: eth.DefaultConfig.MinerGasPrice,
   357  	}
   358  	MinerLegacyGasPriceFlag = BigFlag{
   359  		Name:  "gasprice",
   360  		Usage: "Minimum gas price for mining a transaction (deprecated, use --miner.gasprice)",
   361  		Value: eth.DefaultConfig.MinerGasPrice,
   362  	}
   363  	MinerEtherbaseFlag = cli.StringFlag{
   364  		Name:  "miner.etherbase",
   365  		Usage: "Public address for block mining rewards (default = first account)",
   366  		Value: "0",
   367  	}
   368  	MinerLegacyEtherbaseFlag = cli.StringFlag{
   369  		Name:  "etherbase",
   370  		Usage: "Public address for block mining rewards (default = first account, deprecated, use --miner.etherbase)",
   371  		Value: "0",
   372  	}
   373  	MinerExtraDataFlag = cli.StringFlag{
   374  		Name:  "miner.extradata",
   375  		Usage: "Block extra data set by the miner (default = client version)",
   376  	}
   377  	MinerLegacyExtraDataFlag = cli.StringFlag{
   378  		Name:  "extradata",
   379  		Usage: "Block extra data set by the miner (default = client version, deprecated, use --miner.extradata)",
   380  	}
   381  	MinerRecommitIntervalFlag = cli.DurationFlag{
   382  		Name:  "miner.recommit",
   383  		Usage: "Time interval to recreate the block being mined",
   384  		Value: eth.DefaultConfig.MinerRecommit,
   385  	}
   386  	MinerNoVerfiyFlag = cli.BoolFlag{
   387  		Name:  "miner.noverify",
   388  		Usage: "Disable remote sealing verification",
   389  	}
   390  //帐户设置
   391  	UnlockedAccountFlag = cli.StringFlag{
   392  		Name:  "unlock",
   393  		Usage: "Comma separated list of accounts to unlock",
   394  		Value: "",
   395  	}
   396  	PasswordFileFlag = cli.StringFlag{
   397  		Name:  "password",
   398  		Usage: "Password file to use for non-interactive password input",
   399  		Value: "",
   400  	}
   401  
   402  	VMEnableDebugFlag = cli.BoolFlag{
   403  		Name:  "vmdebug",
   404  		Usage: "Record information useful for VM and contract debugging",
   405  	}
   406  //日志记录和调试设置
   407  	EthStatsURLFlag = cli.StringFlag{
   408  		Name:  "ethstats",
   409  		Usage: "Reporting URL of a ethstats service (nodename:secret@host:port)",
   410  	}
   411  	FakePoWFlag = cli.BoolFlag{
   412  		Name:  "fakepow",
   413  		Usage: "Disables proof-of-work verification",
   414  	}
   415  	NoCompactionFlag = cli.BoolFlag{
   416  		Name:  "nocompaction",
   417  		Usage: "Disables db compaction after import",
   418  	}
   419  //RPC设置
   420  	RPCEnabledFlag = cli.BoolFlag{
   421  		Name:  "rpc",
   422  		Usage: "Enable the HTTP-RPC server",
   423  	}
   424  	RPCListenAddrFlag = cli.StringFlag{
   425  		Name:  "rpcaddr",
   426  		Usage: "HTTP-RPC server listening interface",
   427  		Value: node.DefaultHTTPHost,
   428  	}
   429  	RPCPortFlag = cli.IntFlag{
   430  		Name:  "rpcport",
   431  		Usage: "HTTP-RPC server listening port",
   432  		Value: node.DefaultHTTPPort,
   433  	}
   434  	RPCCORSDomainFlag = cli.StringFlag{
   435  		Name:  "rpccorsdomain",
   436  		Usage: "Comma separated list of domains from which to accept cross origin requests (browser enforced)",
   437  		Value: "",
   438  	}
   439  	RPCVirtualHostsFlag = cli.StringFlag{
   440  		Name:  "rpcvhosts",
   441  		Usage: "Comma separated list of virtual hostnames from which to accept requests (server enforced). Accepts '*' wildcard.",
   442  		Value: strings.Join(node.DefaultConfig.HTTPVirtualHosts, ","),
   443  	}
   444  	RPCApiFlag = cli.StringFlag{
   445  		Name:  "rpcapi",
   446  		Usage: "API's offered over the HTTP-RPC interface",
   447  		Value: "",
   448  	}
   449  	IPCDisabledFlag = cli.BoolFlag{
   450  		Name:  "ipcdisable",
   451  		Usage: "Disable the IPC-RPC server",
   452  	}
   453  	IPCPathFlag = DirectoryFlag{
   454  		Name:  "ipcpath",
   455  		Usage: "Filename for IPC socket/pipe within the datadir (explicit paths escape it)",
   456  	}
   457  	WSEnabledFlag = cli.BoolFlag{
   458  		Name:  "ws",
   459  		Usage: "Enable the WS-RPC server",
   460  	}
   461  	WSListenAddrFlag = cli.StringFlag{
   462  		Name:  "wsaddr",
   463  		Usage: "WS-RPC server listening interface",
   464  		Value: node.DefaultWSHost,
   465  	}
   466  	WSPortFlag = cli.IntFlag{
   467  		Name:  "wsport",
   468  		Usage: "WS-RPC server listening port",
   469  		Value: node.DefaultWSPort,
   470  	}
   471  	WSApiFlag = cli.StringFlag{
   472  		Name:  "wsapi",
   473  		Usage: "API's offered over the WS-RPC interface",
   474  		Value: "",
   475  	}
   476  	WSAllowedOriginsFlag = cli.StringFlag{
   477  		Name:  "wsorigins",
   478  		Usage: "Origins from which to accept websockets requests",
   479  		Value: "",
   480  	}
   481  	ExecFlag = cli.StringFlag{
   482  		Name:  "exec",
   483  		Usage: "Execute JavaScript statement",
   484  	}
   485  	PreloadJSFlag = cli.StringFlag{
   486  		Name:  "preload",
   487  		Usage: "Comma separated list of JavaScript files to preload into the console",
   488  	}
   489  
   490  //网络设置
   491  	MaxPeersFlag = cli.IntFlag{
   492  		Name:  "maxpeers",
   493  		Usage: "Maximum number of network peers (network disabled if set to 0)",
   494  		Value: 25,
   495  	}
   496  	MaxPendingPeersFlag = cli.IntFlag{
   497  		Name:  "maxpendpeers",
   498  		Usage: "Maximum number of pending connection attempts (defaults used if set to 0)",
   499  		Value: 0,
   500  	}
   501  	ListenPortFlag = cli.IntFlag{
   502  		Name:  "port",
   503  		Usage: "Network listening port",
   504  		Value: 30303,
   505  	}
   506  	BootnodesFlag = cli.StringFlag{
   507  		Name:  "bootnodes",
   508  		Usage: "Comma separated enode URLs for P2P discovery bootstrap (set v4+v5 instead for light servers)",
   509  		Value: "",
   510  	}
   511  	BootnodesV4Flag = cli.StringFlag{
   512  		Name:  "bootnodesv4",
   513  		Usage: "Comma separated enode URLs for P2P v4 discovery bootstrap (light server, full nodes)",
   514  		Value: "",
   515  	}
   516  	BootnodesV5Flag = cli.StringFlag{
   517  		Name:  "bootnodesv5",
   518  		Usage: "Comma separated enode URLs for P2P v5 discovery bootstrap (light server, light nodes)",
   519  		Value: "",
   520  	}
   521  	NodeKeyFileFlag = cli.StringFlag{
   522  		Name:  "nodekey",
   523  		Usage: "P2P node key file",
   524  	}
   525  	NodeKeyHexFlag = cli.StringFlag{
   526  		Name:  "nodekeyhex",
   527  		Usage: "P2P node key as hex (for testing)",
   528  	}
   529  	NATFlag = cli.StringFlag{
   530  		Name:  "nat",
   531  		Usage: "NAT port mapping mechanism (any|none|upnp|pmp|extip:<IP>)",
   532  		Value: "any",
   533  	}
   534  	NoDiscoverFlag = cli.BoolFlag{
   535  		Name:  "nodiscover",
   536  		Usage: "Disables the peer discovery mechanism (manual peer addition)",
   537  	}
   538  	DiscoveryV5Flag = cli.BoolFlag{
   539  		Name:  "v5disc",
   540  		Usage: "Enables the experimental RLPx V5 (Topic Discovery) mechanism",
   541  	}
   542  	NetrestrictFlag = cli.StringFlag{
   543  		Name:  "netrestrict",
   544  		Usage: "Restricts network communication to the given IP networks (CIDR masks)",
   545  	}
   546  
   547  //将URL留给用户并部署到的ATM
   548  	JSpathFlag = cli.StringFlag{
   549  		Name:  "jspath",
   550  		Usage: "JavaScript root path for `loadScript`",
   551  		Value: ".",
   552  	}
   553  
   554  //天然气价格Oracle设置
   555  	GpoBlocksFlag = cli.IntFlag{
   556  		Name:  "gpoblocks",
   557  		Usage: "Number of recent blocks to check for gas prices",
   558  		Value: eth.DefaultConfig.GPO.Blocks,
   559  	}
   560  	GpoPercentileFlag = cli.IntFlag{
   561  		Name:  "gpopercentile",
   562  		Usage: "Suggested gas price is the given percentile of a set of recent transaction gas prices",
   563  		Value: eth.DefaultConfig.GPO.Percentile,
   564  	}
   565  	WhisperEnabledFlag = cli.BoolFlag{
   566  		Name:  "shh",
   567  		Usage: "Enable Whisper",
   568  	}
   569  	WhisperMaxMessageSizeFlag = cli.IntFlag{
   570  		Name:  "shh.maxmessagesize",
   571  		Usage: "Max message size accepted",
   572  		Value: int(whisper.DefaultMaxMessageSize),
   573  	}
   574  	WhisperMinPOWFlag = cli.Float64Flag{
   575  		Name:  "shh.pow",
   576  		Usage: "Minimum POW accepted",
   577  		Value: whisper.DefaultMinimumPoW,
   578  	}
   579  	WhisperRestrictConnectionBetweenLightClientsFlag = cli.BoolFlag{
   580  		Name:  "shh.restrict-light",
   581  		Usage: "Restrict connection between two whisper light clients",
   582  	}
   583  
   584  //度量标志
   585  	MetricsEnabledFlag = cli.BoolFlag{
   586  		Name:  metrics.MetricsEnabledFlag,
   587  		Usage: "Enable metrics collection and reporting",
   588  	}
   589  	MetricsEnableInfluxDBFlag = cli.BoolFlag{
   590  		Name:  "metrics.influxdb",
   591  		Usage: "Enable metrics export/push to an external InfluxDB database",
   592  	}
   593  	MetricsInfluxDBEndpointFlag = cli.StringFlag{
   594  		Name:  "metrics.influxdb.endpoint",
   595  		Usage: "InfluxDB API endpoint to report metrics to",
   596  Value: "http://本地主机:8086“,
   597  	}
   598  	MetricsInfluxDBDatabaseFlag = cli.StringFlag{
   599  		Name:  "metrics.influxdb.database",
   600  		Usage: "InfluxDB database name to push reported metrics to",
   601  		Value: "geth",
   602  	}
   603  	MetricsInfluxDBUsernameFlag = cli.StringFlag{
   604  		Name:  "metrics.influxdb.username",
   605  		Usage: "Username to authorize access to the database",
   606  		Value: "test",
   607  	}
   608  	MetricsInfluxDBPasswordFlag = cli.StringFlag{
   609  		Name:  "metrics.influxdb.password",
   610  		Usage: "Password to authorize access to the database",
   611  		Value: "test",
   612  	}
   613  //“host”标记是发送到influxdb的每个度量的一部分。在influxdb中,对标签的查询更快。
   614  //它的使用是为了让我们可以对所有节点进行分组,并对所有节点的测量值进行平均,但也同样如此
   615  //我们可以选择一个特定的节点并检查它的测量值。
   616  //https://docs.influxdata.com/influxdb/v1.4/concepts/key_-concepts/标记密钥
   617  	MetricsInfluxDBHostTagFlag = cli.StringFlag{
   618  		Name:  "metrics.influxdb.host.tag",
   619  		Usage: "InfluxDB `host` tag attached to all measurements",
   620  		Value: "localhost",
   621  	}
   622  
   623  	EWASMInterpreterFlag = cli.StringFlag{
   624  		Name:  "vm.ewasm",
   625  		Usage: "External ewasm configuration (default = built-in interpreter)",
   626  		Value: "",
   627  	}
   628  	EVMInterpreterFlag = cli.StringFlag{
   629  		Name:  "vm.evm",
   630  		Usage: "External EVM configuration (default = built-in interpreter)",
   631  		Value: "",
   632  	}
   633  )
   634  
   635  //makedatadir检索当前请求的数据目录,终止
   636  //如果没有指定(或空字符串)。如果节点正在启动一个测试网,
   637  //将使用指定datadir的a子目录。
   638  func MakeDataDir(ctx *cli.Context) string {
   639  	if path := ctx.GlobalString(DataDirFlag.Name); path != "" {
   640  		if ctx.GlobalBool(TestnetFlag.Name) {
   641  			return filepath.Join(path, "testnet")
   642  		}
   643  		if ctx.GlobalBool(RinkebyFlag.Name) {
   644  			return filepath.Join(path, "rinkeby")
   645  		}
   646  		return path
   647  	}
   648  	Fatalf("Cannot determine default data directory, please set manually (--datadir)")
   649  	return ""
   650  }
   651  
   652  //set node key从set命令行标志创建一个节点键,或者加载它
   653  //从文件或作为指定的十六进制值。如果没有提供任何标志,则
   654  //方法返回nil,将生成一个临时键。
   655  func setNodeKey(ctx *cli.Context, cfg *p2p.Config) {
   656  	var (
   657  		hex  = ctx.GlobalString(NodeKeyHexFlag.Name)
   658  		file = ctx.GlobalString(NodeKeyFileFlag.Name)
   659  		key  *ecdsa.PrivateKey
   660  		err  error
   661  	)
   662  	switch {
   663  	case file != "" && hex != "":
   664  		Fatalf("Options %q and %q are mutually exclusive", NodeKeyFileFlag.Name, NodeKeyHexFlag.Name)
   665  	case file != "":
   666  		if key, err = crypto.LoadECDSA(file); err != nil {
   667  			Fatalf("Option %q: %v", NodeKeyFileFlag.Name, err)
   668  		}
   669  		cfg.PrivateKey = key
   670  	case hex != "":
   671  		if key, err = crypto.HexToECDSA(hex); err != nil {
   672  			Fatalf("Option %q: %v", NodeKeyHexFlag.Name, err)
   673  		}
   674  		cfg.PrivateKey = key
   675  	}
   676  }
   677  
   678  //setnodeuserident从cli标志创建用户标识符。
   679  func setNodeUserIdent(ctx *cli.Context, cfg *node.Config) {
   680  	if identity := ctx.GlobalString(IdentityFlag.Name); len(identity) > 0 {
   681  		cfg.UserIdent = identity
   682  	}
   683  }
   684  
   685  //setbootstrapnodes从命令行创建引导节点列表
   686  //标记,如果未指定,则恢复为预配置的标记。
   687  func setBootstrapNodes(ctx *cli.Context, cfg *p2p.Config) {
   688  	urls := params.MainnetBootnodes
   689  	switch {
   690  	case ctx.GlobalIsSet(BootnodesFlag.Name) || ctx.GlobalIsSet(BootnodesV4Flag.Name):
   691  		if ctx.GlobalIsSet(BootnodesV4Flag.Name) {
   692  			urls = strings.Split(ctx.GlobalString(BootnodesV4Flag.Name), ",")
   693  		} else {
   694  			urls = strings.Split(ctx.GlobalString(BootnodesFlag.Name), ",")
   695  		}
   696  	case ctx.GlobalBool(TestnetFlag.Name):
   697  		urls = params.TestnetBootnodes
   698  	case ctx.GlobalBool(RinkebyFlag.Name):
   699  		urls = params.RinkebyBootnodes
   700  	case cfg.BootstrapNodes != nil:
   701  return //已设置,不应用默认值。
   702  	}
   703  
   704  	cfg.BootstrapNodes = make([]*enode.Node, 0, len(urls))
   705  	for _, url := range urls {
   706  		node, err := enode.ParseV4(url)
   707  		if err != nil {
   708  			log.Crit("Bootstrap URL invalid", "enode", url, "err", err)
   709  		}
   710  		cfg.BootstrapNodes = append(cfg.BootstrapNodes, node)
   711  	}
   712  }
   713  
   714  //setbootstrapnodesv5从命令行创建引导节点列表
   715  //标记,如果未指定,则恢复为预配置的标记。
   716  func setBootstrapNodesV5(ctx *cli.Context, cfg *p2p.Config) {
   717  	urls := params.DiscoveryV5Bootnodes
   718  	switch {
   719  	case ctx.GlobalIsSet(BootnodesFlag.Name) || ctx.GlobalIsSet(BootnodesV5Flag.Name):
   720  		if ctx.GlobalIsSet(BootnodesV5Flag.Name) {
   721  			urls = strings.Split(ctx.GlobalString(BootnodesV5Flag.Name), ",")
   722  		} else {
   723  			urls = strings.Split(ctx.GlobalString(BootnodesFlag.Name), ",")
   724  		}
   725  	case ctx.GlobalBool(RinkebyFlag.Name):
   726  		urls = params.RinkebyBootnodes
   727  	case cfg.BootstrapNodesV5 != nil:
   728  return //已设置,不应用默认值。
   729  	}
   730  
   731  	cfg.BootstrapNodesV5 = make([]*discv5.Node, 0, len(urls))
   732  	for _, url := range urls {
   733  		node, err := discv5.ParseNode(url)
   734  		if err != nil {
   735  			log.Error("Bootstrap URL invalid", "enode", url, "err", err)
   736  			continue
   737  		}
   738  		cfg.BootstrapNodesV5 = append(cfg.BootstrapNodesV5, node)
   739  	}
   740  }
   741  
   742  //setlistenaddress从set命令创建TCP侦听地址字符串
   743  //行标志。
   744  func setListenAddress(ctx *cli.Context, cfg *p2p.Config) {
   745  	if ctx.GlobalIsSet(ListenPortFlag.Name) {
   746  		cfg.ListenAddr = fmt.Sprintf(":%d", ctx.GlobalInt(ListenPortFlag.Name))
   747  	}
   748  }
   749  
   750  //setnat从命令行标志创建端口映射器。
   751  func setNAT(ctx *cli.Context, cfg *p2p.Config) {
   752  	if ctx.GlobalIsSet(NATFlag.Name) {
   753  		natif, err := nat.Parse(ctx.GlobalString(NATFlag.Name))
   754  		if err != nil {
   755  			Fatalf("Option %s: %v", NATFlag.Name, err)
   756  		}
   757  		cfg.NAT = natif
   758  	}
   759  }
   760  
   761  //splitandtrim拆分由逗号分隔的输入
   762  //并修剪子字符串中多余的空白。
   763  func splitAndTrim(input string) []string {
   764  	result := strings.Split(input, ",")
   765  	for i, r := range result {
   766  		result[i] = strings.TrimSpace(r)
   767  	}
   768  	return result
   769  }
   770  
   771  //set http从集合创建HTTP RPC侦听器接口字符串
   772  //命令行标志,如果禁用HTTP端点,则返回空。
   773  func setHTTP(ctx *cli.Context, cfg *node.Config) {
   774  	if ctx.GlobalBool(RPCEnabledFlag.Name) && cfg.HTTPHost == "" {
   775  		cfg.HTTPHost = "127.0.0.1"
   776  		if ctx.GlobalIsSet(RPCListenAddrFlag.Name) {
   777  			cfg.HTTPHost = ctx.GlobalString(RPCListenAddrFlag.Name)
   778  		}
   779  	}
   780  
   781  	if ctx.GlobalIsSet(RPCPortFlag.Name) {
   782  		cfg.HTTPPort = ctx.GlobalInt(RPCPortFlag.Name)
   783  	}
   784  	if ctx.GlobalIsSet(RPCCORSDomainFlag.Name) {
   785  		cfg.HTTPCors = splitAndTrim(ctx.GlobalString(RPCCORSDomainFlag.Name))
   786  	}
   787  	if ctx.GlobalIsSet(RPCApiFlag.Name) {
   788  		cfg.HTTPModules = splitAndTrim(ctx.GlobalString(RPCApiFlag.Name))
   789  	}
   790  	if ctx.GlobalIsSet(RPCVirtualHostsFlag.Name) {
   791  		cfg.HTTPVirtualHosts = splitAndTrim(ctx.GlobalString(RPCVirtualHostsFlag.Name))
   792  	}
   793  }
   794  
   795  //setws从集合创建websocket rpc侦听器接口字符串
   796  //命令行标志,如果禁用HTTP端点,则返回空。
   797  func setWS(ctx *cli.Context, cfg *node.Config) {
   798  	if ctx.GlobalBool(WSEnabledFlag.Name) && cfg.WSHost == "" {
   799  		cfg.WSHost = "127.0.0.1"
   800  		if ctx.GlobalIsSet(WSListenAddrFlag.Name) {
   801  			cfg.WSHost = ctx.GlobalString(WSListenAddrFlag.Name)
   802  		}
   803  	}
   804  
   805  	if ctx.GlobalIsSet(WSPortFlag.Name) {
   806  		cfg.WSPort = ctx.GlobalInt(WSPortFlag.Name)
   807  	}
   808  	if ctx.GlobalIsSet(WSAllowedOriginsFlag.Name) {
   809  		cfg.WSOrigins = splitAndTrim(ctx.GlobalString(WSAllowedOriginsFlag.Name))
   810  	}
   811  	if ctx.GlobalIsSet(WSApiFlag.Name) {
   812  		cfg.WSModules = splitAndTrim(ctx.GlobalString(WSApiFlag.Name))
   813  	}
   814  }
   815  
   816  //set ipc从set命令行标志创建ipc路径配置,
   817  //如果显式禁用了IPC或设置的路径,则返回空字符串。
   818  func setIPC(ctx *cli.Context, cfg *node.Config) {
   819  	checkExclusive(ctx, IPCDisabledFlag, IPCPathFlag)
   820  	switch {
   821  	case ctx.GlobalBool(IPCDisabledFlag.Name):
   822  		cfg.IPCPath = ""
   823  	case ctx.GlobalIsSet(IPCPathFlag.Name):
   824  		cfg.IPCPath = ctx.GlobalString(IPCPathFlag.Name)
   825  	}
   826  }
   827  
   828  //makedatabasehandles引发每个进程允许的文件句柄数
   829  //并返回要分配给数据库的津贴的一半。
   830  func makeDatabaseHandles() int {
   831  	limit, err := fdlimit.Maximum()
   832  	if err != nil {
   833  		Fatalf("Failed to retrieve file descriptor allowance: %v", err)
   834  	}
   835  	if err := fdlimit.Raise(uint64(limit)); err != nil {
   836  		Fatalf("Failed to raise file descriptor allowance: %v", err)
   837  	}
   838  return limit / 2 //留下一半用于网络和其他东西
   839  }
   840  
   841  //makeaddress转换直接指定为十六进制编码字符串或
   842  //内部帐户表示形式的密钥存储中的密钥索引。
   843  func MakeAddress(ks *keystore.KeyStore, account string) (accounts.Account, error) {
   844  //如果指定的帐户是有效地址,请将其返回
   845  	if common.IsHexAddress(account) {
   846  		return accounts.Account{Address: common.HexToAddress(account)}, nil
   847  	}
   848  //否则,尝试将帐户解释为密钥存储索引
   849  	index, err := strconv.Atoi(account)
   850  	if err != nil || index < 0 {
   851  		return accounts.Account{}, fmt.Errorf("invalid account address or index %q", account)
   852  	}
   853  	log.Warn("-------------------------------------------------------------------")
   854  	log.Warn("Referring to accounts by order in the keystore folder is dangerous!")
   855  	log.Warn("This functionality is deprecated and will be removed in the future!")
   856  	log.Warn("Please use explicit addresses! (can search via `geth account list`)")
   857  	log.Warn("-------------------------------------------------------------------")
   858  
   859  	accs := ks.Accounts()
   860  	if len(accs) <= index {
   861  		return accounts.Account{}, fmt.Errorf("index %d higher than number of accounts %d", index, len(accs))
   862  	}
   863  	return accs[index], nil
   864  }
   865  
   866  //
   867  //命令行标志或来自keystore(如果为cli编制了索引)。
   868  func setEtherbase(ctx *cli.Context, ks *keystore.KeyStore, cfg *eth.Config) {
   869  //提取当前的EtherBase,新标志覆盖旧标志
   870  	var etherbase string
   871  	if ctx.GlobalIsSet(MinerLegacyEtherbaseFlag.Name) {
   872  		etherbase = ctx.GlobalString(MinerLegacyEtherbaseFlag.Name)
   873  	}
   874  	if ctx.GlobalIsSet(MinerEtherbaseFlag.Name) {
   875  		etherbase = ctx.GlobalString(MinerEtherbaseFlag.Name)
   876  	}
   877  //将EtherBase转换为地址并进行配置
   878  	if etherbase != "" {
   879  		account, err := MakeAddress(ks, etherbase)
   880  		if err != nil {
   881  			Fatalf("Invalid miner etherbase: %v", err)
   882  		}
   883  		cfg.Etherbase = account.Address
   884  	}
   885  }
   886  
   887  //makepasswordlist从global--password标志指定的文件中读取密码行。
   888  func MakePasswordList(ctx *cli.Context) []string {
   889  	path := ctx.GlobalString(PasswordFileFlag.Name)
   890  	if path == "" {
   891  		return nil
   892  	}
   893  	text, err := ioutil.ReadFile(path)
   894  	if err != nil {
   895  		Fatalf("Failed to read password file: %v", err)
   896  	}
   897  	lines := strings.Split(string(text), "\n")
   898  //对DOS行结尾进行消毒。
   899  	for i := range lines {
   900  		lines[i] = strings.TrimRight(lines[i], "\r")
   901  	}
   902  	return lines
   903  }
   904  
   905  func SetP2PConfig(ctx *cli.Context, cfg *p2p.Config) {
   906  	setNodeKey(ctx, cfg)
   907  	setNAT(ctx, cfg)
   908  	setListenAddress(ctx, cfg)
   909  	setBootstrapNodes(ctx, cfg)
   910  	setBootstrapNodesV5(ctx, cfg)
   911  
   912  	lightClient := ctx.GlobalString(SyncModeFlag.Name) == "light"
   913  	lightServer := ctx.GlobalInt(LightServFlag.Name) != 0
   914  	lightPeers := ctx.GlobalInt(LightPeersFlag.Name)
   915  
   916  	if ctx.GlobalIsSet(MaxPeersFlag.Name) {
   917  		cfg.MaxPeers = ctx.GlobalInt(MaxPeersFlag.Name)
   918  		if lightServer && !ctx.GlobalIsSet(LightPeersFlag.Name) {
   919  			cfg.MaxPeers += lightPeers
   920  		}
   921  	} else {
   922  		if lightServer {
   923  			cfg.MaxPeers += lightPeers
   924  		}
   925  		if lightClient && ctx.GlobalIsSet(LightPeersFlag.Name) && cfg.MaxPeers < lightPeers {
   926  			cfg.MaxPeers = lightPeers
   927  		}
   928  	}
   929  	if !(lightClient || lightServer) {
   930  		lightPeers = 0
   931  	}
   932  	ethPeers := cfg.MaxPeers - lightPeers
   933  	if lightClient {
   934  		ethPeers = 0
   935  	}
   936  	log.Info("Maximum peer count", "ETH", ethPeers, "LES", lightPeers, "total", cfg.MaxPeers)
   937  
   938  	if ctx.GlobalIsSet(MaxPendingPeersFlag.Name) {
   939  		cfg.MaxPendingPeers = ctx.GlobalInt(MaxPendingPeersFlag.Name)
   940  	}
   941  	if ctx.GlobalIsSet(NoDiscoverFlag.Name) || lightClient {
   942  		cfg.NoDiscovery = true
   943  	}
   944  
   945  //如果我们运行的是轻型客户端或服务器,则强制启用v5对等机发现
   946  //除非使用--nodiscover显式禁用它,否则请注意显式指定
   947  //--v5disc overrides--nodiscover,在这种情况下,后者只禁用v4发现
   948  	forceV5Discovery := (lightClient || lightServer) && !ctx.GlobalBool(NoDiscoverFlag.Name)
   949  	if ctx.GlobalIsSet(DiscoveryV5Flag.Name) {
   950  		cfg.DiscoveryV5 = ctx.GlobalBool(DiscoveryV5Flag.Name)
   951  	} else if forceV5Discovery {
   952  		cfg.DiscoveryV5 = true
   953  	}
   954  
   955  	if netrestrict := ctx.GlobalString(NetrestrictFlag.Name); netrestrict != "" {
   956  		list, err := netutil.ParseNetlist(netrestrict)
   957  		if err != nil {
   958  			Fatalf("Option %q: %v", NetrestrictFlag.Name, err)
   959  		}
   960  		cfg.NetRestrict = list
   961  	}
   962  
   963  	if ctx.GlobalBool(DeveloperFlag.Name) {
   964  //--dev模式不能使用p2p网络。
   965  		cfg.MaxPeers = 0
   966  		cfg.ListenAddr = ":0"
   967  		cfg.NoDiscovery = true
   968  		cfg.DiscoveryV5 = false
   969  	}
   970  }
   971  
   972  //setnodeconfig将与节点相关的命令行标志应用于配置。
   973  func SetNodeConfig(ctx *cli.Context, cfg *node.Config) {
   974  	SetP2PConfig(ctx, &cfg.P2P)
   975  	setIPC(ctx, cfg)
   976  	setHTTP(ctx, cfg)
   977  	setWS(ctx, cfg)
   978  	setNodeUserIdent(ctx, cfg)
   979  
   980  	setDataDir(ctx, cfg)
   981  
   982  	if ctx.GlobalIsSet(KeyStoreDirFlag.Name) {
   983  		cfg.KeyStoreDir = ctx.GlobalString(KeyStoreDirFlag.Name)
   984  	}
   985  	if ctx.GlobalIsSet(LightKDFFlag.Name) {
   986  		cfg.UseLightweightKDF = ctx.GlobalBool(LightKDFFlag.Name)
   987  	}
   988  	if ctx.GlobalIsSet(NoUSBFlag.Name) {
   989  		cfg.NoUSB = ctx.GlobalBool(NoUSBFlag.Name)
   990  	}
   991  }
   992  
   993  func setDataDir(ctx *cli.Context, cfg *node.Config) {
   994  	switch {
   995  	case ctx.GlobalIsSet(DataDirFlag.Name):
   996  		cfg.DataDir = ctx.GlobalString(DataDirFlag.Name)
   997  	case ctx.GlobalBool(DeveloperFlag.Name):
   998  cfg.DataDir = "" //除非明确要求,否则使用内存数据库
   999  	case ctx.GlobalBool(TestnetFlag.Name):
  1000  		cfg.DataDir = filepath.Join(node.DefaultDataDir(), "testnet")
  1001  	case ctx.GlobalBool(RinkebyFlag.Name):
  1002  		cfg.DataDir = filepath.Join(node.DefaultDataDir(), "rinkeby")
  1003  	}
  1004  }
  1005  
  1006  func setGPO(ctx *cli.Context, cfg *gasprice.Config) {
  1007  	if ctx.GlobalIsSet(GpoBlocksFlag.Name) {
  1008  		cfg.Blocks = ctx.GlobalInt(GpoBlocksFlag.Name)
  1009  	}
  1010  	if ctx.GlobalIsSet(GpoPercentileFlag.Name) {
  1011  		cfg.Percentile = ctx.GlobalInt(GpoPercentileFlag.Name)
  1012  	}
  1013  }
  1014  
  1015  func setTxPool(ctx *cli.Context, cfg *core.TxPoolConfig) {
  1016  	if ctx.GlobalIsSet(TxPoolLocalsFlag.Name) {
  1017  		locals := strings.Split(ctx.GlobalString(TxPoolLocalsFlag.Name), ",")
  1018  		for _, account := range locals {
  1019  			if trimmed := strings.TrimSpace(account); !common.IsHexAddress(trimmed) {
  1020  				Fatalf("Invalid account in --txpool.locals: %s", trimmed)
  1021  			} else {
  1022  				cfg.Locals = append(cfg.Locals, common.HexToAddress(account))
  1023  			}
  1024  		}
  1025  	}
  1026  	if ctx.GlobalIsSet(TxPoolNoLocalsFlag.Name) {
  1027  		cfg.NoLocals = ctx.GlobalBool(TxPoolNoLocalsFlag.Name)
  1028  	}
  1029  	if ctx.GlobalIsSet(TxPoolJournalFlag.Name) {
  1030  		cfg.Journal = ctx.GlobalString(TxPoolJournalFlag.Name)
  1031  	}
  1032  	if ctx.GlobalIsSet(TxPoolRejournalFlag.Name) {
  1033  		cfg.Rejournal = ctx.GlobalDuration(TxPoolRejournalFlag.Name)
  1034  	}
  1035  	if ctx.GlobalIsSet(TxPoolPriceLimitFlag.Name) {
  1036  		cfg.PriceLimit = ctx.GlobalUint64(TxPoolPriceLimitFlag.Name)
  1037  	}
  1038  	if ctx.GlobalIsSet(TxPoolPriceBumpFlag.Name) {
  1039  		cfg.PriceBump = ctx.GlobalUint64(TxPoolPriceBumpFlag.Name)
  1040  	}
  1041  	if ctx.GlobalIsSet(TxPoolAccountSlotsFlag.Name) {
  1042  		cfg.AccountSlots = ctx.GlobalUint64(TxPoolAccountSlotsFlag.Name)
  1043  	}
  1044  	if ctx.GlobalIsSet(TxPoolGlobalSlotsFlag.Name) {
  1045  		cfg.GlobalSlots = ctx.GlobalUint64(TxPoolGlobalSlotsFlag.Name)
  1046  	}
  1047  	if ctx.GlobalIsSet(TxPoolAccountQueueFlag.Name) {
  1048  		cfg.AccountQueue = ctx.GlobalUint64(TxPoolAccountQueueFlag.Name)
  1049  	}
  1050  	if ctx.GlobalIsSet(TxPoolGlobalQueueFlag.Name) {
  1051  		cfg.GlobalQueue = ctx.GlobalUint64(TxPoolGlobalQueueFlag.Name)
  1052  	}
  1053  	if ctx.GlobalIsSet(TxPoolLifetimeFlag.Name) {
  1054  		cfg.Lifetime = ctx.GlobalDuration(TxPoolLifetimeFlag.Name)
  1055  	}
  1056  }
  1057  
  1058  func setEthash(ctx *cli.Context, cfg *eth.Config) {
  1059  	if ctx.GlobalIsSet(EthashCacheDirFlag.Name) {
  1060  		cfg.Ethash.CacheDir = ctx.GlobalString(EthashCacheDirFlag.Name)
  1061  	}
  1062  	if ctx.GlobalIsSet(EthashDatasetDirFlag.Name) {
  1063  		cfg.Ethash.DatasetDir = ctx.GlobalString(EthashDatasetDirFlag.Name)
  1064  	}
  1065  	if ctx.GlobalIsSet(EthashCachesInMemoryFlag.Name) {
  1066  		cfg.Ethash.CachesInMem = ctx.GlobalInt(EthashCachesInMemoryFlag.Name)
  1067  	}
  1068  	if ctx.GlobalIsSet(EthashCachesOnDiskFlag.Name) {
  1069  		cfg.Ethash.CachesOnDisk = ctx.GlobalInt(EthashCachesOnDiskFlag.Name)
  1070  	}
  1071  	if ctx.GlobalIsSet(EthashDatasetsInMemoryFlag.Name) {
  1072  		cfg.Ethash.DatasetsInMem = ctx.GlobalInt(EthashDatasetsInMemoryFlag.Name)
  1073  	}
  1074  	if ctx.GlobalIsSet(EthashDatasetsOnDiskFlag.Name) {
  1075  		cfg.Ethash.DatasetsOnDisk = ctx.GlobalInt(EthashDatasetsOnDiskFlag.Name)
  1076  	}
  1077  }
  1078  
  1079  func setWhitelist(ctx *cli.Context, cfg *eth.Config) {
  1080  	whitelist := ctx.GlobalString(WhitelistFlag.Name)
  1081  	if whitelist == "" {
  1082  		return
  1083  	}
  1084  	cfg.Whitelist = make(map[uint64]common.Hash)
  1085  	for _, entry := range strings.Split(whitelist, ",") {
  1086  		parts := strings.Split(entry, "=")
  1087  		if len(parts) != 2 {
  1088  			Fatalf("Invalid whitelist entry: %s", entry)
  1089  		}
  1090  		number, err := strconv.ParseUint(parts[0], 0, 64)
  1091  		if err != nil {
  1092  			Fatalf("Invalid whitelist block number %s: %v", parts[0], err)
  1093  		}
  1094  		var hash common.Hash
  1095  		if err = hash.UnmarshalText([]byte(parts[1])); err != nil {
  1096  			Fatalf("Invalid whitelist hash %s: %v", parts[1], err)
  1097  		}
  1098  		cfg.Whitelist[number] = hash
  1099  	}
  1100  }
  1101  
  1102  //checkExclusive验证提供的标志只有一个实例
  1103  //由用户设置。每个标志后面可以选择跟一个字符串类型
  1104  //进一步专业化。
  1105  func checkExclusive(ctx *cli.Context, args ...interface{}) {
  1106  	set := make([]string, 0, 1)
  1107  	for i := 0; i < len(args); i++ {
  1108  //确保下一个参数是标志,如果未设置,则跳过。
  1109  		flag, ok := args[i].(cli.Flag)
  1110  		if !ok {
  1111  			panic(fmt.Sprintf("invalid argument, not cli.Flag type: %T", args[i]))
  1112  		}
  1113  //检查next参数是否扩展当前参数,如果扩展,则扩展其名称
  1114  		name := flag.GetName()
  1115  
  1116  		if i+1 < len(args) {
  1117  			switch option := args[i+1].(type) {
  1118  			case string:
  1119  //扩展标志检查,确保值集与传入选项不冲突
  1120  				if ctx.GlobalString(flag.GetName()) == option {
  1121  					name += "=" + option
  1122  					set = append(set, "--"+name)
  1123  				}
  1124  //移位参数并继续
  1125  				i++
  1126  				continue
  1127  
  1128  			case cli.Flag:
  1129  			default:
  1130  				panic(fmt.Sprintf("invalid argument, not cli.Flag or string extension: %T", args[i+1]))
  1131  			}
  1132  		}
  1133  //如果旗子已经设置好,就标记它
  1134  		if ctx.GlobalIsSet(flag.GetName()) {
  1135  			set = append(set, "--"+name)
  1136  		}
  1137  	}
  1138  	if len(set) > 1 {
  1139  		Fatalf("Flags %v can't be used at the same time", strings.Join(set, ", "))
  1140  	}
  1141  }
  1142  
  1143  //setshhconfig将与shh相关的命令行标志应用于配置。
  1144  func SetShhConfig(ctx *cli.Context, stack *node.Node, cfg *whisper.Config) {
  1145  	if ctx.GlobalIsSet(WhisperMaxMessageSizeFlag.Name) {
  1146  		cfg.MaxMessageSize = uint32(ctx.GlobalUint(WhisperMaxMessageSizeFlag.Name))
  1147  	}
  1148  	if ctx.GlobalIsSet(WhisperMinPOWFlag.Name) {
  1149  		cfg.MinimumAcceptedPOW = ctx.GlobalFloat64(WhisperMinPOWFlag.Name)
  1150  	}
  1151  	if ctx.GlobalIsSet(WhisperRestrictConnectionBetweenLightClientsFlag.Name) {
  1152  		cfg.RestrictConnectionBetweenLightClients = true
  1153  	}
  1154  }
  1155  
  1156  //setethconfig将与eth相关的命令行标志应用于配置。
  1157  func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *eth.Config) {
  1158  //避免冲突的网络标志
  1159  	checkExclusive(ctx, DeveloperFlag, TestnetFlag, RinkebyFlag)
  1160  	checkExclusive(ctx, LightServFlag, SyncModeFlag, "light")
  1161  
  1162  	ks := stack.AccountManager().Backends(keystore.KeyStoreType)[0].(*keystore.KeyStore)
  1163  	setEtherbase(ctx, ks, cfg)
  1164  	setGPO(ctx, &cfg.GPO)
  1165  	setTxPool(ctx, &cfg.TxPool)
  1166  	setEthash(ctx, cfg)
  1167  	setWhitelist(ctx, cfg)
  1168  
  1169  	if ctx.GlobalIsSet(SyncModeFlag.Name) {
  1170  		cfg.SyncMode = *GlobalTextMarshaler(ctx, SyncModeFlag.Name).(*downloader.SyncMode)
  1171  	}
  1172  	if ctx.GlobalIsSet(LightServFlag.Name) {
  1173  		cfg.LightServ = ctx.GlobalInt(LightServFlag.Name)
  1174  	}
  1175  	if ctx.GlobalIsSet(LightPeersFlag.Name) {
  1176  		cfg.LightPeers = ctx.GlobalInt(LightPeersFlag.Name)
  1177  	}
  1178  	if ctx.GlobalIsSet(NetworkIdFlag.Name) {
  1179  		cfg.NetworkId = ctx.GlobalUint64(NetworkIdFlag.Name)
  1180  	}
  1181  	if ctx.GlobalIsSet(CacheFlag.Name) || ctx.GlobalIsSet(CacheDatabaseFlag.Name) {
  1182  		cfg.DatabaseCache = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheDatabaseFlag.Name) / 100
  1183  	}
  1184  	cfg.DatabaseHandles = makeDatabaseHandles()
  1185  
  1186  	if gcmode := ctx.GlobalString(GCModeFlag.Name); gcmode != "full" && gcmode != "archive" {
  1187  		Fatalf("--%s must be either 'full' or 'archive'", GCModeFlag.Name)
  1188  	}
  1189  	cfg.NoPruning = ctx.GlobalString(GCModeFlag.Name) == "archive"
  1190  
  1191  	if ctx.GlobalIsSet(CacheFlag.Name) || ctx.GlobalIsSet(CacheTrieFlag.Name) {
  1192  		cfg.TrieCleanCache = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheTrieFlag.Name) / 100
  1193  	}
  1194  	if ctx.GlobalIsSet(CacheFlag.Name) || ctx.GlobalIsSet(CacheGCFlag.Name) {
  1195  		cfg.TrieDirtyCache = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheGCFlag.Name) / 100
  1196  	}
  1197  	if ctx.GlobalIsSet(MinerNotifyFlag.Name) {
  1198  		cfg.MinerNotify = strings.Split(ctx.GlobalString(MinerNotifyFlag.Name), ",")
  1199  	}
  1200  	if ctx.GlobalIsSet(DocRootFlag.Name) {
  1201  		cfg.DocRoot = ctx.GlobalString(DocRootFlag.Name)
  1202  	}
  1203  	if ctx.GlobalIsSet(MinerLegacyExtraDataFlag.Name) {
  1204  		cfg.MinerExtraData = []byte(ctx.GlobalString(MinerLegacyExtraDataFlag.Name))
  1205  	}
  1206  	if ctx.GlobalIsSet(MinerExtraDataFlag.Name) {
  1207  		cfg.MinerExtraData = []byte(ctx.GlobalString(MinerExtraDataFlag.Name))
  1208  	}
  1209  	if ctx.GlobalIsSet(MinerLegacyGasTargetFlag.Name) {
  1210  		cfg.MinerGasFloor = ctx.GlobalUint64(MinerLegacyGasTargetFlag.Name)
  1211  	}
  1212  	if ctx.GlobalIsSet(MinerGasTargetFlag.Name) {
  1213  		cfg.MinerGasFloor = ctx.GlobalUint64(MinerGasTargetFlag.Name)
  1214  	}
  1215  	if ctx.GlobalIsSet(MinerGasLimitFlag.Name) {
  1216  		cfg.MinerGasCeil = ctx.GlobalUint64(MinerGasLimitFlag.Name)
  1217  	}
  1218  	if ctx.GlobalIsSet(MinerLegacyGasPriceFlag.Name) {
  1219  		cfg.MinerGasPrice = GlobalBig(ctx, MinerLegacyGasPriceFlag.Name)
  1220  	}
  1221  	if ctx.GlobalIsSet(MinerGasPriceFlag.Name) {
  1222  		cfg.MinerGasPrice = GlobalBig(ctx, MinerGasPriceFlag.Name)
  1223  	}
  1224  	if ctx.GlobalIsSet(MinerRecommitIntervalFlag.Name) {
  1225  		cfg.MinerRecommit = ctx.Duration(MinerRecommitIntervalFlag.Name)
  1226  	}
  1227  	if ctx.GlobalIsSet(MinerNoVerfiyFlag.Name) {
  1228  		cfg.MinerNoverify = ctx.Bool(MinerNoVerfiyFlag.Name)
  1229  	}
  1230  	if ctx.GlobalIsSet(VMEnableDebugFlag.Name) {
  1231  //TODO(FJL):强制启用--dev模式
  1232  		cfg.EnablePreimageRecording = ctx.GlobalBool(VMEnableDebugFlag.Name)
  1233  	}
  1234  
  1235  	if ctx.GlobalIsSet(EWASMInterpreterFlag.Name) {
  1236  		cfg.EWASMInterpreter = ctx.GlobalString(EWASMInterpreterFlag.Name)
  1237  	}
  1238  
  1239  	if ctx.GlobalIsSet(EVMInterpreterFlag.Name) {
  1240  		cfg.EVMInterpreter = ctx.GlobalString(EVMInterpreterFlag.Name)
  1241  	}
  1242  
  1243  //覆盖硬编码网络的任何默认配置。
  1244  	switch {
  1245  	case ctx.GlobalBool(TestnetFlag.Name):
  1246  		if !ctx.GlobalIsSet(NetworkIdFlag.Name) {
  1247  			cfg.NetworkId = 3
  1248  		}
  1249  		cfg.Genesis = core.DefaultTestnetGenesisBlock()
  1250  	case ctx.GlobalBool(RinkebyFlag.Name):
  1251  		if !ctx.GlobalIsSet(NetworkIdFlag.Name) {
  1252  			cfg.NetworkId = 4
  1253  		}
  1254  		cfg.Genesis = core.DefaultRinkebyGenesisBlock()
  1255  	case ctx.GlobalBool(DeveloperFlag.Name):
  1256  		if !ctx.GlobalIsSet(NetworkIdFlag.Name) {
  1257  			cfg.NetworkId = 1337
  1258  		}
  1259  //创建新的开发人员帐户或重用现有帐户
  1260  		var (
  1261  			developer accounts.Account
  1262  			err       error
  1263  		)
  1264  		if accs := ks.Accounts(); len(accs) > 0 {
  1265  			developer = ks.Accounts()[0]
  1266  		} else {
  1267  			developer, err = ks.NewAccount("")
  1268  			if err != nil {
  1269  				Fatalf("Failed to create developer account: %v", err)
  1270  			}
  1271  		}
  1272  		if err := ks.Unlock(developer, ""); err != nil {
  1273  			Fatalf("Failed to unlock developer account: %v", err)
  1274  		}
  1275  		log.Info("Using developer account", "address", developer.Address)
  1276  
  1277  		cfg.Genesis = core.DeveloperGenesisBlock(uint64(ctx.GlobalInt(DeveloperPeriodFlag.Name)), developer.Address)
  1278  		if !ctx.GlobalIsSet(MinerGasPriceFlag.Name) && !ctx.GlobalIsSet(MinerLegacyGasPriceFlag.Name) {
  1279  			cfg.MinerGasPrice = big.NewInt(1)
  1280  		}
  1281  	}
  1282  //TODO(FJL):将trie缓存生成移动到配置中
  1283  	if gen := ctx.GlobalInt(TrieCacheGenFlag.Name); gen > 0 {
  1284  		state.MaxTrieCacheGen = uint16(gen)
  1285  	}
  1286  }
  1287  
  1288  //setdashboardconfig将与仪表板相关的命令行标志应用于配置。
  1289  func SetDashboardConfig(ctx *cli.Context, cfg *dashboard.Config) {
  1290  	cfg.Host = ctx.GlobalString(DashboardAddrFlag.Name)
  1291  	cfg.Port = ctx.GlobalInt(DashboardPortFlag.Name)
  1292  	cfg.Refresh = ctx.GlobalDuration(DashboardRefreshFlag.Name)
  1293  }
  1294  
  1295  //registerethservice将以太坊客户端添加到堆栈中。
  1296  func RegisterEthService(stack *node.Node, cfg *eth.Config) {
  1297  	var err error
  1298  	if cfg.SyncMode == downloader.LightSync {
  1299  		err = stack.Register(func(ctx *node.ServiceContext) (node.Service, error) {
  1300  			return les.New(ctx, cfg)
  1301  		})
  1302  	} else {
  1303  		err = stack.Register(func(ctx *node.ServiceContext) (node.Service, error) {
  1304  			fullNode, err := eth.New(ctx, cfg)
  1305  			if fullNode != nil && cfg.LightServ > 0 {
  1306  				ls, _ := les.NewLesServer(fullNode, cfg)
  1307  				fullNode.AddLesServer(ls)
  1308  			}
  1309  			return fullNode, err
  1310  		})
  1311  	}
  1312  	if err != nil {
  1313  		Fatalf("Failed to register the Ethereum service: %v", err)
  1314  	}
  1315  }
  1316  
  1317  //
  1318  func RegisterDashboardService(stack *node.Node, cfg *dashboard.Config, commit string) {
  1319  	stack.Register(func(ctx *node.ServiceContext) (node.Service, error) {
  1320  		return dashboard.New(cfg, commit, ctx.ResolvePath("logs")), nil
  1321  	})
  1322  }
  1323  
  1324  //registershhservice配置whisper并将其添加到给定节点。
  1325  func RegisterShhService(stack *node.Node, cfg *whisper.Config) {
  1326  	if err := stack.Register(func(n *node.ServiceContext) (node.Service, error) {
  1327  		return whisper.New(cfg), nil
  1328  	}); err != nil {
  1329  		Fatalf("Failed to register the Whisper service: %v", err)
  1330  	}
  1331  }
  1332  
  1333  //registerethstattsservice配置ethereum stats守护进程并将其添加到
  1334  //给定节点。
  1335  func RegisterEthStatsService(stack *node.Node, url string) {
  1336  	if err := stack.Register(func(ctx *node.ServiceContext) (node.Service, error) {
  1337  //检索ETH和LES服务
  1338  		var ethServ *eth.Ethereum
  1339  		ctx.Service(&ethServ)
  1340  
  1341  		var lesServ *les.LightEthereum
  1342  		ctx.Service(&lesServ)
  1343  
  1344  		return ethstats.New(url, ethServ, lesServ)
  1345  	}); err != nil {
  1346  		Fatalf("Failed to register the Ethereum Stats service: %v", err)
  1347  	}
  1348  }
  1349  
  1350  func SetupMetrics(ctx *cli.Context) {
  1351  	if metrics.Enabled {
  1352  		log.Info("Enabling metrics collection")
  1353  		var (
  1354  			enableExport = ctx.GlobalBool(MetricsEnableInfluxDBFlag.Name)
  1355  			endpoint     = ctx.GlobalString(MetricsInfluxDBEndpointFlag.Name)
  1356  			database     = ctx.GlobalString(MetricsInfluxDBDatabaseFlag.Name)
  1357  			username     = ctx.GlobalString(MetricsInfluxDBUsernameFlag.Name)
  1358  			password     = ctx.GlobalString(MetricsInfluxDBPasswordFlag.Name)
  1359  			hosttag      = ctx.GlobalString(MetricsInfluxDBHostTagFlag.Name)
  1360  		)
  1361  
  1362  		if enableExport {
  1363  			log.Info("Enabling metrics export to InfluxDB")
  1364  			go influxdb.InfluxDBWithTags(metrics.DefaultRegistry, 10*time.Second, endpoint, database, username, password, "geth.", map[string]string{
  1365  				"host": hosttag,
  1366  			})
  1367  		}
  1368  	}
  1369  }
  1370  
  1371  //makechaindatabase使用传递给客户机的标志打开一个leveldb,如果失败,它将很难崩溃。
  1372  func MakeChainDatabase(ctx *cli.Context, stack *node.Node) ethdb.Database {
  1373  	var (
  1374  		cache   = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheDatabaseFlag.Name) / 100
  1375  		handles = makeDatabaseHandles()
  1376  	)
  1377  	name := "chaindata"
  1378  	if ctx.GlobalString(SyncModeFlag.Name) == "light" {
  1379  		name = "lightchaindata"
  1380  	}
  1381  	chainDb, err := stack.OpenDatabase(name, cache, handles)
  1382  	if err != nil {
  1383  		Fatalf("Could not open database: %v", err)
  1384  	}
  1385  	return chainDb
  1386  }
  1387  
  1388  func MakeGenesis(ctx *cli.Context) *core.Genesis {
  1389  	var genesis *core.Genesis
  1390  	switch {
  1391  	case ctx.GlobalBool(TestnetFlag.Name):
  1392  		genesis = core.DefaultTestnetGenesisBlock()
  1393  	case ctx.GlobalBool(RinkebyFlag.Name):
  1394  		genesis = core.DefaultRinkebyGenesisBlock()
  1395  	case ctx.GlobalBool(DeveloperFlag.Name):
  1396  		Fatalf("Developer chains are ephemeral")
  1397  	}
  1398  	return genesis
  1399  }
  1400  
  1401  //makechain从设置命令行标志创建链管理器。
  1402  func MakeChain(ctx *cli.Context, stack *node.Node) (chain *core.BlockChain, chainDb ethdb.Database) {
  1403  	var err error
  1404  	chainDb = MakeChainDatabase(ctx, stack)
  1405  	config, _, err := core.SetupGenesisBlock(chainDb, MakeGenesis(ctx))
  1406  	if err != nil {
  1407  		Fatalf("%v", err)
  1408  	}
  1409  	var engine consensus.Engine
  1410  	if config.Clique != nil {
  1411  		engine = clique.New(config.Clique, chainDb)
  1412  	} else {
  1413  		engine = ethash.NewFaker()
  1414  		if !ctx.GlobalBool(FakePoWFlag.Name) {
  1415  			engine = ethash.New(ethash.Config{
  1416  				CacheDir:       stack.ResolvePath(eth.DefaultConfig.Ethash.CacheDir),
  1417  				CachesInMem:    eth.DefaultConfig.Ethash.CachesInMem,
  1418  				CachesOnDisk:   eth.DefaultConfig.Ethash.CachesOnDisk,
  1419  				DatasetDir:     stack.ResolvePath(eth.DefaultConfig.Ethash.DatasetDir),
  1420  				DatasetsInMem:  eth.DefaultConfig.Ethash.DatasetsInMem,
  1421  				DatasetsOnDisk: eth.DefaultConfig.Ethash.DatasetsOnDisk,
  1422  			}, nil, false)
  1423  		}
  1424  	}
  1425  	if gcmode := ctx.GlobalString(GCModeFlag.Name); gcmode != "full" && gcmode != "archive" {
  1426  		Fatalf("--%s must be either 'full' or 'archive'", GCModeFlag.Name)
  1427  	}
  1428  	cache := &core.CacheConfig{
  1429  		Disabled:       ctx.GlobalString(GCModeFlag.Name) == "archive",
  1430  		TrieCleanLimit: eth.DefaultConfig.TrieCleanCache,
  1431  		TrieDirtyLimit: eth.DefaultConfig.TrieDirtyCache,
  1432  		TrieTimeLimit:  eth.DefaultConfig.TrieTimeout,
  1433  	}
  1434  	if ctx.GlobalIsSet(CacheFlag.Name) || ctx.GlobalIsSet(CacheTrieFlag.Name) {
  1435  		cache.TrieCleanLimit = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheTrieFlag.Name) / 100
  1436  	}
  1437  	if ctx.GlobalIsSet(CacheFlag.Name) || ctx.GlobalIsSet(CacheGCFlag.Name) {
  1438  		cache.TrieDirtyLimit = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheGCFlag.Name) / 100
  1439  	}
  1440  	vmcfg := vm.Config{EnablePreimageRecording: ctx.GlobalBool(VMEnableDebugFlag.Name)}
  1441  	chain, err = core.NewBlockChain(chainDb, cache, config, engine, vmcfg, nil)
  1442  	if err != nil {
  1443  		Fatalf("Can't create BlockChain: %v", err)
  1444  	}
  1445  	return chain, chainDb
  1446  }
  1447  
  1448  //makeconsolepreloads检索控制台javascript的绝对路径
  1449  //启动前要预加载的脚本。
  1450  func MakeConsolePreloads(ctx *cli.Context) []string {
  1451  //如果没有要预加载的内容,则跳过预加载
  1452  	if ctx.GlobalString(PreloadJSFlag.Name) == "" {
  1453  		return nil
  1454  	}
  1455  //否则,解析绝对路径并返回它们
  1456  	preloads := []string{}
  1457  
  1458  	assets := ctx.GlobalString(JSpathFlag.Name)
  1459  	for _, file := range strings.Split(ctx.GlobalString(PreloadJSFlag.Name), ",") {
  1460  		preloads = append(preloads, common.AbsolutePath(assets, strings.TrimSpace(file)))
  1461  	}
  1462  	return preloads
  1463  }
  1464  
  1465  //migrateflags在设置本地标志时从该标志设置全局标志。
  1466  //这是一个临时函数,用于将旧命令/标志迁移到
  1467  //新格式。
  1468  //
  1469  //例如,geth account new--keystore/tmp/mykeystore--lightkdf
  1470  //
  1471  //在用以下方法调用此方法后等效:
  1472  //
  1473  //geth--keystore/tmp/mykeystore--lightkdf新帐户
  1474  //
  1475  //这允许使用现有的配置功能。
  1476  //当迁移所有标志时,可以删除此函数,并且
  1477  //必须更改使用本地标志的配置功能
  1478  func MigrateFlags(action func(ctx *cli.Context) error) func(*cli.Context) error {
  1479  	return func(ctx *cli.Context) error {
  1480  		for _, name := range ctx.FlagNames() {
  1481  			if ctx.IsSet(name) {
  1482  				ctx.GlobalSet(name, ctx.String(name))
  1483  			}
  1484  		}
  1485  		return action(ctx)
  1486  	}
  1487  }
  1488