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