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