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