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