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