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