github.com/fly8eros/go-ethereum@v1.9.1/cmd/utils/flags.go (about)

     1  // Copyright 2015 The go-ethereum Authors
     2  // This file is part of go-ethereum.
     3  //
     4  // go-ethereum is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // go-ethereum is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU General Public License
    15  // along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  // Package utils contains internal helper functions for go-ethereum commands.
    18  package utils
    19  
    20  import (
    21  	"crypto/ecdsa"
    22  	"errors"
    23  	"fmt"
    24  	"io/ioutil"
    25  	"math/big"
    26  	"os"
    27  	"path/filepath"
    28  	"strconv"
    29  	"strings"
    30  	"time"
    31  
    32  	"github.com/ethereum/go-ethereum/accounts"
    33  	"github.com/ethereum/go-ethereum/accounts/keystore"
    34  	"github.com/ethereum/go-ethereum/common"
    35  	"github.com/ethereum/go-ethereum/common/fdlimit"
    36  	"github.com/ethereum/go-ethereum/consensus"
    37  	"github.com/ethereum/go-ethereum/consensus/clique"
    38  	"github.com/ethereum/go-ethereum/consensus/ethash"
    39  	"github.com/ethereum/go-ethereum/core"
    40  	"github.com/ethereum/go-ethereum/core/vm"
    41  	"github.com/ethereum/go-ethereum/crypto"
    42  	"github.com/ethereum/go-ethereum/dashboard"
    43  	"github.com/ethereum/go-ethereum/eth"
    44  	"github.com/ethereum/go-ethereum/eth/downloader"
    45  	"github.com/ethereum/go-ethereum/eth/gasprice"
    46  	"github.com/ethereum/go-ethereum/ethdb"
    47  	"github.com/ethereum/go-ethereum/ethstats"
    48  	"github.com/ethereum/go-ethereum/graphql"
    49  	"github.com/ethereum/go-ethereum/les"
    50  	"github.com/ethereum/go-ethereum/log"
    51  	"github.com/ethereum/go-ethereum/metrics"
    52  	"github.com/ethereum/go-ethereum/metrics/influxdb"
    53  	"github.com/ethereum/go-ethereum/miner"
    54  	"github.com/ethereum/go-ethereum/node"
    55  	"github.com/ethereum/go-ethereum/p2p"
    56  	"github.com/ethereum/go-ethereum/p2p/discv5"
    57  	"github.com/ethereum/go-ethereum/p2p/enode"
    58  	"github.com/ethereum/go-ethereum/p2p/nat"
    59  	"github.com/ethereum/go-ethereum/p2p/netutil"
    60  	"github.com/ethereum/go-ethereum/params"
    61  	"github.com/ethereum/go-ethereum/rpc"
    62  	whisper "github.com/ethereum/go-ethereum/whisper/whisperv6"
    63  	pcsclite "github.com/gballet/go-libpcsclite"
    64  	cli "gopkg.in/urfave/cli.v1"
    65  )
    66  
    67  var (
    68  	CommandHelpTemplate = `{{.cmd.Name}}{{if .cmd.Subcommands}} command{{end}}{{if .cmd.Flags}} [command options]{{end}} [arguments...]
    69  {{if .cmd.Description}}{{.cmd.Description}}
    70  {{end}}{{if .cmd.Subcommands}}
    71  SUBCOMMANDS:
    72  	{{range .cmd.Subcommands}}{{.Name}}{{with .ShortName}}, {{.}}{{end}}{{ "\t" }}{{.Usage}}
    73  	{{end}}{{end}}{{if .categorizedFlags}}
    74  {{range $idx, $categorized := .categorizedFlags}}{{$categorized.Name}} OPTIONS:
    75  {{range $categorized.Flags}}{{"\t"}}{{.}}
    76  {{end}}
    77  {{end}}{{end}}`
    78  )
    79  
    80  func init() {
    81  	cli.AppHelpTemplate = `{{.Name}} {{if .Flags}}[global options] {{end}}command{{if .Flags}} [command options]{{end}} [arguments...]
    82  
    83  VERSION:
    84     {{.Version}}
    85  
    86  COMMANDS:
    87     {{range .Commands}}{{.Name}}{{with .ShortName}}, {{.}}{{end}}{{ "\t" }}{{.Usage}}
    88     {{end}}{{if .Flags}}
    89  GLOBAL OPTIONS:
    90     {{range .Flags}}{{.}}
    91     {{end}}{{end}}
    92  `
    93  
    94  	cli.CommandHelpTemplate = CommandHelpTemplate
    95  }
    96  
    97  // NewApp creates an app with sane defaults.
    98  func NewApp(gitCommit, gitDate, usage string) *cli.App {
    99  	app := cli.NewApp()
   100  	app.Name = filepath.Base(os.Args[0])
   101  	app.Author = ""
   102  	app.Email = ""
   103  	app.Version = params.VersionWithCommit(gitCommit, gitDate)
   104  	app.Usage = usage
   105  	return app
   106  }
   107  
   108  // These are all the command line flags we support.
   109  // If you add to this list, please remember to include the
   110  // flag in the appropriate command definition.
   111  //
   112  // The flags are defined here so their names and help texts
   113  // are the same for all commands.
   114  
   115  var (
   116  	// General settings
   117  	DataDirFlag = DirectoryFlag{
   118  		Name:  "datadir",
   119  		Usage: "Data directory for the databases and keystore",
   120  		Value: DirectoryString{node.DefaultDataDir()},
   121  	}
   122  	AncientFlag = DirectoryFlag{
   123  		Name:  "datadir.ancient",
   124  		Usage: "Data directory for ancient chain segments (default = inside chaindata)",
   125  	}
   126  	KeyStoreDirFlag = DirectoryFlag{
   127  		Name:  "keystore",
   128  		Usage: "Directory for the keystore (default = inside the datadir)",
   129  	}
   130  	NoUSBFlag = cli.BoolFlag{
   131  		Name:  "nousb",
   132  		Usage: "Disables monitoring for and managing USB hardware wallets",
   133  	}
   134  	SmartCardDaemonPathFlag = cli.StringFlag{
   135  		Name:  "pcscdpath",
   136  		Usage: "Path to the smartcard daemon (pcscd) socket file",
   137  		Value: pcsclite.PCSCDSockName,
   138  	}
   139  	NetworkIdFlag = cli.Uint64Flag{
   140  		Name:  "networkid",
   141  		Usage: "Network identifier (integer, 1=Frontier, 2=Morden (disused), 3=Ropsten, 4=Rinkeby)",
   142  		Value: eth.DefaultConfig.NetworkId,
   143  	}
   144  	TestnetFlag = cli.BoolFlag{
   145  		Name:  "testnet",
   146  		Usage: "Ropsten network: pre-configured proof-of-work test network",
   147  	}
   148  	RinkebyFlag = cli.BoolFlag{
   149  		Name:  "rinkeby",
   150  		Usage: "Rinkeby network: pre-configured proof-of-authority test network",
   151  	}
   152  	GoerliFlag = cli.BoolFlag{
   153  		Name:  "goerli",
   154  		Usage: "Görli network: pre-configured proof-of-authority test network",
   155  	}
   156  	DeveloperFlag = cli.BoolFlag{
   157  		Name:  "dev",
   158  		Usage: "Ephemeral proof-of-authority network with a pre-funded developer account, mining enabled",
   159  	}
   160  	DeveloperPeriodFlag = cli.IntFlag{
   161  		Name:  "dev.period",
   162  		Usage: "Block period to use in developer mode (0 = mine only if transaction pending)",
   163  	}
   164  	IdentityFlag = cli.StringFlag{
   165  		Name:  "identity",
   166  		Usage: "Custom node name",
   167  	}
   168  	DocRootFlag = DirectoryFlag{
   169  		Name:  "docroot",
   170  		Usage: "Document Root for HTTPClient file scheme",
   171  		Value: DirectoryString{homeDir()},
   172  	}
   173  	ExitWhenSyncedFlag = cli.BoolFlag{
   174  		Name:  "exitwhensynced",
   175  		Usage: "Exits after block synchronisation completes",
   176  	}
   177  	IterativeOutputFlag = cli.BoolFlag{
   178  		Name:  "iterative",
   179  		Usage: "Print streaming JSON iteratively, delimited by newlines",
   180  	}
   181  	ExcludeStorageFlag = cli.BoolFlag{
   182  		Name:  "nostorage",
   183  		Usage: "Exclude storage entries (save db lookups)",
   184  	}
   185  	IncludeIncompletesFlag = cli.BoolFlag{
   186  		Name:  "incompletes",
   187  		Usage: "Include accounts for which we don't have the address (missing preimage)",
   188  	}
   189  	ExcludeCodeFlag = cli.BoolFlag{
   190  		Name:  "nocode",
   191  		Usage: "Exclude contract code (save db lookups)",
   192  	}
   193  	defaultSyncMode = eth.DefaultConfig.SyncMode
   194  	SyncModeFlag    = TextMarshalerFlag{
   195  		Name:  "syncmode",
   196  		Usage: `Blockchain sync mode ("fast", "full", or "light")`,
   197  		Value: &defaultSyncMode,
   198  	}
   199  	GCModeFlag = cli.StringFlag{
   200  		Name:  "gcmode",
   201  		Usage: `Blockchain garbage collection mode ("full", "archive")`,
   202  		Value: "full",
   203  	}
   204  	LightKDFFlag = cli.BoolFlag{
   205  		Name:  "lightkdf",
   206  		Usage: "Reduce key-derivation RAM & CPU usage at some expense of KDF strength",
   207  	}
   208  	WhitelistFlag = cli.StringFlag{
   209  		Name:  "whitelist",
   210  		Usage: "Comma separated block number-to-hash mappings to enforce (<number>=<hash>)",
   211  	}
   212  	// Light server and client settings
   213  	LightLegacyServFlag = cli.IntFlag{ // Deprecated in favor of light.serve, remove in 2021
   214  		Name:  "lightserv",
   215  		Usage: "Maximum percentage of time allowed for serving LES requests (deprecated, use --light.serve)",
   216  		Value: eth.DefaultConfig.LightServ,
   217  	}
   218  	LightServeFlag = cli.IntFlag{
   219  		Name:  "light.serve",
   220  		Usage: "Maximum percentage of time allowed for serving LES requests (multi-threaded processing allows values over 100)",
   221  		Value: eth.DefaultConfig.LightServ,
   222  	}
   223  	LightIngressFlag = cli.IntFlag{
   224  		Name:  "light.ingress",
   225  		Usage: "Incoming bandwidth limit for serving light clients (kilobytes/sec, 0 = unlimited)",
   226  		Value: eth.DefaultConfig.LightIngress,
   227  	}
   228  	LightEgressFlag = cli.IntFlag{
   229  		Name:  "light.egress",
   230  		Usage: "Outgoing bandwidth limit for serving light clients (kilobytes/sec, 0 = unlimited)",
   231  		Value: eth.DefaultConfig.LightEgress,
   232  	}
   233  	LightLegacyPeersFlag = cli.IntFlag{ // Deprecated in favor of light.maxpeers, remove in 2021
   234  		Name:  "lightpeers",
   235  		Usage: "Maximum number of light clients to serve, or light servers to attach to  (deprecated, use --light.maxpeers)",
   236  		Value: eth.DefaultConfig.LightPeers,
   237  	}
   238  	LightMaxPeersFlag = cli.IntFlag{
   239  		Name:  "light.maxpeers",
   240  		Usage: "Maximum number of light clients to serve, or light servers to attach to",
   241  		Value: eth.DefaultConfig.LightPeers,
   242  	}
   243  	UltraLightServersFlag = cli.StringFlag{
   244  		Name:  "ulc.servers",
   245  		Usage: "List of trusted ultra-light servers",
   246  		Value: strings.Join(eth.DefaultConfig.UltraLightServers, ","),
   247  	}
   248  	UltraLightFractionFlag = cli.IntFlag{
   249  		Name:  "ulc.fraction",
   250  		Usage: "Minimum % of trusted ultra-light servers required to announce a new head",
   251  		Value: eth.DefaultConfig.UltraLightFraction,
   252  	}
   253  	UltraLightOnlyAnnounceFlag = cli.BoolFlag{
   254  		Name:  "ulc.onlyannounce",
   255  		Usage: "Ultra light server sends announcements only",
   256  	}
   257  	// Dashboard settings
   258  	DashboardEnabledFlag = cli.BoolFlag{
   259  		Name:  "dashboard",
   260  		Usage: "Enable the dashboard",
   261  	}
   262  	DashboardAddrFlag = cli.StringFlag{
   263  		Name:  "dashboard.addr",
   264  		Usage: "Dashboard listening interface",
   265  		Value: dashboard.DefaultConfig.Host,
   266  	}
   267  	DashboardPortFlag = cli.IntFlag{
   268  		Name:  "dashboard.host",
   269  		Usage: "Dashboard listening port",
   270  		Value: dashboard.DefaultConfig.Port,
   271  	}
   272  	DashboardRefreshFlag = cli.DurationFlag{
   273  		Name:  "dashboard.refresh",
   274  		Usage: "Dashboard metrics collection refresh rate",
   275  		Value: dashboard.DefaultConfig.Refresh,
   276  	}
   277  	// Ethash settings
   278  	EthashCacheDirFlag = DirectoryFlag{
   279  		Name:  "ethash.cachedir",
   280  		Usage: "Directory to store the ethash verification caches (default = inside the datadir)",
   281  	}
   282  	EthashCachesInMemoryFlag = cli.IntFlag{
   283  		Name:  "ethash.cachesinmem",
   284  		Usage: "Number of recent ethash caches to keep in memory (16MB each)",
   285  		Value: eth.DefaultConfig.Ethash.CachesInMem,
   286  	}
   287  	EthashCachesOnDiskFlag = cli.IntFlag{
   288  		Name:  "ethash.cachesondisk",
   289  		Usage: "Number of recent ethash caches to keep on disk (16MB each)",
   290  		Value: eth.DefaultConfig.Ethash.CachesOnDisk,
   291  	}
   292  	EthashDatasetDirFlag = DirectoryFlag{
   293  		Name:  "ethash.dagdir",
   294  		Usage: "Directory to store the ethash mining DAGs (default = inside home folder)",
   295  		Value: DirectoryString{eth.DefaultConfig.Ethash.DatasetDir},
   296  	}
   297  	EthashDatasetsInMemoryFlag = cli.IntFlag{
   298  		Name:  "ethash.dagsinmem",
   299  		Usage: "Number of recent ethash mining DAGs to keep in memory (1+GB each)",
   300  		Value: eth.DefaultConfig.Ethash.DatasetsInMem,
   301  	}
   302  	EthashDatasetsOnDiskFlag = cli.IntFlag{
   303  		Name:  "ethash.dagsondisk",
   304  		Usage: "Number of recent ethash mining DAGs to keep on disk (1+GB each)",
   305  		Value: eth.DefaultConfig.Ethash.DatasetsOnDisk,
   306  	}
   307  	// Transaction pool settings
   308  	TxPoolLocalsFlag = cli.StringFlag{
   309  		Name:  "txpool.locals",
   310  		Usage: "Comma separated accounts to treat as locals (no flush, priority inclusion)",
   311  	}
   312  	TxPoolNoLocalsFlag = cli.BoolFlag{
   313  		Name:  "txpool.nolocals",
   314  		Usage: "Disables price exemptions for locally submitted transactions",
   315  	}
   316  	TxPoolJournalFlag = cli.StringFlag{
   317  		Name:  "txpool.journal",
   318  		Usage: "Disk journal for local transaction to survive node restarts",
   319  		Value: core.DefaultTxPoolConfig.Journal,
   320  	}
   321  	TxPoolRejournalFlag = cli.DurationFlag{
   322  		Name:  "txpool.rejournal",
   323  		Usage: "Time interval to regenerate the local transaction journal",
   324  		Value: core.DefaultTxPoolConfig.Rejournal,
   325  	}
   326  	TxPoolPriceLimitFlag = cli.Uint64Flag{
   327  		Name:  "txpool.pricelimit",
   328  		Usage: "Minimum gas price limit to enforce for acceptance into the pool",
   329  		Value: eth.DefaultConfig.TxPool.PriceLimit,
   330  	}
   331  	TxPoolPriceBumpFlag = cli.Uint64Flag{
   332  		Name:  "txpool.pricebump",
   333  		Usage: "Price bump percentage to replace an already existing transaction",
   334  		Value: eth.DefaultConfig.TxPool.PriceBump,
   335  	}
   336  	TxPoolAccountSlotsFlag = cli.Uint64Flag{
   337  		Name:  "txpool.accountslots",
   338  		Usage: "Minimum number of executable transaction slots guaranteed per account",
   339  		Value: eth.DefaultConfig.TxPool.AccountSlots,
   340  	}
   341  	TxPoolGlobalSlotsFlag = cli.Uint64Flag{
   342  		Name:  "txpool.globalslots",
   343  		Usage: "Maximum number of executable transaction slots for all accounts",
   344  		Value: eth.DefaultConfig.TxPool.GlobalSlots,
   345  	}
   346  	TxPoolAccountQueueFlag = cli.Uint64Flag{
   347  		Name:  "txpool.accountqueue",
   348  		Usage: "Maximum number of non-executable transaction slots permitted per account",
   349  		Value: eth.DefaultConfig.TxPool.AccountQueue,
   350  	}
   351  	TxPoolGlobalQueueFlag = cli.Uint64Flag{
   352  		Name:  "txpool.globalqueue",
   353  		Usage: "Maximum number of non-executable transaction slots for all accounts",
   354  		Value: eth.DefaultConfig.TxPool.GlobalQueue,
   355  	}
   356  	TxPoolLifetimeFlag = cli.DurationFlag{
   357  		Name:  "txpool.lifetime",
   358  		Usage: "Maximum amount of time non-executable transaction are queued",
   359  		Value: eth.DefaultConfig.TxPool.Lifetime,
   360  	}
   361  	// Performance tuning settings
   362  	CacheFlag = cli.IntFlag{
   363  		Name:  "cache",
   364  		Usage: "Megabytes of memory allocated to internal caching (default = 4096 mainnet full node, 128 light mode)",
   365  		Value: 1024,
   366  	}
   367  	CacheDatabaseFlag = cli.IntFlag{
   368  		Name:  "cache.database",
   369  		Usage: "Percentage of cache memory allowance to use for database io",
   370  		Value: 50,
   371  	}
   372  	CacheTrieFlag = cli.IntFlag{
   373  		Name:  "cache.trie",
   374  		Usage: "Percentage of cache memory allowance to use for trie caching (default = 25% full mode, 50% archive mode)",
   375  		Value: 25,
   376  	}
   377  	CacheGCFlag = cli.IntFlag{
   378  		Name:  "cache.gc",
   379  		Usage: "Percentage of cache memory allowance to use for trie pruning (default = 25% full mode, 0% archive mode)",
   380  		Value: 25,
   381  	}
   382  	CacheNoPrefetchFlag = cli.BoolFlag{
   383  		Name:  "cache.noprefetch",
   384  		Usage: "Disable heuristic state prefetch during block import (less CPU and disk IO, more time waiting for data)",
   385  	}
   386  	// Miner settings
   387  	MiningEnabledFlag = cli.BoolFlag{
   388  		Name:  "mine",
   389  		Usage: "Enable mining",
   390  	}
   391  	MinerThreadsFlag = cli.IntFlag{
   392  		Name:  "miner.threads",
   393  		Usage: "Number of CPU threads to use for mining",
   394  		Value: 0,
   395  	}
   396  	MinerLegacyThreadsFlag = cli.IntFlag{
   397  		Name:  "minerthreads",
   398  		Usage: "Number of CPU threads to use for mining (deprecated, use --miner.threads)",
   399  		Value: 0,
   400  	}
   401  	MinerNotifyFlag = cli.StringFlag{
   402  		Name:  "miner.notify",
   403  		Usage: "Comma separated HTTP URL list to notify of new work packages",
   404  	}
   405  	MinerGasTargetFlag = cli.Uint64Flag{
   406  		Name:  "miner.gastarget",
   407  		Usage: "Target gas floor for mined blocks",
   408  		Value: eth.DefaultConfig.Miner.GasFloor,
   409  	}
   410  	MinerLegacyGasTargetFlag = cli.Uint64Flag{
   411  		Name:  "targetgaslimit",
   412  		Usage: "Target gas floor for mined blocks (deprecated, use --miner.gastarget)",
   413  		Value: eth.DefaultConfig.Miner.GasFloor,
   414  	}
   415  	MinerGasLimitFlag = cli.Uint64Flag{
   416  		Name:  "miner.gaslimit",
   417  		Usage: "Target gas ceiling for mined blocks",
   418  		Value: eth.DefaultConfig.Miner.GasCeil,
   419  	}
   420  	MinerGasPriceFlag = BigFlag{
   421  		Name:  "miner.gasprice",
   422  		Usage: "Minimum gas price for mining a transaction",
   423  		Value: eth.DefaultConfig.Miner.GasPrice,
   424  	}
   425  	MinerLegacyGasPriceFlag = BigFlag{
   426  		Name:  "gasprice",
   427  		Usage: "Minimum gas price for mining a transaction (deprecated, use --miner.gasprice)",
   428  		Value: eth.DefaultConfig.Miner.GasPrice,
   429  	}
   430  	MinerEtherbaseFlag = cli.StringFlag{
   431  		Name:  "miner.etherbase",
   432  		Usage: "Public address for block mining rewards (default = first account)",
   433  		Value: "0",
   434  	}
   435  	MinerLegacyEtherbaseFlag = cli.StringFlag{
   436  		Name:  "etherbase",
   437  		Usage: "Public address for block mining rewards (default = first account, deprecated, use --miner.etherbase)",
   438  		Value: "0",
   439  	}
   440  	MinerExtraDataFlag = cli.StringFlag{
   441  		Name:  "miner.extradata",
   442  		Usage: "Block extra data set by the miner (default = client version)",
   443  	}
   444  	MinerLegacyExtraDataFlag = cli.StringFlag{
   445  		Name:  "extradata",
   446  		Usage: "Block extra data set by the miner (default = client version, deprecated, use --miner.extradata)",
   447  	}
   448  	MinerRecommitIntervalFlag = cli.DurationFlag{
   449  		Name:  "miner.recommit",
   450  		Usage: "Time interval to recreate the block being mined",
   451  		Value: eth.DefaultConfig.Miner.Recommit,
   452  	}
   453  	MinerNoVerfiyFlag = cli.BoolFlag{
   454  		Name:  "miner.noverify",
   455  		Usage: "Disable remote sealing verification",
   456  	}
   457  	// Account settings
   458  	UnlockedAccountFlag = cli.StringFlag{
   459  		Name:  "unlock",
   460  		Usage: "Comma separated list of accounts to unlock",
   461  		Value: "",
   462  	}
   463  	PasswordFileFlag = cli.StringFlag{
   464  		Name:  "password",
   465  		Usage: "Password file to use for non-interactive password input",
   466  		Value: "",
   467  	}
   468  	ExternalSignerFlag = cli.StringFlag{
   469  		Name:  "signer",
   470  		Usage: "External signer (url or path to ipc file)",
   471  		Value: "",
   472  	}
   473  	VMEnableDebugFlag = cli.BoolFlag{
   474  		Name:  "vmdebug",
   475  		Usage: "Record information useful for VM and contract debugging",
   476  	}
   477  	InsecureUnlockAllowedFlag = cli.BoolFlag{
   478  		Name:  "allow-insecure-unlock",
   479  		Usage: "Allow insecure account unlocking when account-related RPCs are exposed by http",
   480  	}
   481  	RPCGlobalGasCap = cli.Uint64Flag{
   482  		Name:  "rpc.gascap",
   483  		Usage: "Sets a cap on gas that can be used in eth_call/estimateGas",
   484  	}
   485  	// Logging and debug settings
   486  	EthStatsURLFlag = cli.StringFlag{
   487  		Name:  "ethstats",
   488  		Usage: "Reporting URL of a ethstats service (nodename:secret@host:port)",
   489  	}
   490  	FakePoWFlag = cli.BoolFlag{
   491  		Name:  "fakepow",
   492  		Usage: "Disables proof-of-work verification",
   493  	}
   494  	NoCompactionFlag = cli.BoolFlag{
   495  		Name:  "nocompaction",
   496  		Usage: "Disables db compaction after import",
   497  	}
   498  	// RPC settings
   499  	IPCDisabledFlag = cli.BoolFlag{
   500  		Name:  "ipcdisable",
   501  		Usage: "Disable the IPC-RPC server",
   502  	}
   503  	IPCPathFlag = DirectoryFlag{
   504  		Name:  "ipcpath",
   505  		Usage: "Filename for IPC socket/pipe within the datadir (explicit paths escape it)",
   506  	}
   507  	RPCEnabledFlag = cli.BoolFlag{
   508  		Name:  "rpc",
   509  		Usage: "Enable the HTTP-RPC server",
   510  	}
   511  	RPCListenAddrFlag = cli.StringFlag{
   512  		Name:  "rpcaddr",
   513  		Usage: "HTTP-RPC server listening interface",
   514  		Value: node.DefaultHTTPHost,
   515  	}
   516  	RPCPortFlag = cli.IntFlag{
   517  		Name:  "rpcport",
   518  		Usage: "HTTP-RPC server listening port",
   519  		Value: node.DefaultHTTPPort,
   520  	}
   521  	RPCCORSDomainFlag = cli.StringFlag{
   522  		Name:  "rpccorsdomain",
   523  		Usage: "Comma separated list of domains from which to accept cross origin requests (browser enforced)",
   524  		Value: "",
   525  	}
   526  	RPCVirtualHostsFlag = cli.StringFlag{
   527  		Name:  "rpcvhosts",
   528  		Usage: "Comma separated list of virtual hostnames from which to accept requests (server enforced). Accepts '*' wildcard.",
   529  		Value: strings.Join(node.DefaultConfig.HTTPVirtualHosts, ","),
   530  	}
   531  	RPCApiFlag = cli.StringFlag{
   532  		Name:  "rpcapi",
   533  		Usage: "API's offered over the HTTP-RPC interface",
   534  		Value: "",
   535  	}
   536  	WSEnabledFlag = cli.BoolFlag{
   537  		Name:  "ws",
   538  		Usage: "Enable the WS-RPC server",
   539  	}
   540  	WSListenAddrFlag = cli.StringFlag{
   541  		Name:  "wsaddr",
   542  		Usage: "WS-RPC server listening interface",
   543  		Value: node.DefaultWSHost,
   544  	}
   545  	WSPortFlag = cli.IntFlag{
   546  		Name:  "wsport",
   547  		Usage: "WS-RPC server listening port",
   548  		Value: node.DefaultWSPort,
   549  	}
   550  	WSApiFlag = cli.StringFlag{
   551  		Name:  "wsapi",
   552  		Usage: "API's offered over the WS-RPC interface",
   553  		Value: "",
   554  	}
   555  	WSAllowedOriginsFlag = cli.StringFlag{
   556  		Name:  "wsorigins",
   557  		Usage: "Origins from which to accept websockets requests",
   558  		Value: "",
   559  	}
   560  	GraphQLEnabledFlag = cli.BoolFlag{
   561  		Name:  "graphql",
   562  		Usage: "Enable the GraphQL server",
   563  	}
   564  	GraphQLListenAddrFlag = cli.StringFlag{
   565  		Name:  "graphql.addr",
   566  		Usage: "GraphQL server listening interface",
   567  		Value: node.DefaultGraphQLHost,
   568  	}
   569  	GraphQLPortFlag = cli.IntFlag{
   570  		Name:  "graphql.port",
   571  		Usage: "GraphQL server listening port",
   572  		Value: node.DefaultGraphQLPort,
   573  	}
   574  	GraphQLCORSDomainFlag = cli.StringFlag{
   575  		Name:  "graphql.corsdomain",
   576  		Usage: "Comma separated list of domains from which to accept cross origin requests (browser enforced)",
   577  		Value: "",
   578  	}
   579  	GraphQLVirtualHostsFlag = cli.StringFlag{
   580  		Name:  "graphql.vhosts",
   581  		Usage: "Comma separated list of virtual hostnames from which to accept requests (server enforced). Accepts '*' wildcard.",
   582  		Value: strings.Join(node.DefaultConfig.GraphQLVirtualHosts, ","),
   583  	}
   584  	ExecFlag = cli.StringFlag{
   585  		Name:  "exec",
   586  		Usage: "Execute JavaScript statement",
   587  	}
   588  	PreloadJSFlag = cli.StringFlag{
   589  		Name:  "preload",
   590  		Usage: "Comma separated list of JavaScript files to preload into the console",
   591  	}
   592  
   593  	// Network Settings
   594  	MaxPeersFlag = cli.IntFlag{
   595  		Name:  "maxpeers",
   596  		Usage: "Maximum number of network peers (network disabled if set to 0)",
   597  		Value: node.DefaultConfig.P2P.MaxPeers,
   598  	}
   599  	MaxPendingPeersFlag = cli.IntFlag{
   600  		Name:  "maxpendpeers",
   601  		Usage: "Maximum number of pending connection attempts (defaults used if set to 0)",
   602  		Value: node.DefaultConfig.P2P.MaxPendingPeers,
   603  	}
   604  	ListenPortFlag = cli.IntFlag{
   605  		Name:  "port",
   606  		Usage: "Network listening port",
   607  		Value: 30303,
   608  	}
   609  	BootnodesFlag = cli.StringFlag{
   610  		Name:  "bootnodes",
   611  		Usage: "Comma separated enode URLs for P2P discovery bootstrap (set v4+v5 instead for light servers)",
   612  		Value: "",
   613  	}
   614  	BootnodesV4Flag = cli.StringFlag{
   615  		Name:  "bootnodesv4",
   616  		Usage: "Comma separated enode URLs for P2P v4 discovery bootstrap (light server, full nodes)",
   617  		Value: "",
   618  	}
   619  	BootnodesV5Flag = cli.StringFlag{
   620  		Name:  "bootnodesv5",
   621  		Usage: "Comma separated enode URLs for P2P v5 discovery bootstrap (light server, light nodes)",
   622  		Value: "",
   623  	}
   624  	NodeKeyFileFlag = cli.StringFlag{
   625  		Name:  "nodekey",
   626  		Usage: "P2P node key file",
   627  	}
   628  	NodeKeyHexFlag = cli.StringFlag{
   629  		Name:  "nodekeyhex",
   630  		Usage: "P2P node key as hex (for testing)",
   631  	}
   632  	NATFlag = cli.StringFlag{
   633  		Name:  "nat",
   634  		Usage: "NAT port mapping mechanism (any|none|upnp|pmp|extip:<IP>)",
   635  		Value: "any",
   636  	}
   637  	NoDiscoverFlag = cli.BoolFlag{
   638  		Name:  "nodiscover",
   639  		Usage: "Disables the peer discovery mechanism (manual peer addition)",
   640  	}
   641  	DiscoveryV5Flag = cli.BoolFlag{
   642  		Name:  "v5disc",
   643  		Usage: "Enables the experimental RLPx V5 (Topic Discovery) mechanism",
   644  	}
   645  	NetrestrictFlag = cli.StringFlag{
   646  		Name:  "netrestrict",
   647  		Usage: "Restricts network communication to the given IP networks (CIDR masks)",
   648  	}
   649  
   650  	// ATM the url is left to the user and deployment to
   651  	JSpathFlag = cli.StringFlag{
   652  		Name:  "jspath",
   653  		Usage: "JavaScript root path for `loadScript`",
   654  		Value: ".",
   655  	}
   656  
   657  	// Gas price oracle settings
   658  	GpoBlocksFlag = cli.IntFlag{
   659  		Name:  "gpoblocks",
   660  		Usage: "Number of recent blocks to check for gas prices",
   661  		Value: eth.DefaultConfig.GPO.Blocks,
   662  	}
   663  	GpoPercentileFlag = cli.IntFlag{
   664  		Name:  "gpopercentile",
   665  		Usage: "Suggested gas price is the given percentile of a set of recent transaction gas prices",
   666  		Value: eth.DefaultConfig.GPO.Percentile,
   667  	}
   668  	WhisperEnabledFlag = cli.BoolFlag{
   669  		Name:  "shh",
   670  		Usage: "Enable Whisper",
   671  	}
   672  	WhisperMaxMessageSizeFlag = cli.IntFlag{
   673  		Name:  "shh.maxmessagesize",
   674  		Usage: "Max message size accepted",
   675  		Value: int(whisper.DefaultMaxMessageSize),
   676  	}
   677  	WhisperMinPOWFlag = cli.Float64Flag{
   678  		Name:  "shh.pow",
   679  		Usage: "Minimum POW accepted",
   680  		Value: whisper.DefaultMinimumPoW,
   681  	}
   682  	WhisperRestrictConnectionBetweenLightClientsFlag = cli.BoolFlag{
   683  		Name:  "shh.restrict-light",
   684  		Usage: "Restrict connection between two whisper light clients",
   685  	}
   686  
   687  	// Metrics flags
   688  	MetricsEnabledFlag = cli.BoolFlag{
   689  		Name:  "metrics",
   690  		Usage: "Enable metrics collection and reporting",
   691  	}
   692  	MetricsEnabledExpensiveFlag = cli.BoolFlag{
   693  		Name:  "metrics.expensive",
   694  		Usage: "Enable expensive metrics collection and reporting",
   695  	}
   696  	MetricsEnableInfluxDBFlag = cli.BoolFlag{
   697  		Name:  "metrics.influxdb",
   698  		Usage: "Enable metrics export/push to an external InfluxDB database",
   699  	}
   700  	MetricsInfluxDBEndpointFlag = cli.StringFlag{
   701  		Name:  "metrics.influxdb.endpoint",
   702  		Usage: "InfluxDB API endpoint to report metrics to",
   703  		Value: "http://localhost:8086",
   704  	}
   705  	MetricsInfluxDBDatabaseFlag = cli.StringFlag{
   706  		Name:  "metrics.influxdb.database",
   707  		Usage: "InfluxDB database name to push reported metrics to",
   708  		Value: "geth",
   709  	}
   710  	MetricsInfluxDBUsernameFlag = cli.StringFlag{
   711  		Name:  "metrics.influxdb.username",
   712  		Usage: "Username to authorize access to the database",
   713  		Value: "test",
   714  	}
   715  	MetricsInfluxDBPasswordFlag = cli.StringFlag{
   716  		Name:  "metrics.influxdb.password",
   717  		Usage: "Password to authorize access to the database",
   718  		Value: "test",
   719  	}
   720  	// Tags are part of every measurement sent to InfluxDB. Queries on tags are faster in InfluxDB.
   721  	// For example `host` tag could be used so that we can group all nodes and average a measurement
   722  	// across all of them, but also so that we can select a specific node and inspect its measurements.
   723  	// https://docs.influxdata.com/influxdb/v1.4/concepts/key_concepts/#tag-key
   724  	MetricsInfluxDBTagsFlag = cli.StringFlag{
   725  		Name:  "metrics.influxdb.tags",
   726  		Usage: "Comma-separated InfluxDB tags (key/values) attached to all measurements",
   727  		Value: "host=localhost",
   728  	}
   729  
   730  	EWASMInterpreterFlag = cli.StringFlag{
   731  		Name:  "vm.ewasm",
   732  		Usage: "External ewasm configuration (default = built-in interpreter)",
   733  		Value: "",
   734  	}
   735  	EVMInterpreterFlag = cli.StringFlag{
   736  		Name:  "vm.evm",
   737  		Usage: "External EVM configuration (default = built-in interpreter)",
   738  		Value: "",
   739  	}
   740  )
   741  
   742  // MakeDataDir retrieves the currently requested data directory, terminating
   743  // if none (or the empty string) is specified. If the node is starting a testnet,
   744  // the a subdirectory of the specified datadir will be used.
   745  func MakeDataDir(ctx *cli.Context) string {
   746  	if path := ctx.GlobalString(DataDirFlag.Name); path != "" {
   747  		if ctx.GlobalBool(TestnetFlag.Name) {
   748  			return filepath.Join(path, "testnet")
   749  		}
   750  		if ctx.GlobalBool(RinkebyFlag.Name) {
   751  			return filepath.Join(path, "rinkeby")
   752  		}
   753  		if ctx.GlobalBool(GoerliFlag.Name) {
   754  			return filepath.Join(path, "goerli")
   755  		}
   756  		return path
   757  	}
   758  	Fatalf("Cannot determine default data directory, please set manually (--datadir)")
   759  	return ""
   760  }
   761  
   762  // setNodeKey creates a node key from set command line flags, either loading it
   763  // from a file or as a specified hex value. If neither flags were provided, this
   764  // method returns nil and an emphemeral key is to be generated.
   765  func setNodeKey(ctx *cli.Context, cfg *p2p.Config) {
   766  	var (
   767  		hex  = ctx.GlobalString(NodeKeyHexFlag.Name)
   768  		file = ctx.GlobalString(NodeKeyFileFlag.Name)
   769  		key  *ecdsa.PrivateKey
   770  		err  error
   771  	)
   772  	switch {
   773  	case file != "" && hex != "":
   774  		Fatalf("Options %q and %q are mutually exclusive", NodeKeyFileFlag.Name, NodeKeyHexFlag.Name)
   775  	case file != "":
   776  		if key, err = crypto.LoadECDSA(file); err != nil {
   777  			Fatalf("Option %q: %v", NodeKeyFileFlag.Name, err)
   778  		}
   779  		cfg.PrivateKey = key
   780  	case hex != "":
   781  		if key, err = crypto.HexToECDSA(hex); err != nil {
   782  			Fatalf("Option %q: %v", NodeKeyHexFlag.Name, err)
   783  		}
   784  		cfg.PrivateKey = key
   785  	}
   786  }
   787  
   788  // setNodeUserIdent creates the user identifier from CLI flags.
   789  func setNodeUserIdent(ctx *cli.Context, cfg *node.Config) {
   790  	if identity := ctx.GlobalString(IdentityFlag.Name); len(identity) > 0 {
   791  		cfg.UserIdent = identity
   792  	}
   793  }
   794  
   795  // setBootstrapNodes creates a list of bootstrap nodes from the command line
   796  // flags, reverting to pre-configured ones if none have been specified.
   797  func setBootstrapNodes(ctx *cli.Context, cfg *p2p.Config) {
   798  	urls := params.MainnetBootnodes
   799  	switch {
   800  	case ctx.GlobalIsSet(BootnodesFlag.Name) || ctx.GlobalIsSet(BootnodesV4Flag.Name):
   801  		if ctx.GlobalIsSet(BootnodesV4Flag.Name) {
   802  			urls = strings.Split(ctx.GlobalString(BootnodesV4Flag.Name), ",")
   803  		} else {
   804  			urls = strings.Split(ctx.GlobalString(BootnodesFlag.Name), ",")
   805  		}
   806  	case ctx.GlobalBool(TestnetFlag.Name):
   807  		urls = params.TestnetBootnodes
   808  	case ctx.GlobalBool(RinkebyFlag.Name):
   809  		urls = params.RinkebyBootnodes
   810  	case ctx.GlobalBool(GoerliFlag.Name):
   811  		urls = params.GoerliBootnodes
   812  	case cfg.BootstrapNodes != nil:
   813  		return // already set, don't apply defaults.
   814  	}
   815  
   816  	cfg.BootstrapNodes = make([]*enode.Node, 0, len(urls))
   817  	for _, url := range urls {
   818  		if url != "" {
   819  			node, err := enode.Parse(enode.ValidSchemes, url)
   820  			if err != nil {
   821  				log.Crit("Bootstrap URL invalid", "enode", url, "err", err)
   822  				continue
   823  			}
   824  			cfg.BootstrapNodes = append(cfg.BootstrapNodes, node)
   825  		}
   826  	}
   827  }
   828  
   829  // setBootstrapNodesV5 creates a list of bootstrap nodes from the command line
   830  // flags, reverting to pre-configured ones if none have been specified.
   831  func setBootstrapNodesV5(ctx *cli.Context, cfg *p2p.Config) {
   832  	urls := params.DiscoveryV5Bootnodes
   833  	switch {
   834  	case ctx.GlobalIsSet(BootnodesFlag.Name) || ctx.GlobalIsSet(BootnodesV5Flag.Name):
   835  		if ctx.GlobalIsSet(BootnodesV5Flag.Name) {
   836  			urls = strings.Split(ctx.GlobalString(BootnodesV5Flag.Name), ",")
   837  		} else {
   838  			urls = strings.Split(ctx.GlobalString(BootnodesFlag.Name), ",")
   839  		}
   840  	case ctx.GlobalBool(RinkebyFlag.Name):
   841  		urls = params.RinkebyBootnodes
   842  	case ctx.GlobalBool(GoerliFlag.Name):
   843  		urls = params.GoerliBootnodes
   844  	case cfg.BootstrapNodesV5 != nil:
   845  		return // already set, don't apply defaults.
   846  	}
   847  
   848  	cfg.BootstrapNodesV5 = make([]*discv5.Node, 0, len(urls))
   849  	for _, url := range urls {
   850  		if url != "" {
   851  			node, err := discv5.ParseNode(url)
   852  			if err != nil {
   853  				log.Error("Bootstrap URL invalid", "enode", url, "err", err)
   854  				continue
   855  			}
   856  			cfg.BootstrapNodesV5 = append(cfg.BootstrapNodesV5, node)
   857  		}
   858  	}
   859  }
   860  
   861  // setListenAddress creates a TCP listening address string from set command
   862  // line flags.
   863  func setListenAddress(ctx *cli.Context, cfg *p2p.Config) {
   864  	if ctx.GlobalIsSet(ListenPortFlag.Name) {
   865  		cfg.ListenAddr = fmt.Sprintf(":%d", ctx.GlobalInt(ListenPortFlag.Name))
   866  	}
   867  }
   868  
   869  // setNAT creates a port mapper from command line flags.
   870  func setNAT(ctx *cli.Context, cfg *p2p.Config) {
   871  	if ctx.GlobalIsSet(NATFlag.Name) {
   872  		natif, err := nat.Parse(ctx.GlobalString(NATFlag.Name))
   873  		if err != nil {
   874  			Fatalf("Option %s: %v", NATFlag.Name, err)
   875  		}
   876  		cfg.NAT = natif
   877  	}
   878  }
   879  
   880  // splitAndTrim splits input separated by a comma
   881  // and trims excessive white space from the substrings.
   882  func splitAndTrim(input string) []string {
   883  	result := strings.Split(input, ",")
   884  	for i, r := range result {
   885  		result[i] = strings.TrimSpace(r)
   886  	}
   887  	return result
   888  }
   889  
   890  // setHTTP creates the HTTP RPC listener interface string from the set
   891  // command line flags, returning empty if the HTTP endpoint is disabled.
   892  func setHTTP(ctx *cli.Context, cfg *node.Config) {
   893  	if ctx.GlobalBool(RPCEnabledFlag.Name) && cfg.HTTPHost == "" {
   894  		cfg.HTTPHost = "127.0.0.1"
   895  		if ctx.GlobalIsSet(RPCListenAddrFlag.Name) {
   896  			cfg.HTTPHost = ctx.GlobalString(RPCListenAddrFlag.Name)
   897  		}
   898  	}
   899  	if ctx.GlobalIsSet(RPCPortFlag.Name) {
   900  		cfg.HTTPPort = ctx.GlobalInt(RPCPortFlag.Name)
   901  	}
   902  	if ctx.GlobalIsSet(RPCCORSDomainFlag.Name) {
   903  		cfg.HTTPCors = splitAndTrim(ctx.GlobalString(RPCCORSDomainFlag.Name))
   904  	}
   905  	if ctx.GlobalIsSet(RPCApiFlag.Name) {
   906  		cfg.HTTPModules = splitAndTrim(ctx.GlobalString(RPCApiFlag.Name))
   907  	}
   908  	if ctx.GlobalIsSet(RPCVirtualHostsFlag.Name) {
   909  		cfg.HTTPVirtualHosts = splitAndTrim(ctx.GlobalString(RPCVirtualHostsFlag.Name))
   910  	}
   911  }
   912  
   913  // setGraphQL creates the GraphQL listener interface string from the set
   914  // command line flags, returning empty if the GraphQL endpoint is disabled.
   915  func setGraphQL(ctx *cli.Context, cfg *node.Config) {
   916  	if ctx.GlobalBool(GraphQLEnabledFlag.Name) && cfg.GraphQLHost == "" {
   917  		cfg.GraphQLHost = "127.0.0.1"
   918  		if ctx.GlobalIsSet(GraphQLListenAddrFlag.Name) {
   919  			cfg.GraphQLHost = ctx.GlobalString(GraphQLListenAddrFlag.Name)
   920  		}
   921  	}
   922  	cfg.GraphQLPort = ctx.GlobalInt(GraphQLPortFlag.Name)
   923  	if ctx.GlobalIsSet(GraphQLCORSDomainFlag.Name) {
   924  		cfg.GraphQLCors = splitAndTrim(ctx.GlobalString(GraphQLCORSDomainFlag.Name))
   925  	}
   926  	if ctx.GlobalIsSet(GraphQLVirtualHostsFlag.Name) {
   927  		cfg.GraphQLVirtualHosts = splitAndTrim(ctx.GlobalString(GraphQLVirtualHostsFlag.Name))
   928  	}
   929  }
   930  
   931  // setWS creates the WebSocket RPC listener interface string from the set
   932  // command line flags, returning empty if the HTTP endpoint is disabled.
   933  func setWS(ctx *cli.Context, cfg *node.Config) {
   934  	if ctx.GlobalBool(WSEnabledFlag.Name) && cfg.WSHost == "" {
   935  		cfg.WSHost = "127.0.0.1"
   936  		if ctx.GlobalIsSet(WSListenAddrFlag.Name) {
   937  			cfg.WSHost = ctx.GlobalString(WSListenAddrFlag.Name)
   938  		}
   939  	}
   940  	if ctx.GlobalIsSet(WSPortFlag.Name) {
   941  		cfg.WSPort = ctx.GlobalInt(WSPortFlag.Name)
   942  	}
   943  	if ctx.GlobalIsSet(WSAllowedOriginsFlag.Name) {
   944  		cfg.WSOrigins = splitAndTrim(ctx.GlobalString(WSAllowedOriginsFlag.Name))
   945  	}
   946  	if ctx.GlobalIsSet(WSApiFlag.Name) {
   947  		cfg.WSModules = splitAndTrim(ctx.GlobalString(WSApiFlag.Name))
   948  	}
   949  }
   950  
   951  // setIPC creates an IPC path configuration from the set command line flags,
   952  // returning an empty string if IPC was explicitly disabled, or the set path.
   953  func setIPC(ctx *cli.Context, cfg *node.Config) {
   954  	CheckExclusive(ctx, IPCDisabledFlag, IPCPathFlag)
   955  	switch {
   956  	case ctx.GlobalBool(IPCDisabledFlag.Name):
   957  		cfg.IPCPath = ""
   958  	case ctx.GlobalIsSet(IPCPathFlag.Name):
   959  		cfg.IPCPath = ctx.GlobalString(IPCPathFlag.Name)
   960  	}
   961  }
   962  
   963  // setLes configures the les server and ultra light client settings from the command line flags.
   964  func setLes(ctx *cli.Context, cfg *eth.Config) {
   965  	if ctx.GlobalIsSet(LightLegacyServFlag.Name) {
   966  		cfg.LightServ = ctx.GlobalInt(LightLegacyServFlag.Name)
   967  	}
   968  	if ctx.GlobalIsSet(LightServeFlag.Name) {
   969  		cfg.LightServ = ctx.GlobalInt(LightServeFlag.Name)
   970  	}
   971  	if ctx.GlobalIsSet(LightIngressFlag.Name) {
   972  		cfg.LightIngress = ctx.GlobalInt(LightIngressFlag.Name)
   973  	}
   974  	if ctx.GlobalIsSet(LightEgressFlag.Name) {
   975  		cfg.LightEgress = ctx.GlobalInt(LightEgressFlag.Name)
   976  	}
   977  	if ctx.GlobalIsSet(LightLegacyPeersFlag.Name) {
   978  		cfg.LightPeers = ctx.GlobalInt(LightLegacyPeersFlag.Name)
   979  	}
   980  	if ctx.GlobalIsSet(LightMaxPeersFlag.Name) {
   981  		cfg.LightPeers = ctx.GlobalInt(LightMaxPeersFlag.Name)
   982  	}
   983  	if ctx.GlobalIsSet(UltraLightServersFlag.Name) {
   984  		cfg.UltraLightServers = strings.Split(ctx.GlobalString(UltraLightServersFlag.Name), ",")
   985  	}
   986  	if ctx.GlobalIsSet(UltraLightFractionFlag.Name) {
   987  		cfg.UltraLightFraction = ctx.GlobalInt(UltraLightFractionFlag.Name)
   988  	}
   989  	if cfg.UltraLightFraction <= 0 && cfg.UltraLightFraction > 100 {
   990  		log.Error("Ultra light fraction is invalid", "had", cfg.UltraLightFraction, "updated", eth.DefaultConfig.UltraLightFraction)
   991  		cfg.UltraLightFraction = eth.DefaultConfig.UltraLightFraction
   992  	}
   993  	if ctx.GlobalIsSet(UltraLightOnlyAnnounceFlag.Name) {
   994  		cfg.UltraLightOnlyAnnounce = ctx.GlobalBool(UltraLightOnlyAnnounceFlag.Name)
   995  	}
   996  }
   997  
   998  // makeDatabaseHandles raises out the number of allowed file handles per process
   999  // for Geth and returns half of the allowance to assign to the database.
  1000  func makeDatabaseHandles() int {
  1001  	limit, err := fdlimit.Maximum()
  1002  	if err != nil {
  1003  		Fatalf("Failed to retrieve file descriptor allowance: %v", err)
  1004  	}
  1005  	raised, err := fdlimit.Raise(uint64(limit))
  1006  	if err != nil {
  1007  		Fatalf("Failed to raise file descriptor allowance: %v", err)
  1008  	}
  1009  	return int(raised / 2) // Leave half for networking and other stuff
  1010  }
  1011  
  1012  // MakeAddress converts an account specified directly as a hex encoded string or
  1013  // a key index in the key store to an internal account representation.
  1014  func MakeAddress(ks *keystore.KeyStore, account string) (accounts.Account, error) {
  1015  	// If the specified account is a valid address, return it
  1016  	if common.IsHexAddress(account) {
  1017  		return accounts.Account{Address: common.HexToAddress(account)}, nil
  1018  	}
  1019  	// Otherwise try to interpret the account as a keystore index
  1020  	index, err := strconv.Atoi(account)
  1021  	if err != nil || index < 0 {
  1022  		return accounts.Account{}, fmt.Errorf("invalid account address or index %q", account)
  1023  	}
  1024  	log.Warn("-------------------------------------------------------------------")
  1025  	log.Warn("Referring to accounts by order in the keystore folder is dangerous!")
  1026  	log.Warn("This functionality is deprecated and will be removed in the future!")
  1027  	log.Warn("Please use explicit addresses! (can search via `geth account list`)")
  1028  	log.Warn("-------------------------------------------------------------------")
  1029  
  1030  	accs := ks.Accounts()
  1031  	if len(accs) <= index {
  1032  		return accounts.Account{}, fmt.Errorf("index %d higher than number of accounts %d", index, len(accs))
  1033  	}
  1034  	return accs[index], nil
  1035  }
  1036  
  1037  // setEtherbase retrieves the etherbase either from the directly specified
  1038  // command line flags or from the keystore if CLI indexed.
  1039  func setEtherbase(ctx *cli.Context, ks *keystore.KeyStore, cfg *eth.Config) {
  1040  	// Extract the current etherbase, new flag overriding legacy one
  1041  	var etherbase string
  1042  	if ctx.GlobalIsSet(MinerLegacyEtherbaseFlag.Name) {
  1043  		etherbase = ctx.GlobalString(MinerLegacyEtherbaseFlag.Name)
  1044  	}
  1045  	if ctx.GlobalIsSet(MinerEtherbaseFlag.Name) {
  1046  		etherbase = ctx.GlobalString(MinerEtherbaseFlag.Name)
  1047  	}
  1048  	// Convert the etherbase into an address and configure it
  1049  	if etherbase != "" {
  1050  		if ks != nil {
  1051  			account, err := MakeAddress(ks, etherbase)
  1052  			if err != nil {
  1053  				Fatalf("Invalid miner etherbase: %v", err)
  1054  			}
  1055  			cfg.Miner.Etherbase = account.Address
  1056  		} else {
  1057  			Fatalf("No etherbase configured")
  1058  		}
  1059  	}
  1060  }
  1061  
  1062  // MakePasswordList reads password lines from the file specified by the global --password flag.
  1063  func MakePasswordList(ctx *cli.Context) []string {
  1064  	path := ctx.GlobalString(PasswordFileFlag.Name)
  1065  	if path == "" {
  1066  		return nil
  1067  	}
  1068  	text, err := ioutil.ReadFile(path)
  1069  	if err != nil {
  1070  		Fatalf("Failed to read password file: %v", err)
  1071  	}
  1072  	lines := strings.Split(string(text), "\n")
  1073  	// Sanitise DOS line endings.
  1074  	for i := range lines {
  1075  		lines[i] = strings.TrimRight(lines[i], "\r")
  1076  	}
  1077  	return lines
  1078  }
  1079  
  1080  func SetP2PConfig(ctx *cli.Context, cfg *p2p.Config) {
  1081  	setNodeKey(ctx, cfg)
  1082  	setNAT(ctx, cfg)
  1083  	setListenAddress(ctx, cfg)
  1084  	setBootstrapNodes(ctx, cfg)
  1085  	setBootstrapNodesV5(ctx, cfg)
  1086  
  1087  	lightClient := ctx.GlobalString(SyncModeFlag.Name) == "light"
  1088  	lightServer := (ctx.GlobalInt(LightLegacyServFlag.Name) != 0 || ctx.GlobalInt(LightServeFlag.Name) != 0)
  1089  
  1090  	lightPeers := ctx.GlobalInt(LightLegacyPeersFlag.Name)
  1091  	if ctx.GlobalIsSet(LightMaxPeersFlag.Name) {
  1092  		lightPeers = ctx.GlobalInt(LightMaxPeersFlag.Name)
  1093  	}
  1094  	if ctx.GlobalIsSet(MaxPeersFlag.Name) {
  1095  		cfg.MaxPeers = ctx.GlobalInt(MaxPeersFlag.Name)
  1096  		if lightServer && !ctx.GlobalIsSet(LightLegacyPeersFlag.Name) && !ctx.GlobalIsSet(LightMaxPeersFlag.Name) {
  1097  			cfg.MaxPeers += lightPeers
  1098  		}
  1099  	} else {
  1100  		if lightServer {
  1101  			cfg.MaxPeers += lightPeers
  1102  		}
  1103  		if lightClient && (ctx.GlobalIsSet(LightLegacyPeersFlag.Name) || ctx.GlobalIsSet(LightMaxPeersFlag.Name)) && cfg.MaxPeers < lightPeers {
  1104  			cfg.MaxPeers = lightPeers
  1105  		}
  1106  	}
  1107  	if !(lightClient || lightServer) {
  1108  		lightPeers = 0
  1109  	}
  1110  	ethPeers := cfg.MaxPeers - lightPeers
  1111  	if lightClient {
  1112  		ethPeers = 0
  1113  	}
  1114  	log.Info("Maximum peer count", "ETH", ethPeers, "LES", lightPeers, "total", cfg.MaxPeers)
  1115  
  1116  	if ctx.GlobalIsSet(MaxPendingPeersFlag.Name) {
  1117  		cfg.MaxPendingPeers = ctx.GlobalInt(MaxPendingPeersFlag.Name)
  1118  	}
  1119  	if ctx.GlobalIsSet(NoDiscoverFlag.Name) || lightClient {
  1120  		cfg.NoDiscovery = true
  1121  	}
  1122  
  1123  	// if we're running a light client or server, force enable the v5 peer discovery
  1124  	// unless it is explicitly disabled with --nodiscover note that explicitly specifying
  1125  	// --v5disc overrides --nodiscover, in which case the later only disables v4 discovery
  1126  	forceV5Discovery := (lightClient || lightServer) && !ctx.GlobalBool(NoDiscoverFlag.Name)
  1127  	if ctx.GlobalIsSet(DiscoveryV5Flag.Name) {
  1128  		cfg.DiscoveryV5 = ctx.GlobalBool(DiscoveryV5Flag.Name)
  1129  	} else if forceV5Discovery {
  1130  		cfg.DiscoveryV5 = true
  1131  	}
  1132  
  1133  	if netrestrict := ctx.GlobalString(NetrestrictFlag.Name); netrestrict != "" {
  1134  		list, err := netutil.ParseNetlist(netrestrict)
  1135  		if err != nil {
  1136  			Fatalf("Option %q: %v", NetrestrictFlag.Name, err)
  1137  		}
  1138  		cfg.NetRestrict = list
  1139  	}
  1140  
  1141  	if ctx.GlobalBool(DeveloperFlag.Name) {
  1142  		// --dev mode can't use p2p networking.
  1143  		cfg.MaxPeers = 0
  1144  		cfg.ListenAddr = ":0"
  1145  		cfg.NoDiscovery = true
  1146  		cfg.DiscoveryV5 = false
  1147  	}
  1148  }
  1149  
  1150  // SetNodeConfig applies node-related command line flags to the config.
  1151  func SetNodeConfig(ctx *cli.Context, cfg *node.Config) {
  1152  	SetP2PConfig(ctx, &cfg.P2P)
  1153  	setIPC(ctx, cfg)
  1154  	setHTTP(ctx, cfg)
  1155  	setGraphQL(ctx, cfg)
  1156  	setWS(ctx, cfg)
  1157  	setNodeUserIdent(ctx, cfg)
  1158  	setDataDir(ctx, cfg)
  1159  	setSmartCard(ctx, cfg)
  1160  
  1161  	if ctx.GlobalIsSet(ExternalSignerFlag.Name) {
  1162  		cfg.ExternalSigner = ctx.GlobalString(ExternalSignerFlag.Name)
  1163  	}
  1164  
  1165  	if ctx.GlobalIsSet(KeyStoreDirFlag.Name) {
  1166  		cfg.KeyStoreDir = ctx.GlobalString(KeyStoreDirFlag.Name)
  1167  	}
  1168  	if ctx.GlobalIsSet(LightKDFFlag.Name) {
  1169  		cfg.UseLightweightKDF = ctx.GlobalBool(LightKDFFlag.Name)
  1170  	}
  1171  	if ctx.GlobalIsSet(NoUSBFlag.Name) {
  1172  		cfg.NoUSB = ctx.GlobalBool(NoUSBFlag.Name)
  1173  	}
  1174  	if ctx.GlobalIsSet(InsecureUnlockAllowedFlag.Name) {
  1175  		cfg.InsecureUnlockAllowed = ctx.GlobalBool(InsecureUnlockAllowedFlag.Name)
  1176  	}
  1177  }
  1178  
  1179  func setSmartCard(ctx *cli.Context, cfg *node.Config) {
  1180  	// Skip enabling smartcards if no path is set
  1181  	path := ctx.GlobalString(SmartCardDaemonPathFlag.Name)
  1182  	if path == "" {
  1183  		return
  1184  	}
  1185  	// Sanity check that the smartcard path is valid
  1186  	fi, err := os.Stat(path)
  1187  	if err != nil {
  1188  		log.Info("Smartcard socket not found, disabling", "err", err)
  1189  		return
  1190  	}
  1191  	if fi.Mode()&os.ModeType != os.ModeSocket {
  1192  		log.Error("Invalid smartcard daemon path", "path", path, "type", fi.Mode().String())
  1193  		return
  1194  	}
  1195  	// Smartcard daemon path exists and is a socket, enable it
  1196  	cfg.SmartCardDaemonPath = path
  1197  }
  1198  
  1199  func setDataDir(ctx *cli.Context, cfg *node.Config) {
  1200  	switch {
  1201  	case ctx.GlobalIsSet(DataDirFlag.Name):
  1202  		cfg.DataDir = ctx.GlobalString(DataDirFlag.Name)
  1203  	case ctx.GlobalBool(DeveloperFlag.Name):
  1204  		cfg.DataDir = "" // unless explicitly requested, use memory databases
  1205  	case ctx.GlobalBool(TestnetFlag.Name) && cfg.DataDir == node.DefaultDataDir():
  1206  		cfg.DataDir = filepath.Join(node.DefaultDataDir(), "testnet")
  1207  	case ctx.GlobalBool(RinkebyFlag.Name) && cfg.DataDir == node.DefaultDataDir():
  1208  		cfg.DataDir = filepath.Join(node.DefaultDataDir(), "rinkeby")
  1209  	case ctx.GlobalBool(GoerliFlag.Name) && cfg.DataDir == node.DefaultDataDir():
  1210  		cfg.DataDir = filepath.Join(node.DefaultDataDir(), "goerli")
  1211  	}
  1212  }
  1213  
  1214  func setGPO(ctx *cli.Context, cfg *gasprice.Config) {
  1215  	if ctx.GlobalIsSet(GpoBlocksFlag.Name) {
  1216  		cfg.Blocks = ctx.GlobalInt(GpoBlocksFlag.Name)
  1217  	}
  1218  	if ctx.GlobalIsSet(GpoPercentileFlag.Name) {
  1219  		cfg.Percentile = ctx.GlobalInt(GpoPercentileFlag.Name)
  1220  	}
  1221  }
  1222  
  1223  func setTxPool(ctx *cli.Context, cfg *core.TxPoolConfig) {
  1224  	if ctx.GlobalIsSet(TxPoolLocalsFlag.Name) {
  1225  		locals := strings.Split(ctx.GlobalString(TxPoolLocalsFlag.Name), ",")
  1226  		for _, account := range locals {
  1227  			if trimmed := strings.TrimSpace(account); !common.IsHexAddress(trimmed) {
  1228  				Fatalf("Invalid account in --txpool.locals: %s", trimmed)
  1229  			} else {
  1230  				cfg.Locals = append(cfg.Locals, common.HexToAddress(account))
  1231  			}
  1232  		}
  1233  	}
  1234  	if ctx.GlobalIsSet(TxPoolNoLocalsFlag.Name) {
  1235  		cfg.NoLocals = ctx.GlobalBool(TxPoolNoLocalsFlag.Name)
  1236  	}
  1237  	if ctx.GlobalIsSet(TxPoolJournalFlag.Name) {
  1238  		cfg.Journal = ctx.GlobalString(TxPoolJournalFlag.Name)
  1239  	}
  1240  	if ctx.GlobalIsSet(TxPoolRejournalFlag.Name) {
  1241  		cfg.Rejournal = ctx.GlobalDuration(TxPoolRejournalFlag.Name)
  1242  	}
  1243  	if ctx.GlobalIsSet(TxPoolPriceLimitFlag.Name) {
  1244  		cfg.PriceLimit = ctx.GlobalUint64(TxPoolPriceLimitFlag.Name)
  1245  	}
  1246  	if ctx.GlobalIsSet(TxPoolPriceBumpFlag.Name) {
  1247  		cfg.PriceBump = ctx.GlobalUint64(TxPoolPriceBumpFlag.Name)
  1248  	}
  1249  	if ctx.GlobalIsSet(TxPoolAccountSlotsFlag.Name) {
  1250  		cfg.AccountSlots = ctx.GlobalUint64(TxPoolAccountSlotsFlag.Name)
  1251  	}
  1252  	if ctx.GlobalIsSet(TxPoolGlobalSlotsFlag.Name) {
  1253  		cfg.GlobalSlots = ctx.GlobalUint64(TxPoolGlobalSlotsFlag.Name)
  1254  	}
  1255  	if ctx.GlobalIsSet(TxPoolAccountQueueFlag.Name) {
  1256  		cfg.AccountQueue = ctx.GlobalUint64(TxPoolAccountQueueFlag.Name)
  1257  	}
  1258  	if ctx.GlobalIsSet(TxPoolGlobalQueueFlag.Name) {
  1259  		cfg.GlobalQueue = ctx.GlobalUint64(TxPoolGlobalQueueFlag.Name)
  1260  	}
  1261  	if ctx.GlobalIsSet(TxPoolLifetimeFlag.Name) {
  1262  		cfg.Lifetime = ctx.GlobalDuration(TxPoolLifetimeFlag.Name)
  1263  	}
  1264  }
  1265  
  1266  func setEthash(ctx *cli.Context, cfg *eth.Config) {
  1267  	if ctx.GlobalIsSet(EthashCacheDirFlag.Name) {
  1268  		cfg.Ethash.CacheDir = ctx.GlobalString(EthashCacheDirFlag.Name)
  1269  	}
  1270  	if ctx.GlobalIsSet(EthashDatasetDirFlag.Name) {
  1271  		cfg.Ethash.DatasetDir = ctx.GlobalString(EthashDatasetDirFlag.Name)
  1272  	}
  1273  	if ctx.GlobalIsSet(EthashCachesInMemoryFlag.Name) {
  1274  		cfg.Ethash.CachesInMem = ctx.GlobalInt(EthashCachesInMemoryFlag.Name)
  1275  	}
  1276  	if ctx.GlobalIsSet(EthashCachesOnDiskFlag.Name) {
  1277  		cfg.Ethash.CachesOnDisk = ctx.GlobalInt(EthashCachesOnDiskFlag.Name)
  1278  	}
  1279  	if ctx.GlobalIsSet(EthashDatasetsInMemoryFlag.Name) {
  1280  		cfg.Ethash.DatasetsInMem = ctx.GlobalInt(EthashDatasetsInMemoryFlag.Name)
  1281  	}
  1282  	if ctx.GlobalIsSet(EthashDatasetsOnDiskFlag.Name) {
  1283  		cfg.Ethash.DatasetsOnDisk = ctx.GlobalInt(EthashDatasetsOnDiskFlag.Name)
  1284  	}
  1285  }
  1286  
  1287  func setMiner(ctx *cli.Context, cfg *miner.Config) {
  1288  	if ctx.GlobalIsSet(MinerNotifyFlag.Name) {
  1289  		cfg.Notify = strings.Split(ctx.GlobalString(MinerNotifyFlag.Name), ",")
  1290  	}
  1291  	if ctx.GlobalIsSet(MinerLegacyExtraDataFlag.Name) {
  1292  		cfg.ExtraData = []byte(ctx.GlobalString(MinerLegacyExtraDataFlag.Name))
  1293  	}
  1294  	if ctx.GlobalIsSet(MinerExtraDataFlag.Name) {
  1295  		cfg.ExtraData = []byte(ctx.GlobalString(MinerExtraDataFlag.Name))
  1296  	}
  1297  	if ctx.GlobalIsSet(MinerLegacyGasTargetFlag.Name) {
  1298  		cfg.GasFloor = ctx.GlobalUint64(MinerLegacyGasTargetFlag.Name)
  1299  	}
  1300  	if ctx.GlobalIsSet(MinerGasTargetFlag.Name) {
  1301  		cfg.GasFloor = ctx.GlobalUint64(MinerGasTargetFlag.Name)
  1302  	}
  1303  	if ctx.GlobalIsSet(MinerGasLimitFlag.Name) {
  1304  		cfg.GasCeil = ctx.GlobalUint64(MinerGasLimitFlag.Name)
  1305  	}
  1306  	if ctx.GlobalIsSet(MinerLegacyGasPriceFlag.Name) {
  1307  		cfg.GasPrice = GlobalBig(ctx, MinerLegacyGasPriceFlag.Name)
  1308  	}
  1309  	if ctx.GlobalIsSet(MinerGasPriceFlag.Name) {
  1310  		cfg.GasPrice = GlobalBig(ctx, MinerGasPriceFlag.Name)
  1311  	}
  1312  	if ctx.GlobalIsSet(MinerRecommitIntervalFlag.Name) {
  1313  		cfg.Recommit = ctx.Duration(MinerRecommitIntervalFlag.Name)
  1314  	}
  1315  	if ctx.GlobalIsSet(MinerNoVerfiyFlag.Name) {
  1316  		cfg.Noverify = ctx.Bool(MinerNoVerfiyFlag.Name)
  1317  	}
  1318  }
  1319  
  1320  func setWhitelist(ctx *cli.Context, cfg *eth.Config) {
  1321  	whitelist := ctx.GlobalString(WhitelistFlag.Name)
  1322  	if whitelist == "" {
  1323  		return
  1324  	}
  1325  	cfg.Whitelist = make(map[uint64]common.Hash)
  1326  	for _, entry := range strings.Split(whitelist, ",") {
  1327  		parts := strings.Split(entry, "=")
  1328  		if len(parts) != 2 {
  1329  			Fatalf("Invalid whitelist entry: %s", entry)
  1330  		}
  1331  		number, err := strconv.ParseUint(parts[0], 0, 64)
  1332  		if err != nil {
  1333  			Fatalf("Invalid whitelist block number %s: %v", parts[0], err)
  1334  		}
  1335  		var hash common.Hash
  1336  		if err = hash.UnmarshalText([]byte(parts[1])); err != nil {
  1337  			Fatalf("Invalid whitelist hash %s: %v", parts[1], err)
  1338  		}
  1339  		cfg.Whitelist[number] = hash
  1340  	}
  1341  }
  1342  
  1343  // CheckExclusive verifies that only a single instance of the provided flags was
  1344  // set by the user. Each flag might optionally be followed by a string type to
  1345  // specialize it further.
  1346  func CheckExclusive(ctx *cli.Context, args ...interface{}) {
  1347  	set := make([]string, 0, 1)
  1348  	for i := 0; i < len(args); i++ {
  1349  		// Make sure the next argument is a flag and skip if not set
  1350  		flag, ok := args[i].(cli.Flag)
  1351  		if !ok {
  1352  			panic(fmt.Sprintf("invalid argument, not cli.Flag type: %T", args[i]))
  1353  		}
  1354  		// Check if next arg extends current and expand its name if so
  1355  		name := flag.GetName()
  1356  
  1357  		if i+1 < len(args) {
  1358  			switch option := args[i+1].(type) {
  1359  			case string:
  1360  				// Extended flag check, make sure value set doesn't conflict with passed in option
  1361  				if ctx.GlobalString(flag.GetName()) == option {
  1362  					name += "=" + option
  1363  					set = append(set, "--"+name)
  1364  				}
  1365  				// shift arguments and continue
  1366  				i++
  1367  				continue
  1368  
  1369  			case cli.Flag:
  1370  			default:
  1371  				panic(fmt.Sprintf("invalid argument, not cli.Flag or string extension: %T", args[i+1]))
  1372  			}
  1373  		}
  1374  		// Mark the flag if it's set
  1375  		if ctx.GlobalIsSet(flag.GetName()) {
  1376  			set = append(set, "--"+name)
  1377  		}
  1378  	}
  1379  	if len(set) > 1 {
  1380  		Fatalf("Flags %v can't be used at the same time", strings.Join(set, ", "))
  1381  	}
  1382  }
  1383  
  1384  // SetShhConfig applies shh-related command line flags to the config.
  1385  func SetShhConfig(ctx *cli.Context, stack *node.Node, cfg *whisper.Config) {
  1386  	if ctx.GlobalIsSet(WhisperMaxMessageSizeFlag.Name) {
  1387  		cfg.MaxMessageSize = uint32(ctx.GlobalUint(WhisperMaxMessageSizeFlag.Name))
  1388  	}
  1389  	if ctx.GlobalIsSet(WhisperMinPOWFlag.Name) {
  1390  		cfg.MinimumAcceptedPOW = ctx.GlobalFloat64(WhisperMinPOWFlag.Name)
  1391  	}
  1392  	if ctx.GlobalIsSet(WhisperRestrictConnectionBetweenLightClientsFlag.Name) {
  1393  		cfg.RestrictConnectionBetweenLightClients = true
  1394  	}
  1395  }
  1396  
  1397  // SetEthConfig applies eth-related command line flags to the config.
  1398  func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *eth.Config) {
  1399  	// Avoid conflicting network flags
  1400  	CheckExclusive(ctx, DeveloperFlag, TestnetFlag, RinkebyFlag, GoerliFlag)
  1401  	CheckExclusive(ctx, LightLegacyServFlag, LightServeFlag, SyncModeFlag, "light")
  1402  	CheckExclusive(ctx, DeveloperFlag, ExternalSignerFlag) // Can't use both ephemeral unlocked and external signer
  1403  
  1404  	var ks *keystore.KeyStore
  1405  	if keystores := stack.AccountManager().Backends(keystore.KeyStoreType); len(keystores) > 0 {
  1406  		ks = keystores[0].(*keystore.KeyStore)
  1407  	}
  1408  	setEtherbase(ctx, ks, cfg)
  1409  	setGPO(ctx, &cfg.GPO)
  1410  	setTxPool(ctx, &cfg.TxPool)
  1411  	setEthash(ctx, cfg)
  1412  	setMiner(ctx, &cfg.Miner)
  1413  	setWhitelist(ctx, cfg)
  1414  	setLes(ctx, cfg)
  1415  
  1416  	if ctx.GlobalIsSet(SyncModeFlag.Name) {
  1417  		cfg.SyncMode = *GlobalTextMarshaler(ctx, SyncModeFlag.Name).(*downloader.SyncMode)
  1418  	}
  1419  	if ctx.GlobalIsSet(NetworkIdFlag.Name) {
  1420  		cfg.NetworkId = ctx.GlobalUint64(NetworkIdFlag.Name)
  1421  	}
  1422  	if ctx.GlobalIsSet(CacheFlag.Name) || ctx.GlobalIsSet(CacheDatabaseFlag.Name) {
  1423  		cfg.DatabaseCache = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheDatabaseFlag.Name) / 100
  1424  	}
  1425  	cfg.DatabaseHandles = makeDatabaseHandles()
  1426  	if ctx.GlobalIsSet(AncientFlag.Name) {
  1427  		cfg.DatabaseFreezer = ctx.GlobalString(AncientFlag.Name)
  1428  	}
  1429  
  1430  	if gcmode := ctx.GlobalString(GCModeFlag.Name); gcmode != "full" && gcmode != "archive" {
  1431  		Fatalf("--%s must be either 'full' or 'archive'", GCModeFlag.Name)
  1432  	}
  1433  	cfg.NoPruning = ctx.GlobalString(GCModeFlag.Name) == "archive"
  1434  	cfg.NoPrefetch = ctx.GlobalBool(CacheNoPrefetchFlag.Name)
  1435  
  1436  	if ctx.GlobalIsSet(CacheFlag.Name) || ctx.GlobalIsSet(CacheTrieFlag.Name) {
  1437  		cfg.TrieCleanCache = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheTrieFlag.Name) / 100
  1438  	}
  1439  	if ctx.GlobalIsSet(CacheFlag.Name) || ctx.GlobalIsSet(CacheGCFlag.Name) {
  1440  		cfg.TrieDirtyCache = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheGCFlag.Name) / 100
  1441  	}
  1442  	if ctx.GlobalIsSet(DocRootFlag.Name) {
  1443  		cfg.DocRoot = ctx.GlobalString(DocRootFlag.Name)
  1444  	}
  1445  	if ctx.GlobalIsSet(VMEnableDebugFlag.Name) {
  1446  		// TODO(fjl): force-enable this in --dev mode
  1447  		cfg.EnablePreimageRecording = ctx.GlobalBool(VMEnableDebugFlag.Name)
  1448  	}
  1449  
  1450  	if ctx.GlobalIsSet(EWASMInterpreterFlag.Name) {
  1451  		cfg.EWASMInterpreter = ctx.GlobalString(EWASMInterpreterFlag.Name)
  1452  	}
  1453  
  1454  	if ctx.GlobalIsSet(EVMInterpreterFlag.Name) {
  1455  		cfg.EVMInterpreter = ctx.GlobalString(EVMInterpreterFlag.Name)
  1456  	}
  1457  	if ctx.GlobalIsSet(RPCGlobalGasCap.Name) {
  1458  		cfg.RPCGasCap = new(big.Int).SetUint64(ctx.GlobalUint64(RPCGlobalGasCap.Name))
  1459  	}
  1460  
  1461  	// Override any default configs for hard coded networks.
  1462  	switch {
  1463  	case ctx.GlobalBool(TestnetFlag.Name):
  1464  		if !ctx.GlobalIsSet(NetworkIdFlag.Name) {
  1465  			cfg.NetworkId = 3
  1466  		}
  1467  		cfg.Genesis = core.DefaultTestnetGenesisBlock()
  1468  	case ctx.GlobalBool(RinkebyFlag.Name):
  1469  		if !ctx.GlobalIsSet(NetworkIdFlag.Name) {
  1470  			cfg.NetworkId = 4
  1471  		}
  1472  		cfg.Genesis = core.DefaultRinkebyGenesisBlock()
  1473  	case ctx.GlobalBool(GoerliFlag.Name):
  1474  		if !ctx.GlobalIsSet(NetworkIdFlag.Name) {
  1475  			cfg.NetworkId = 5
  1476  		}
  1477  		cfg.Genesis = core.DefaultGoerliGenesisBlock()
  1478  	case ctx.GlobalBool(DeveloperFlag.Name):
  1479  		if !ctx.GlobalIsSet(NetworkIdFlag.Name) {
  1480  			cfg.NetworkId = 1337
  1481  		}
  1482  		// Create new developer account or reuse existing one
  1483  		var (
  1484  			developer accounts.Account
  1485  			err       error
  1486  		)
  1487  		if accs := ks.Accounts(); len(accs) > 0 {
  1488  			developer = ks.Accounts()[0]
  1489  		} else {
  1490  			developer, err = ks.NewAccount("")
  1491  			if err != nil {
  1492  				Fatalf("Failed to create developer account: %v", err)
  1493  			}
  1494  		}
  1495  		if err := ks.Unlock(developer, ""); err != nil {
  1496  			Fatalf("Failed to unlock developer account: %v", err)
  1497  		}
  1498  		log.Info("Using developer account", "address", developer.Address)
  1499  
  1500  		cfg.Genesis = core.DeveloperGenesisBlock(uint64(ctx.GlobalInt(DeveloperPeriodFlag.Name)), developer.Address)
  1501  		if !ctx.GlobalIsSet(MinerGasPriceFlag.Name) && !ctx.GlobalIsSet(MinerLegacyGasPriceFlag.Name) {
  1502  			cfg.Miner.GasPrice = big.NewInt(1)
  1503  		}
  1504  	}
  1505  }
  1506  
  1507  // SetDashboardConfig applies dashboard related command line flags to the config.
  1508  func SetDashboardConfig(ctx *cli.Context, cfg *dashboard.Config) {
  1509  	cfg.Host = ctx.GlobalString(DashboardAddrFlag.Name)
  1510  	cfg.Port = ctx.GlobalInt(DashboardPortFlag.Name)
  1511  	cfg.Refresh = ctx.GlobalDuration(DashboardRefreshFlag.Name)
  1512  }
  1513  
  1514  // RegisterEthService adds an Ethereum client to the stack.
  1515  func RegisterEthService(stack *node.Node, cfg *eth.Config) {
  1516  	var err error
  1517  	if cfg.SyncMode == downloader.LightSync {
  1518  		err = stack.Register(func(ctx *node.ServiceContext) (node.Service, error) {
  1519  			return les.New(ctx, cfg)
  1520  		})
  1521  	} else {
  1522  		err = stack.Register(func(ctx *node.ServiceContext) (node.Service, error) {
  1523  			fullNode, err := eth.New(ctx, cfg)
  1524  			if fullNode != nil && cfg.LightServ > 0 {
  1525  				ls, _ := les.NewLesServer(fullNode, cfg)
  1526  				fullNode.AddLesServer(ls)
  1527  			}
  1528  			return fullNode, err
  1529  		})
  1530  	}
  1531  	if err != nil {
  1532  		Fatalf("Failed to register the Ethereum service: %v", err)
  1533  	}
  1534  }
  1535  
  1536  // RegisterDashboardService adds a dashboard to the stack.
  1537  func RegisterDashboardService(stack *node.Node, cfg *dashboard.Config, commit string) {
  1538  	stack.Register(func(ctx *node.ServiceContext) (node.Service, error) {
  1539  		return dashboard.New(cfg, commit, ctx.ResolvePath("logs")), nil
  1540  	})
  1541  }
  1542  
  1543  // RegisterShhService configures Whisper and adds it to the given node.
  1544  func RegisterShhService(stack *node.Node, cfg *whisper.Config) {
  1545  	if err := stack.Register(func(n *node.ServiceContext) (node.Service, error) {
  1546  		return whisper.New(cfg), nil
  1547  	}); err != nil {
  1548  		Fatalf("Failed to register the Whisper service: %v", err)
  1549  	}
  1550  }
  1551  
  1552  // RegisterEthStatsService configures the Ethereum Stats daemon and adds it to
  1553  // the given node.
  1554  func RegisterEthStatsService(stack *node.Node, url string) {
  1555  	if err := stack.Register(func(ctx *node.ServiceContext) (node.Service, error) {
  1556  		// Retrieve both eth and les services
  1557  		var ethServ *eth.Ethereum
  1558  		ctx.Service(&ethServ)
  1559  
  1560  		var lesServ *les.LightEthereum
  1561  		ctx.Service(&lesServ)
  1562  
  1563  		// Let ethstats use whichever is not nil
  1564  		return ethstats.New(url, ethServ, lesServ)
  1565  	}); err != nil {
  1566  		Fatalf("Failed to register the Ethereum Stats service: %v", err)
  1567  	}
  1568  }
  1569  
  1570  // RegisterGraphQLService is a utility function to construct a new service and register it against a node.
  1571  func RegisterGraphQLService(stack *node.Node, endpoint string, cors, vhosts []string, timeouts rpc.HTTPTimeouts) {
  1572  	if err := stack.Register(func(ctx *node.ServiceContext) (node.Service, error) {
  1573  		// Try to construct the GraphQL service backed by a full node
  1574  		var ethServ *eth.Ethereum
  1575  		if err := ctx.Service(&ethServ); err == nil {
  1576  			return graphql.New(ethServ.APIBackend, endpoint, cors, vhosts, timeouts)
  1577  		}
  1578  		// Try to construct the GraphQL service backed by a light node
  1579  		var lesServ *les.LightEthereum
  1580  		if err := ctx.Service(&lesServ); err == nil {
  1581  			return graphql.New(lesServ.ApiBackend, endpoint, cors, vhosts, timeouts)
  1582  		}
  1583  		// Well, this should not have happened, bail out
  1584  		return nil, errors.New("no Ethereum service")
  1585  	}); err != nil {
  1586  		Fatalf("Failed to register the GraphQL service: %v", err)
  1587  	}
  1588  }
  1589  
  1590  func SetupMetrics(ctx *cli.Context) {
  1591  	if metrics.Enabled {
  1592  		log.Info("Enabling metrics collection")
  1593  		var (
  1594  			enableExport = ctx.GlobalBool(MetricsEnableInfluxDBFlag.Name)
  1595  			endpoint     = ctx.GlobalString(MetricsInfluxDBEndpointFlag.Name)
  1596  			database     = ctx.GlobalString(MetricsInfluxDBDatabaseFlag.Name)
  1597  			username     = ctx.GlobalString(MetricsInfluxDBUsernameFlag.Name)
  1598  			password     = ctx.GlobalString(MetricsInfluxDBPasswordFlag.Name)
  1599  		)
  1600  
  1601  		if enableExport {
  1602  			tagsMap := SplitTagsFlag(ctx.GlobalString(MetricsInfluxDBTagsFlag.Name))
  1603  
  1604  			log.Info("Enabling metrics export to InfluxDB")
  1605  
  1606  			go influxdb.InfluxDBWithTags(metrics.DefaultRegistry, 10*time.Second, endpoint, database, username, password, "geth.", tagsMap)
  1607  		}
  1608  	}
  1609  }
  1610  
  1611  func SplitTagsFlag(tagsFlag string) map[string]string {
  1612  	tags := strings.Split(tagsFlag, ",")
  1613  	tagsMap := map[string]string{}
  1614  
  1615  	for _, t := range tags {
  1616  		if t != "" {
  1617  			kv := strings.Split(t, "=")
  1618  
  1619  			if len(kv) == 2 {
  1620  				tagsMap[kv[0]] = kv[1]
  1621  			}
  1622  		}
  1623  	}
  1624  
  1625  	return tagsMap
  1626  }
  1627  
  1628  // MakeChainDatabase open an LevelDB using the flags passed to the client and will hard crash if it fails.
  1629  func MakeChainDatabase(ctx *cli.Context, stack *node.Node) ethdb.Database {
  1630  	var (
  1631  		cache   = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheDatabaseFlag.Name) / 100
  1632  		handles = makeDatabaseHandles()
  1633  	)
  1634  	name := "chaindata"
  1635  	if ctx.GlobalString(SyncModeFlag.Name) == "light" {
  1636  		name = "lightchaindata"
  1637  	}
  1638  	chainDb, err := stack.OpenDatabaseWithFreezer(name, cache, handles, ctx.GlobalString(AncientFlag.Name), "")
  1639  	if err != nil {
  1640  		Fatalf("Could not open database: %v", err)
  1641  	}
  1642  	return chainDb
  1643  }
  1644  
  1645  func MakeGenesis(ctx *cli.Context) *core.Genesis {
  1646  	var genesis *core.Genesis
  1647  	switch {
  1648  	case ctx.GlobalBool(TestnetFlag.Name):
  1649  		genesis = core.DefaultTestnetGenesisBlock()
  1650  	case ctx.GlobalBool(RinkebyFlag.Name):
  1651  		genesis = core.DefaultRinkebyGenesisBlock()
  1652  	case ctx.GlobalBool(GoerliFlag.Name):
  1653  		genesis = core.DefaultGoerliGenesisBlock()
  1654  	case ctx.GlobalBool(DeveloperFlag.Name):
  1655  		Fatalf("Developer chains are ephemeral")
  1656  	}
  1657  	return genesis
  1658  }
  1659  
  1660  // MakeChain creates a chain manager from set command line flags.
  1661  func MakeChain(ctx *cli.Context, stack *node.Node) (chain *core.BlockChain, chainDb ethdb.Database) {
  1662  	var err error
  1663  	chainDb = MakeChainDatabase(ctx, stack)
  1664  	config, _, err := core.SetupGenesisBlock(chainDb, MakeGenesis(ctx))
  1665  	if err != nil {
  1666  		Fatalf("%v", err)
  1667  	}
  1668  	var engine consensus.Engine
  1669  	if config.Clique != nil {
  1670  		engine = clique.New(config.Clique, chainDb)
  1671  	} else {
  1672  		engine = ethash.NewFaker()
  1673  		if !ctx.GlobalBool(FakePoWFlag.Name) {
  1674  			engine = ethash.New(ethash.Config{
  1675  				CacheDir:       stack.ResolvePath(eth.DefaultConfig.Ethash.CacheDir),
  1676  				CachesInMem:    eth.DefaultConfig.Ethash.CachesInMem,
  1677  				CachesOnDisk:   eth.DefaultConfig.Ethash.CachesOnDisk,
  1678  				DatasetDir:     stack.ResolvePath(eth.DefaultConfig.Ethash.DatasetDir),
  1679  				DatasetsInMem:  eth.DefaultConfig.Ethash.DatasetsInMem,
  1680  				DatasetsOnDisk: eth.DefaultConfig.Ethash.DatasetsOnDisk,
  1681  			}, nil, false)
  1682  		}
  1683  	}
  1684  	if gcmode := ctx.GlobalString(GCModeFlag.Name); gcmode != "full" && gcmode != "archive" {
  1685  		Fatalf("--%s must be either 'full' or 'archive'", GCModeFlag.Name)
  1686  	}
  1687  	cache := &core.CacheConfig{
  1688  		TrieCleanLimit:      eth.DefaultConfig.TrieCleanCache,
  1689  		TrieCleanNoPrefetch: ctx.GlobalBool(CacheNoPrefetchFlag.Name),
  1690  		TrieDirtyLimit:      eth.DefaultConfig.TrieDirtyCache,
  1691  		TrieDirtyDisabled:   ctx.GlobalString(GCModeFlag.Name) == "archive",
  1692  		TrieTimeLimit:       eth.DefaultConfig.TrieTimeout,
  1693  	}
  1694  	if ctx.GlobalIsSet(CacheFlag.Name) || ctx.GlobalIsSet(CacheTrieFlag.Name) {
  1695  		cache.TrieCleanLimit = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheTrieFlag.Name) / 100
  1696  	}
  1697  	if ctx.GlobalIsSet(CacheFlag.Name) || ctx.GlobalIsSet(CacheGCFlag.Name) {
  1698  		cache.TrieDirtyLimit = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheGCFlag.Name) / 100
  1699  	}
  1700  	vmcfg := vm.Config{EnablePreimageRecording: ctx.GlobalBool(VMEnableDebugFlag.Name)}
  1701  	chain, err = core.NewBlockChain(chainDb, cache, config, engine, vmcfg, nil)
  1702  	if err != nil {
  1703  		Fatalf("Can't create BlockChain: %v", err)
  1704  	}
  1705  	return chain, chainDb
  1706  }
  1707  
  1708  // MakeConsolePreloads retrieves the absolute paths for the console JavaScript
  1709  // scripts to preload before starting.
  1710  func MakeConsolePreloads(ctx *cli.Context) []string {
  1711  	// Skip preloading if there's nothing to preload
  1712  	if ctx.GlobalString(PreloadJSFlag.Name) == "" {
  1713  		return nil
  1714  	}
  1715  	// Otherwise resolve absolute paths and return them
  1716  	var preloads []string
  1717  
  1718  	assets := ctx.GlobalString(JSpathFlag.Name)
  1719  	for _, file := range strings.Split(ctx.GlobalString(PreloadJSFlag.Name), ",") {
  1720  		preloads = append(preloads, common.AbsolutePath(assets, strings.TrimSpace(file)))
  1721  	}
  1722  	return preloads
  1723  }
  1724  
  1725  // MigrateFlags sets the global flag from a local flag when it's set.
  1726  // This is a temporary function used for migrating old command/flags to the
  1727  // new format.
  1728  //
  1729  // e.g. geth account new --keystore /tmp/mykeystore --lightkdf
  1730  //
  1731  // is equivalent after calling this method with:
  1732  //
  1733  // geth --keystore /tmp/mykeystore --lightkdf account new
  1734  //
  1735  // This allows the use of the existing configuration functionality.
  1736  // When all flags are migrated this function can be removed and the existing
  1737  // configuration functionality must be changed that is uses local flags
  1738  func MigrateFlags(action func(ctx *cli.Context) error) func(*cli.Context) error {
  1739  	return func(ctx *cli.Context) error {
  1740  		for _, name := range ctx.FlagNames() {
  1741  			if ctx.IsSet(name) {
  1742  				ctx.GlobalSet(name, ctx.String(name))
  1743  			}
  1744  		}
  1745  		return action(ctx)
  1746  	}
  1747  }