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