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