github.com/letterj/go-ethereum@v1.8.22-0.20190204142846-520024dfd689/cmd/utils/flags.go (about)

     1  // Copyright 2015 The go-ethereum Authors
     2  // This file is part of go-ethereum.
     3  //
     4  // go-ethereum is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // go-ethereum is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU General Public License
    15  // along with go-ethereum. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  // Package utils contains internal helper functions for go-ethereum commands.
    18  package utils
    19  
    20  import (
    21  	"crypto/ecdsa"
    22  	"encoding/json"
    23  	"fmt"
    24  	"io/ioutil"
    25  	"math/big"
    26  	"os"
    27  	"path/filepath"
    28  	"strconv"
    29  	"strings"
    30  	"time"
    31  
    32  	"github.com/ethereum/go-ethereum/accounts"
    33  	"github.com/ethereum/go-ethereum/accounts/keystore"
    34  	"github.com/ethereum/go-ethereum/common"
    35  	"github.com/ethereum/go-ethereum/common/fdlimit"
    36  	"github.com/ethereum/go-ethereum/consensus"
    37  	"github.com/ethereum/go-ethereum/consensus/clique"
    38  	"github.com/ethereum/go-ethereum/consensus/ethash"
    39  	"github.com/ethereum/go-ethereum/core"
    40  	"github.com/ethereum/go-ethereum/core/state"
    41  	"github.com/ethereum/go-ethereum/core/vm"
    42  	"github.com/ethereum/go-ethereum/crypto"
    43  	"github.com/ethereum/go-ethereum/dashboard"
    44  	"github.com/ethereum/go-ethereum/eth"
    45  	"github.com/ethereum/go-ethereum/eth/downloader"
    46  	"github.com/ethereum/go-ethereum/eth/gasprice"
    47  	"github.com/ethereum/go-ethereum/ethdb"
    48  	"github.com/ethereum/go-ethereum/ethstats"
    49  	"github.com/ethereum/go-ethereum/les"
    50  	"github.com/ethereum/go-ethereum/log"
    51  	"github.com/ethereum/go-ethereum/metrics"
    52  	"github.com/ethereum/go-ethereum/metrics/influxdb"
    53  	"github.com/ethereum/go-ethereum/node"
    54  	"github.com/ethereum/go-ethereum/p2p"
    55  	"github.com/ethereum/go-ethereum/p2p/discv5"
    56  	"github.com/ethereum/go-ethereum/p2p/enode"
    57  	"github.com/ethereum/go-ethereum/p2p/nat"
    58  	"github.com/ethereum/go-ethereum/p2p/netutil"
    59  	"github.com/ethereum/go-ethereum/params"
    60  	whisper "github.com/ethereum/go-ethereum/whisper/whisperv6"
    61  	cli "gopkg.in/urfave/cli.v1"
    62  )
    63  
    64  var (
    65  	CommandHelpTemplate = `{{.cmd.Name}}{{if .cmd.Subcommands}} command{{end}}{{if .cmd.Flags}} [command options]{{end}} [arguments...]
    66  {{if .cmd.Description}}{{.cmd.Description}}
    67  {{end}}{{if .cmd.Subcommands}}
    68  SUBCOMMANDS:
    69  	{{range .cmd.Subcommands}}{{.Name}}{{with .ShortName}}, {{.}}{{end}}{{ "\t" }}{{.Usage}}
    70  	{{end}}{{end}}{{if .categorizedFlags}}
    71  {{range $idx, $categorized := .categorizedFlags}}{{$categorized.Name}} OPTIONS:
    72  {{range $categorized.Flags}}{{"\t"}}{{.}}
    73  {{end}}
    74  {{end}}{{end}}`
    75  )
    76  
    77  func init() {
    78  	cli.AppHelpTemplate = `{{.Name}} {{if .Flags}}[global options] {{end}}command{{if .Flags}} [command options]{{end}} [arguments...]
    79  
    80  VERSION:
    81     {{.Version}}
    82  
    83  COMMANDS:
    84     {{range .Commands}}{{.Name}}{{with .ShortName}}, {{.}}{{end}}{{ "\t" }}{{.Usage}}
    85     {{end}}{{if .Flags}}
    86  GLOBAL OPTIONS:
    87     {{range .Flags}}{{.}}
    88     {{end}}{{end}}
    89  `
    90  
    91  	cli.CommandHelpTemplate = CommandHelpTemplate
    92  }
    93  
    94  // NewApp creates an app with sane defaults.
    95  func NewApp(gitCommit, usage string) *cli.App {
    96  	app := cli.NewApp()
    97  	app.Name = filepath.Base(os.Args[0])
    98  	app.Author = ""
    99  	//app.Authors = nil
   100  	app.Email = ""
   101  	app.Version = params.VersionWithMeta
   102  	if len(gitCommit) >= 8 {
   103  		app.Version += "-" + gitCommit[:8]
   104  	}
   105  	app.Usage = usage
   106  	return app
   107  }
   108  
   109  // These are all the command line flags we support.
   110  // If you add to this list, please remember to include the
   111  // flag in the appropriate command definition.
   112  //
   113  // The flags are defined here so their names and help texts
   114  // are the same for all commands.
   115  
   116  var (
   117  	// General settings
   118  	DataDirFlag = DirectoryFlag{
   119  		Name:  "datadir",
   120  		Usage: "Data directory for the databases and keystore",
   121  		Value: DirectoryString{node.DefaultDataDir()},
   122  	}
   123  	KeyStoreDirFlag = DirectoryFlag{
   124  		Name:  "keystore",
   125  		Usage: "Directory for the keystore (default = inside the datadir)",
   126  	}
   127  	NoUSBFlag = cli.BoolFlag{
   128  		Name:  "nousb",
   129  		Usage: "Disables monitoring for and managing USB hardware wallets",
   130  	}
   131  	NetworkIdFlag = cli.Uint64Flag{
   132  		Name:  "networkid",
   133  		Usage: "Network identifier (integer, 1=Frontier, 2=Morden (disused), 3=Ropsten, 4=Rinkeby)",
   134  		Value: eth.DefaultConfig.NetworkId,
   135  	}
   136  	TestnetFlag = cli.BoolFlag{
   137  		Name:  "testnet",
   138  		Usage: "Ropsten network: pre-configured proof-of-work test network",
   139  	}
   140  	RinkebyFlag = cli.BoolFlag{
   141  		Name:  "rinkeby",
   142  		Usage: "Rinkeby network: pre-configured proof-of-authority test network",
   143  	}
   144  	GoerliFlag = cli.BoolFlag{
   145  		Name:  "goerli",
   146  		Usage: "Görli network: pre-configured proof-of-authority test network",
   147  	}
   148  	ConstantinopleOverrideFlag = cli.Uint64Flag{
   149  		Name:  "override.constantinople",
   150  		Usage: "Manually specify constantinople fork-block, overriding the bundled setting",
   151  	}
   152  	DeveloperFlag = cli.BoolFlag{
   153  		Name:  "dev",
   154  		Usage: "Ephemeral proof-of-authority network with a pre-funded developer account, mining enabled",
   155  	}
   156  	DeveloperPeriodFlag = cli.IntFlag{
   157  		Name:  "dev.period",
   158  		Usage: "Block period to use in developer mode (0 = mine only if transaction pending)",
   159  	}
   160  	IdentityFlag = cli.StringFlag{
   161  		Name:  "identity",
   162  		Usage: "Custom node name",
   163  	}
   164  	DocRootFlag = DirectoryFlag{
   165  		Name:  "docroot",
   166  		Usage: "Document Root for HTTPClient file scheme",
   167  		Value: DirectoryString{homeDir()},
   168  	}
   169  	ExitWhenSyncedFlag = cli.BoolFlag{
   170  		Name:  "exitwhensynced",
   171  		Usage: "Exists syncing after block synchronisation",
   172  	}
   173  	ULCModeConfigFlag = cli.StringFlag{
   174  		Name:  "ulc.config",
   175  		Usage: "Config file to use for ultra light client mode",
   176  	}
   177  	OnlyAnnounceModeFlag = cli.BoolFlag{
   178  		Name:  "ulc.onlyannounce",
   179  		Usage: "ULC server sends announcements only",
   180  	}
   181  	ULCMinTrustedFractionFlag = cli.IntFlag{
   182  		Name:  "ulc.fraction",
   183  		Usage: "Minimum % of trusted ULC servers required to announce a new head",
   184  	}
   185  	ULCTrustedNodesFlag = cli.StringFlag{
   186  		Name:  "ulc.trusted",
   187  		Usage: "List of trusted ULC servers",
   188  	}
   189  	defaultSyncMode = eth.DefaultConfig.SyncMode
   190  	SyncModeFlag    = TextMarshalerFlag{
   191  		Name:  "syncmode",
   192  		Usage: `Blockchain sync mode ("fast", "full", or "light")`,
   193  		Value: &defaultSyncMode,
   194  	}
   195  	GCModeFlag = cli.StringFlag{
   196  		Name:  "gcmode",
   197  		Usage: `Blockchain garbage collection mode ("full", "archive")`,
   198  		Value: "full",
   199  	}
   200  	LightServFlag = cli.IntFlag{
   201  		Name:  "lightserv",
   202  		Usage: "Maximum percentage of time allowed for serving LES requests (0-90)",
   203  		Value: 0,
   204  	}
   205  	LightPeersFlag = cli.IntFlag{
   206  		Name:  "lightpeers",
   207  		Usage: "Maximum number of LES client peers",
   208  		Value: eth.DefaultConfig.LightPeers,
   209  	}
   210  	LightKDFFlag = cli.BoolFlag{
   211  		Name:  "lightkdf",
   212  		Usage: "Reduce key-derivation RAM & CPU usage at some expense of KDF strength",
   213  	}
   214  	WhitelistFlag = cli.StringFlag{
   215  		Name:  "whitelist",
   216  		Usage: "Comma separated block number-to-hash mappings to enforce (<number>=<hash>)",
   217  	}
   218  	// Dashboard settings
   219  	DashboardEnabledFlag = cli.BoolFlag{
   220  		Name:  metrics.DashboardEnabledFlag,
   221  		Usage: "Enable the dashboard",
   222  	}
   223  	DashboardAddrFlag = cli.StringFlag{
   224  		Name:  "dashboard.addr",
   225  		Usage: "Dashboard listening interface",
   226  		Value: dashboard.DefaultConfig.Host,
   227  	}
   228  	DashboardPortFlag = cli.IntFlag{
   229  		Name:  "dashboard.host",
   230  		Usage: "Dashboard listening port",
   231  		Value: dashboard.DefaultConfig.Port,
   232  	}
   233  	DashboardRefreshFlag = cli.DurationFlag{
   234  		Name:  "dashboard.refresh",
   235  		Usage: "Dashboard metrics collection refresh rate",
   236  		Value: dashboard.DefaultConfig.Refresh,
   237  	}
   238  	// Ethash settings
   239  	EthashCacheDirFlag = DirectoryFlag{
   240  		Name:  "ethash.cachedir",
   241  		Usage: "Directory to store the ethash verification caches (default = inside the datadir)",
   242  	}
   243  	EthashCachesInMemoryFlag = cli.IntFlag{
   244  		Name:  "ethash.cachesinmem",
   245  		Usage: "Number of recent ethash caches to keep in memory (16MB each)",
   246  		Value: eth.DefaultConfig.Ethash.CachesInMem,
   247  	}
   248  	EthashCachesOnDiskFlag = cli.IntFlag{
   249  		Name:  "ethash.cachesondisk",
   250  		Usage: "Number of recent ethash caches to keep on disk (16MB each)",
   251  		Value: eth.DefaultConfig.Ethash.CachesOnDisk,
   252  	}
   253  	EthashDatasetDirFlag = DirectoryFlag{
   254  		Name:  "ethash.dagdir",
   255  		Usage: "Directory to store the ethash mining DAGs (default = inside home folder)",
   256  		Value: DirectoryString{eth.DefaultConfig.Ethash.DatasetDir},
   257  	}
   258  	EthashDatasetsInMemoryFlag = cli.IntFlag{
   259  		Name:  "ethash.dagsinmem",
   260  		Usage: "Number of recent ethash mining DAGs to keep in memory (1+GB each)",
   261  		Value: eth.DefaultConfig.Ethash.DatasetsInMem,
   262  	}
   263  	EthashDatasetsOnDiskFlag = cli.IntFlag{
   264  		Name:  "ethash.dagsondisk",
   265  		Usage: "Number of recent ethash mining DAGs to keep on disk (1+GB each)",
   266  		Value: eth.DefaultConfig.Ethash.DatasetsOnDisk,
   267  	}
   268  	// Transaction pool settings
   269  	TxPoolLocalsFlag = cli.StringFlag{
   270  		Name:  "txpool.locals",
   271  		Usage: "Comma separated accounts to treat as locals (no flush, priority inclusion)",
   272  	}
   273  	TxPoolNoLocalsFlag = cli.BoolFlag{
   274  		Name:  "txpool.nolocals",
   275  		Usage: "Disables price exemptions for locally submitted transactions",
   276  	}
   277  	TxPoolJournalFlag = cli.StringFlag{
   278  		Name:  "txpool.journal",
   279  		Usage: "Disk journal for local transaction to survive node restarts",
   280  		Value: core.DefaultTxPoolConfig.Journal,
   281  	}
   282  	TxPoolRejournalFlag = cli.DurationFlag{
   283  		Name:  "txpool.rejournal",
   284  		Usage: "Time interval to regenerate the local transaction journal",
   285  		Value: core.DefaultTxPoolConfig.Rejournal,
   286  	}
   287  	TxPoolPriceLimitFlag = cli.Uint64Flag{
   288  		Name:  "txpool.pricelimit",
   289  		Usage: "Minimum gas price limit to enforce for acceptance into the pool",
   290  		Value: eth.DefaultConfig.TxPool.PriceLimit,
   291  	}
   292  	TxPoolPriceBumpFlag = cli.Uint64Flag{
   293  		Name:  "txpool.pricebump",
   294  		Usage: "Price bump percentage to replace an already existing transaction",
   295  		Value: eth.DefaultConfig.TxPool.PriceBump,
   296  	}
   297  	TxPoolAccountSlotsFlag = cli.Uint64Flag{
   298  		Name:  "txpool.accountslots",
   299  		Usage: "Minimum number of executable transaction slots guaranteed per account",
   300  		Value: eth.DefaultConfig.TxPool.AccountSlots,
   301  	}
   302  	TxPoolGlobalSlotsFlag = cli.Uint64Flag{
   303  		Name:  "txpool.globalslots",
   304  		Usage: "Maximum number of executable transaction slots for all accounts",
   305  		Value: eth.DefaultConfig.TxPool.GlobalSlots,
   306  	}
   307  	TxPoolAccountQueueFlag = cli.Uint64Flag{
   308  		Name:  "txpool.accountqueue",
   309  		Usage: "Maximum number of non-executable transaction slots permitted per account",
   310  		Value: eth.DefaultConfig.TxPool.AccountQueue,
   311  	}
   312  	TxPoolGlobalQueueFlag = cli.Uint64Flag{
   313  		Name:  "txpool.globalqueue",
   314  		Usage: "Maximum number of non-executable transaction slots for all accounts",
   315  		Value: eth.DefaultConfig.TxPool.GlobalQueue,
   316  	}
   317  	TxPoolLifetimeFlag = cli.DurationFlag{
   318  		Name:  "txpool.lifetime",
   319  		Usage: "Maximum amount of time non-executable transaction are queued",
   320  		Value: eth.DefaultConfig.TxPool.Lifetime,
   321  	}
   322  	// Performance tuning settings
   323  	CacheFlag = cli.IntFlag{
   324  		Name:  "cache",
   325  		Usage: "Megabytes of memory allocated to internal caching",
   326  		Value: 1024,
   327  	}
   328  	CacheDatabaseFlag = cli.IntFlag{
   329  		Name:  "cache.database",
   330  		Usage: "Percentage of cache memory allowance to use for database io",
   331  		Value: 50,
   332  	}
   333  	CacheTrieFlag = cli.IntFlag{
   334  		Name:  "cache.trie",
   335  		Usage: "Percentage of cache memory allowance to use for trie caching",
   336  		Value: 25,
   337  	}
   338  	CacheGCFlag = cli.IntFlag{
   339  		Name:  "cache.gc",
   340  		Usage: "Percentage of cache memory allowance to use for trie pruning",
   341  		Value: 25,
   342  	}
   343  	TrieCacheGenFlag = cli.IntFlag{
   344  		Name:  "trie-cache-gens",
   345  		Usage: "Number of trie node generations to keep in memory",
   346  		Value: int(state.MaxTrieCacheGen),
   347  	}
   348  	// Miner settings
   349  	MiningEnabledFlag = cli.BoolFlag{
   350  		Name:  "mine",
   351  		Usage: "Enable mining",
   352  	}
   353  	MinerThreadsFlag = cli.IntFlag{
   354  		Name:  "miner.threads",
   355  		Usage: "Number of CPU threads to use for mining",
   356  		Value: 0,
   357  	}
   358  	MinerLegacyThreadsFlag = cli.IntFlag{
   359  		Name:  "minerthreads",
   360  		Usage: "Number of CPU threads to use for mining (deprecated, use --miner.threads)",
   361  		Value: 0,
   362  	}
   363  	MinerNotifyFlag = cli.StringFlag{
   364  		Name:  "miner.notify",
   365  		Usage: "Comma separated HTTP URL list to notify of new work packages",
   366  	}
   367  	MinerGasTargetFlag = cli.Uint64Flag{
   368  		Name:  "miner.gastarget",
   369  		Usage: "Target gas floor for mined blocks",
   370  		Value: eth.DefaultConfig.MinerGasFloor,
   371  	}
   372  	MinerLegacyGasTargetFlag = cli.Uint64Flag{
   373  		Name:  "targetgaslimit",
   374  		Usage: "Target gas floor for mined blocks (deprecated, use --miner.gastarget)",
   375  		Value: eth.DefaultConfig.MinerGasFloor,
   376  	}
   377  	MinerGasLimitFlag = cli.Uint64Flag{
   378  		Name:  "miner.gaslimit",
   379  		Usage: "Target gas ceiling for mined blocks",
   380  		Value: eth.DefaultConfig.MinerGasCeil,
   381  	}
   382  	MinerGasPriceFlag = BigFlag{
   383  		Name:  "miner.gasprice",
   384  		Usage: "Minimum gas price for mining a transaction",
   385  		Value: eth.DefaultConfig.MinerGasPrice,
   386  	}
   387  	MinerLegacyGasPriceFlag = BigFlag{
   388  		Name:  "gasprice",
   389  		Usage: "Minimum gas price for mining a transaction (deprecated, use --miner.gasprice)",
   390  		Value: eth.DefaultConfig.MinerGasPrice,
   391  	}
   392  	MinerEtherbaseFlag = cli.StringFlag{
   393  		Name:  "miner.etherbase",
   394  		Usage: "Public address for block mining rewards (default = first account)",
   395  		Value: "0",
   396  	}
   397  	MinerLegacyEtherbaseFlag = cli.StringFlag{
   398  		Name:  "etherbase",
   399  		Usage: "Public address for block mining rewards (default = first account, deprecated, use --miner.etherbase)",
   400  		Value: "0",
   401  	}
   402  	MinerExtraDataFlag = cli.StringFlag{
   403  		Name:  "miner.extradata",
   404  		Usage: "Block extra data set by the miner (default = client version)",
   405  	}
   406  	MinerLegacyExtraDataFlag = cli.StringFlag{
   407  		Name:  "extradata",
   408  		Usage: "Block extra data set by the miner (default = client version, deprecated, use --miner.extradata)",
   409  	}
   410  	MinerRecommitIntervalFlag = cli.DurationFlag{
   411  		Name:  "miner.recommit",
   412  		Usage: "Time interval to recreate the block being mined",
   413  		Value: eth.DefaultConfig.MinerRecommit,
   414  	}
   415  	MinerNoVerfiyFlag = cli.BoolFlag{
   416  		Name:  "miner.noverify",
   417  		Usage: "Disable remote sealing verification",
   418  	}
   419  	// Account settings
   420  	UnlockedAccountFlag = cli.StringFlag{
   421  		Name:  "unlock",
   422  		Usage: "Comma separated list of accounts to unlock",
   423  		Value: "",
   424  	}
   425  	PasswordFileFlag = cli.StringFlag{
   426  		Name:  "password",
   427  		Usage: "Password file to use for non-interactive password input",
   428  		Value: "",
   429  	}
   430  
   431  	VMEnableDebugFlag = cli.BoolFlag{
   432  		Name:  "vmdebug",
   433  		Usage: "Record information useful for VM and contract debugging",
   434  	}
   435  	// Logging and debug settings
   436  	EthStatsURLFlag = cli.StringFlag{
   437  		Name:  "ethstats",
   438  		Usage: "Reporting URL of a ethstats service (nodename:secret@host:port)",
   439  	}
   440  	FakePoWFlag = cli.BoolFlag{
   441  		Name:  "fakepow",
   442  		Usage: "Disables proof-of-work verification",
   443  	}
   444  	NoCompactionFlag = cli.BoolFlag{
   445  		Name:  "nocompaction",
   446  		Usage: "Disables db compaction after import",
   447  	}
   448  	// RPC settings
   449  	RPCEnabledFlag = cli.BoolFlag{
   450  		Name:  "rpc",
   451  		Usage: "Enable the HTTP-RPC server",
   452  	}
   453  	RPCListenAddrFlag = cli.StringFlag{
   454  		Name:  "rpcaddr",
   455  		Usage: "HTTP-RPC server listening interface",
   456  		Value: node.DefaultHTTPHost,
   457  	}
   458  	RPCPortFlag = cli.IntFlag{
   459  		Name:  "rpcport",
   460  		Usage: "HTTP-RPC server listening port",
   461  		Value: node.DefaultHTTPPort,
   462  	}
   463  	GraphQLEnabledFlag = cli.BoolFlag{
   464  		Name:  "graphql",
   465  		Usage: "Enable the GraphQL server",
   466  	}
   467  	GraphQLListenAddrFlag = cli.StringFlag{
   468  		Name:  "graphql.addr",
   469  		Usage: "GraphQL server listening interface",
   470  		Value: node.DefaultGraphQLHost,
   471  	}
   472  	GraphQLPortFlag = cli.IntFlag{
   473  		Name:  "graphql.port",
   474  		Usage: "GraphQL server listening port",
   475  		Value: node.DefaultGraphQLPort,
   476  	}
   477  	GraphQLCORSDomainFlag = cli.StringFlag{
   478  		Name:  "graphql.rpccorsdomain",
   479  		Usage: "Comma separated list of domains from which to accept cross origin requests (browser enforced)",
   480  		Value: "",
   481  	}
   482  	GraphQLVirtualHostsFlag = cli.StringFlag{
   483  		Name:  "graphql.rpcvhosts",
   484  		Usage: "Comma separated list of virtual hostnames from which to accept requests (server enforced). Accepts '*' wildcard.",
   485  		Value: strings.Join(node.DefaultConfig.HTTPVirtualHosts, ","),
   486  	}
   487  	RPCCORSDomainFlag = cli.StringFlag{
   488  		Name:  "rpccorsdomain",
   489  		Usage: "Comma separated list of domains from which to accept cross origin requests (browser enforced)",
   490  		Value: "",
   491  	}
   492  	RPCVirtualHostsFlag = cli.StringFlag{
   493  		Name:  "rpcvhosts",
   494  		Usage: "Comma separated list of virtual hostnames from which to accept requests (server enforced). Accepts '*' wildcard.",
   495  		Value: strings.Join(node.DefaultConfig.HTTPVirtualHosts, ","),
   496  	}
   497  	RPCApiFlag = cli.StringFlag{
   498  		Name:  "rpcapi",
   499  		Usage: "API's offered over the HTTP-RPC interface",
   500  		Value: "",
   501  	}
   502  	IPCDisabledFlag = cli.BoolFlag{
   503  		Name:  "ipcdisable",
   504  		Usage: "Disable the IPC-RPC server",
   505  	}
   506  	IPCPathFlag = DirectoryFlag{
   507  		Name:  "ipcpath",
   508  		Usage: "Filename for IPC socket/pipe within the datadir (explicit paths escape it)",
   509  	}
   510  	WSEnabledFlag = cli.BoolFlag{
   511  		Name:  "ws",
   512  		Usage: "Enable the WS-RPC server",
   513  	}
   514  	WSListenAddrFlag = cli.StringFlag{
   515  		Name:  "wsaddr",
   516  		Usage: "WS-RPC server listening interface",
   517  		Value: node.DefaultWSHost,
   518  	}
   519  	WSPortFlag = cli.IntFlag{
   520  		Name:  "wsport",
   521  		Usage: "WS-RPC server listening port",
   522  		Value: node.DefaultWSPort,
   523  	}
   524  	WSApiFlag = cli.StringFlag{
   525  		Name:  "wsapi",
   526  		Usage: "API's offered over the WS-RPC interface",
   527  		Value: "",
   528  	}
   529  	WSAllowedOriginsFlag = cli.StringFlag{
   530  		Name:  "wsorigins",
   531  		Usage: "Origins from which to accept websockets requests",
   532  		Value: "",
   533  	}
   534  	ExecFlag = cli.StringFlag{
   535  		Name:  "exec",
   536  		Usage: "Execute JavaScript statement",
   537  	}
   538  	PreloadJSFlag = cli.StringFlag{
   539  		Name:  "preload",
   540  		Usage: "Comma separated list of JavaScript files to preload into the console",
   541  	}
   542  
   543  	// Network Settings
   544  	MaxPeersFlag = cli.IntFlag{
   545  		Name:  "maxpeers",
   546  		Usage: "Maximum number of network peers (network disabled if set to 0)",
   547  		Value: 25,
   548  	}
   549  	MaxPendingPeersFlag = cli.IntFlag{
   550  		Name:  "maxpendpeers",
   551  		Usage: "Maximum number of pending connection attempts (defaults used if set to 0)",
   552  		Value: 0,
   553  	}
   554  	ListenPortFlag = cli.IntFlag{
   555  		Name:  "port",
   556  		Usage: "Network listening port",
   557  		Value: 30303,
   558  	}
   559  	BootnodesFlag = cli.StringFlag{
   560  		Name:  "bootnodes",
   561  		Usage: "Comma separated enode URLs for P2P discovery bootstrap (set v4+v5 instead for light servers)",
   562  		Value: "",
   563  	}
   564  	BootnodesV4Flag = cli.StringFlag{
   565  		Name:  "bootnodesv4",
   566  		Usage: "Comma separated enode URLs for P2P v4 discovery bootstrap (light server, full nodes)",
   567  		Value: "",
   568  	}
   569  	BootnodesV5Flag = cli.StringFlag{
   570  		Name:  "bootnodesv5",
   571  		Usage: "Comma separated enode URLs for P2P v5 discovery bootstrap (light server, light nodes)",
   572  		Value: "",
   573  	}
   574  	NodeKeyFileFlag = cli.StringFlag{
   575  		Name:  "nodekey",
   576  		Usage: "P2P node key file",
   577  	}
   578  	NodeKeyHexFlag = cli.StringFlag{
   579  		Name:  "nodekeyhex",
   580  		Usage: "P2P node key as hex (for testing)",
   581  	}
   582  	NATFlag = cli.StringFlag{
   583  		Name:  "nat",
   584  		Usage: "NAT port mapping mechanism (any|none|upnp|pmp|extip:<IP>)",
   585  		Value: "any",
   586  	}
   587  	NoDiscoverFlag = cli.BoolFlag{
   588  		Name:  "nodiscover",
   589  		Usage: "Disables the peer discovery mechanism (manual peer addition)",
   590  	}
   591  	DiscoveryV5Flag = cli.BoolFlag{
   592  		Name:  "v5disc",
   593  		Usage: "Enables the experimental RLPx V5 (Topic Discovery) mechanism",
   594  	}
   595  	NetrestrictFlag = cli.StringFlag{
   596  		Name:  "netrestrict",
   597  		Usage: "Restricts network communication to the given IP networks (CIDR masks)",
   598  	}
   599  
   600  	// ATM the url is left to the user and deployment to
   601  	JSpathFlag = cli.StringFlag{
   602  		Name:  "jspath",
   603  		Usage: "JavaScript root path for `loadScript`",
   604  		Value: ".",
   605  	}
   606  
   607  	// Gas price oracle settings
   608  	GpoBlocksFlag = cli.IntFlag{
   609  		Name:  "gpoblocks",
   610  		Usage: "Number of recent blocks to check for gas prices",
   611  		Value: eth.DefaultConfig.GPO.Blocks,
   612  	}
   613  	GpoPercentileFlag = cli.IntFlag{
   614  		Name:  "gpopercentile",
   615  		Usage: "Suggested gas price is the given percentile of a set of recent transaction gas prices",
   616  		Value: eth.DefaultConfig.GPO.Percentile,
   617  	}
   618  	WhisperEnabledFlag = cli.BoolFlag{
   619  		Name:  "shh",
   620  		Usage: "Enable Whisper",
   621  	}
   622  	WhisperMaxMessageSizeFlag = cli.IntFlag{
   623  		Name:  "shh.maxmessagesize",
   624  		Usage: "Max message size accepted",
   625  		Value: int(whisper.DefaultMaxMessageSize),
   626  	}
   627  	WhisperMinPOWFlag = cli.Float64Flag{
   628  		Name:  "shh.pow",
   629  		Usage: "Minimum POW accepted",
   630  		Value: whisper.DefaultMinimumPoW,
   631  	}
   632  	WhisperRestrictConnectionBetweenLightClientsFlag = cli.BoolFlag{
   633  		Name:  "shh.restrict-light",
   634  		Usage: "Restrict connection between two whisper light clients",
   635  	}
   636  
   637  	// Metrics flags
   638  	MetricsEnabledFlag = cli.BoolFlag{
   639  		Name:  metrics.MetricsEnabledFlag,
   640  		Usage: "Enable metrics collection and reporting",
   641  	}
   642  	MetricsEnableInfluxDBFlag = cli.BoolFlag{
   643  		Name:  "metrics.influxdb",
   644  		Usage: "Enable metrics export/push to an external InfluxDB database",
   645  	}
   646  	MetricsInfluxDBEndpointFlag = cli.StringFlag{
   647  		Name:  "metrics.influxdb.endpoint",
   648  		Usage: "InfluxDB API endpoint to report metrics to",
   649  		Value: "http://localhost:8086",
   650  	}
   651  	MetricsInfluxDBDatabaseFlag = cli.StringFlag{
   652  		Name:  "metrics.influxdb.database",
   653  		Usage: "InfluxDB database name to push reported metrics to",
   654  		Value: "geth",
   655  	}
   656  	MetricsInfluxDBUsernameFlag = cli.StringFlag{
   657  		Name:  "metrics.influxdb.username",
   658  		Usage: "Username to authorize access to the database",
   659  		Value: "test",
   660  	}
   661  	MetricsInfluxDBPasswordFlag = cli.StringFlag{
   662  		Name:  "metrics.influxdb.password",
   663  		Usage: "Password to authorize access to the database",
   664  		Value: "test",
   665  	}
   666  	// Tags are part of every measurement sent to InfluxDB. Queries on tags are faster in InfluxDB.
   667  	// For example `host` tag could be used so that we can group all nodes and average a measurement
   668  	// across all of them, but also so that we can select a specific node and inspect its measurements.
   669  	// https://docs.influxdata.com/influxdb/v1.4/concepts/key_concepts/#tag-key
   670  	MetricsInfluxDBTagsFlag = cli.StringFlag{
   671  		Name:  "metrics.influxdb.tags",
   672  		Usage: "Comma-separated InfluxDB tags (key/values) attached to all measurements",
   673  		Value: "host=localhost",
   674  	}
   675  
   676  	EWASMInterpreterFlag = cli.StringFlag{
   677  		Name:  "vm.ewasm",
   678  		Usage: "External ewasm configuration (default = built-in interpreter)",
   679  		Value: "",
   680  	}
   681  	EVMInterpreterFlag = cli.StringFlag{
   682  		Name:  "vm.evm",
   683  		Usage: "External EVM configuration (default = built-in interpreter)",
   684  		Value: "",
   685  	}
   686  )
   687  
   688  // MakeDataDir retrieves the currently requested data directory, terminating
   689  // if none (or the empty string) is specified. If the node is starting a testnet,
   690  // the a subdirectory of the specified datadir will be used.
   691  func MakeDataDir(ctx *cli.Context) string {
   692  	if path := ctx.GlobalString(DataDirFlag.Name); path != "" {
   693  		if ctx.GlobalBool(TestnetFlag.Name) {
   694  			return filepath.Join(path, "testnet")
   695  		}
   696  		if ctx.GlobalBool(RinkebyFlag.Name) {
   697  			return filepath.Join(path, "rinkeby")
   698  		}
   699  		if ctx.GlobalBool(GoerliFlag.Name) {
   700  			return filepath.Join(path, "goerli")
   701  		}
   702  		return path
   703  	}
   704  	Fatalf("Cannot determine default data directory, please set manually (--datadir)")
   705  	return ""
   706  }
   707  
   708  // setNodeKey creates a node key from set command line flags, either loading it
   709  // from a file or as a specified hex value. If neither flags were provided, this
   710  // method returns nil and an emphemeral key is to be generated.
   711  func setNodeKey(ctx *cli.Context, cfg *p2p.Config) {
   712  	var (
   713  		hex  = ctx.GlobalString(NodeKeyHexFlag.Name)
   714  		file = ctx.GlobalString(NodeKeyFileFlag.Name)
   715  		key  *ecdsa.PrivateKey
   716  		err  error
   717  	)
   718  	switch {
   719  	case file != "" && hex != "":
   720  		Fatalf("Options %q and %q are mutually exclusive", NodeKeyFileFlag.Name, NodeKeyHexFlag.Name)
   721  	case file != "":
   722  		if key, err = crypto.LoadECDSA(file); err != nil {
   723  			Fatalf("Option %q: %v", NodeKeyFileFlag.Name, err)
   724  		}
   725  		cfg.PrivateKey = key
   726  	case hex != "":
   727  		if key, err = crypto.HexToECDSA(hex); err != nil {
   728  			Fatalf("Option %q: %v", NodeKeyHexFlag.Name, err)
   729  		}
   730  		cfg.PrivateKey = key
   731  	}
   732  }
   733  
   734  // setNodeUserIdent creates the user identifier from CLI flags.
   735  func setNodeUserIdent(ctx *cli.Context, cfg *node.Config) {
   736  	if identity := ctx.GlobalString(IdentityFlag.Name); len(identity) > 0 {
   737  		cfg.UserIdent = identity
   738  	}
   739  }
   740  
   741  // setBootstrapNodes creates a list of bootstrap nodes from the command line
   742  // flags, reverting to pre-configured ones if none have been specified.
   743  func setBootstrapNodes(ctx *cli.Context, cfg *p2p.Config) {
   744  	urls := params.MainnetBootnodes
   745  	switch {
   746  	case ctx.GlobalIsSet(BootnodesFlag.Name) || ctx.GlobalIsSet(BootnodesV4Flag.Name):
   747  		if ctx.GlobalIsSet(BootnodesV4Flag.Name) {
   748  			urls = strings.Split(ctx.GlobalString(BootnodesV4Flag.Name), ",")
   749  		} else {
   750  			urls = strings.Split(ctx.GlobalString(BootnodesFlag.Name), ",")
   751  		}
   752  	case ctx.GlobalBool(TestnetFlag.Name):
   753  		urls = params.TestnetBootnodes
   754  	case ctx.GlobalBool(RinkebyFlag.Name):
   755  		urls = params.RinkebyBootnodes
   756  	case ctx.GlobalBool(GoerliFlag.Name):
   757  		urls = params.GoerliBootnodes
   758  	case cfg.BootstrapNodes != nil:
   759  		return // already set, don't apply defaults.
   760  	}
   761  
   762  	cfg.BootstrapNodes = make([]*enode.Node, 0, len(urls))
   763  	for _, url := range urls {
   764  		if url != "" {
   765  			node, err := enode.ParseV4(url)
   766  			if err != nil {
   767  				log.Crit("Bootstrap URL invalid", "enode", url, "err", err)
   768  			}
   769  			cfg.BootstrapNodes = append(cfg.BootstrapNodes, node)
   770  		}
   771  	}
   772  }
   773  
   774  // setBootstrapNodesV5 creates a list of bootstrap nodes from the command line
   775  // flags, reverting to pre-configured ones if none have been specified.
   776  func setBootstrapNodesV5(ctx *cli.Context, cfg *p2p.Config) {
   777  	urls := params.DiscoveryV5Bootnodes
   778  	switch {
   779  	case ctx.GlobalIsSet(BootnodesFlag.Name) || ctx.GlobalIsSet(BootnodesV5Flag.Name):
   780  		if ctx.GlobalIsSet(BootnodesV5Flag.Name) {
   781  			urls = strings.Split(ctx.GlobalString(BootnodesV5Flag.Name), ",")
   782  		} else {
   783  			urls = strings.Split(ctx.GlobalString(BootnodesFlag.Name), ",")
   784  		}
   785  	case ctx.GlobalBool(RinkebyFlag.Name):
   786  		urls = params.RinkebyBootnodes
   787  	case ctx.GlobalBool(GoerliFlag.Name):
   788  		urls = params.GoerliBootnodes
   789  	case cfg.BootstrapNodesV5 != nil:
   790  		return // already set, don't apply defaults.
   791  	}
   792  
   793  	cfg.BootstrapNodesV5 = make([]*discv5.Node, 0, len(urls))
   794  	for _, url := range urls {
   795  		node, err := discv5.ParseNode(url)
   796  		if err != nil {
   797  			log.Error("Bootstrap URL invalid", "enode", url, "err", err)
   798  			continue
   799  		}
   800  		cfg.BootstrapNodesV5 = append(cfg.BootstrapNodesV5, node)
   801  	}
   802  }
   803  
   804  // setListenAddress creates a TCP listening address string from set command
   805  // line flags.
   806  func setListenAddress(ctx *cli.Context, cfg *p2p.Config) {
   807  	if ctx.GlobalIsSet(ListenPortFlag.Name) {
   808  		cfg.ListenAddr = fmt.Sprintf(":%d", ctx.GlobalInt(ListenPortFlag.Name))
   809  	}
   810  }
   811  
   812  // setNAT creates a port mapper from command line flags.
   813  func setNAT(ctx *cli.Context, cfg *p2p.Config) {
   814  	if ctx.GlobalIsSet(NATFlag.Name) {
   815  		natif, err := nat.Parse(ctx.GlobalString(NATFlag.Name))
   816  		if err != nil {
   817  			Fatalf("Option %s: %v", NATFlag.Name, err)
   818  		}
   819  		cfg.NAT = natif
   820  	}
   821  }
   822  
   823  // splitAndTrim splits input separated by a comma
   824  // and trims excessive white space from the substrings.
   825  func splitAndTrim(input string) []string {
   826  	result := strings.Split(input, ",")
   827  	for i, r := range result {
   828  		result[i] = strings.TrimSpace(r)
   829  	}
   830  	return result
   831  }
   832  
   833  // setHTTP creates the HTTP RPC listener interface string from the set
   834  // command line flags, returning empty if the HTTP endpoint is disabled.
   835  func setHTTP(ctx *cli.Context, cfg *node.Config) {
   836  	if ctx.GlobalBool(RPCEnabledFlag.Name) && cfg.HTTPHost == "" {
   837  		cfg.HTTPHost = "127.0.0.1"
   838  		if ctx.GlobalIsSet(RPCListenAddrFlag.Name) {
   839  			cfg.HTTPHost = ctx.GlobalString(RPCListenAddrFlag.Name)
   840  		}
   841  	}
   842  
   843  	if ctx.GlobalIsSet(RPCPortFlag.Name) {
   844  		cfg.HTTPPort = ctx.GlobalInt(RPCPortFlag.Name)
   845  	}
   846  	if ctx.GlobalIsSet(RPCCORSDomainFlag.Name) {
   847  		cfg.HTTPCors = splitAndTrim(ctx.GlobalString(RPCCORSDomainFlag.Name))
   848  	}
   849  	if ctx.GlobalIsSet(RPCApiFlag.Name) {
   850  		cfg.HTTPModules = splitAndTrim(ctx.GlobalString(RPCApiFlag.Name))
   851  	}
   852  	if ctx.GlobalIsSet(RPCVirtualHostsFlag.Name) {
   853  		cfg.HTTPVirtualHosts = splitAndTrim(ctx.GlobalString(RPCVirtualHostsFlag.Name))
   854  	}
   855  }
   856  
   857  // setGraphQL creates the GraphQL listener interface string from the set
   858  // command line flags, returning empty if the GraphQL endpoint is disabled.
   859  func setGraphQL(ctx *cli.Context, cfg *node.Config) {
   860  	if ctx.GlobalBool(GraphQLEnabledFlag.Name) && cfg.GraphQLHost == "" {
   861  		cfg.GraphQLHost = "127.0.0.1"
   862  		if ctx.GlobalIsSet(GraphQLListenAddrFlag.Name) {
   863  			cfg.GraphQLHost = ctx.GlobalString(GraphQLListenAddrFlag.Name)
   864  		}
   865  	}
   866  	cfg.GraphQLPort = ctx.GlobalInt(GraphQLPortFlag.Name)
   867  	if ctx.GlobalIsSet(GraphQLCORSDomainFlag.Name) {
   868  		cfg.GraphQLCors = splitAndTrim(ctx.GlobalString(GraphQLCORSDomainFlag.Name))
   869  	}
   870  	if ctx.GlobalIsSet(GraphQLVirtualHostsFlag.Name) {
   871  		cfg.GraphQLVirtualHosts = splitAndTrim(ctx.GlobalString(GraphQLVirtualHostsFlag.Name))
   872  	}
   873  }
   874  
   875  // setWS creates the WebSocket RPC listener interface string from the set
   876  // command line flags, returning empty if the HTTP endpoint is disabled.
   877  func setWS(ctx *cli.Context, cfg *node.Config) {
   878  	if ctx.GlobalBool(WSEnabledFlag.Name) && cfg.WSHost == "" {
   879  		cfg.WSHost = "127.0.0.1"
   880  		if ctx.GlobalIsSet(WSListenAddrFlag.Name) {
   881  			cfg.WSHost = ctx.GlobalString(WSListenAddrFlag.Name)
   882  		}
   883  	}
   884  
   885  	if ctx.GlobalIsSet(WSPortFlag.Name) {
   886  		cfg.WSPort = ctx.GlobalInt(WSPortFlag.Name)
   887  	}
   888  	if ctx.GlobalIsSet(WSAllowedOriginsFlag.Name) {
   889  		cfg.WSOrigins = splitAndTrim(ctx.GlobalString(WSAllowedOriginsFlag.Name))
   890  	}
   891  	if ctx.GlobalIsSet(WSApiFlag.Name) {
   892  		cfg.WSModules = splitAndTrim(ctx.GlobalString(WSApiFlag.Name))
   893  	}
   894  }
   895  
   896  // setIPC creates an IPC path configuration from the set command line flags,
   897  // returning an empty string if IPC was explicitly disabled, or the set path.
   898  func setIPC(ctx *cli.Context, cfg *node.Config) {
   899  	checkExclusive(ctx, IPCDisabledFlag, IPCPathFlag)
   900  	switch {
   901  	case ctx.GlobalBool(IPCDisabledFlag.Name):
   902  		cfg.IPCPath = ""
   903  	case ctx.GlobalIsSet(IPCPathFlag.Name):
   904  		cfg.IPCPath = ctx.GlobalString(IPCPathFlag.Name)
   905  	}
   906  }
   907  
   908  // SetULC setup ULC config from file if given.
   909  func SetULC(ctx *cli.Context, cfg *eth.Config) {
   910  	// ULC config isn't loaded from global config and ULC config and ULC trusted nodes are not defined.
   911  	if cfg.ULC == nil && !(ctx.GlobalIsSet(ULCModeConfigFlag.Name) || ctx.GlobalIsSet(ULCTrustedNodesFlag.Name)) {
   912  		return
   913  	}
   914  	cfg.ULC = &eth.ULCConfig{}
   915  
   916  	path := ctx.GlobalString(ULCModeConfigFlag.Name)
   917  	if path != "" {
   918  		cfgData, err := ioutil.ReadFile(path)
   919  		if err != nil {
   920  			Fatalf("Failed to unmarshal ULC configuration: %v", err)
   921  		}
   922  
   923  		err = json.Unmarshal(cfgData, &cfg.ULC)
   924  		if err != nil {
   925  			Fatalf("Failed to unmarshal ULC configuration: %s", err.Error())
   926  		}
   927  	}
   928  
   929  	if trustedNodes := ctx.GlobalString(ULCTrustedNodesFlag.Name); trustedNodes != "" {
   930  		cfg.ULC.TrustedServers = strings.Split(trustedNodes, ",")
   931  	}
   932  
   933  	if trustedFraction := ctx.GlobalInt(ULCMinTrustedFractionFlag.Name); trustedFraction > 0 {
   934  		cfg.ULC.MinTrustedFraction = trustedFraction
   935  	}
   936  	if cfg.ULC.MinTrustedFraction <= 0 && cfg.ULC.MinTrustedFraction > 100 {
   937  		log.Error("MinTrustedFraction is invalid", "MinTrustedFraction", cfg.ULC.MinTrustedFraction, "Changed to default", eth.DefaultULCMinTrustedFraction)
   938  		cfg.ULC.MinTrustedFraction = eth.DefaultULCMinTrustedFraction
   939  	}
   940  }
   941  
   942  // makeDatabaseHandles raises out the number of allowed file handles per process
   943  // for Geth and returns half of the allowance to assign to the database.
   944  func makeDatabaseHandles() int {
   945  	limit, err := fdlimit.Maximum()
   946  	if err != nil {
   947  		Fatalf("Failed to retrieve file descriptor allowance: %v", err)
   948  	}
   949  	if err := fdlimit.Raise(uint64(limit)); err != nil {
   950  		Fatalf("Failed to raise file descriptor allowance: %v", err)
   951  	}
   952  	return limit / 2 // Leave half for networking and other stuff
   953  }
   954  
   955  // MakeAddress converts an account specified directly as a hex encoded string or
   956  // a key index in the key store to an internal account representation.
   957  func MakeAddress(ks *keystore.KeyStore, account string) (accounts.Account, error) {
   958  	// If the specified account is a valid address, return it
   959  	if common.IsHexAddress(account) {
   960  		return accounts.Account{Address: common.HexToAddress(account)}, nil
   961  	}
   962  	// Otherwise try to interpret the account as a keystore index
   963  	index, err := strconv.Atoi(account)
   964  	if err != nil || index < 0 {
   965  		return accounts.Account{}, fmt.Errorf("invalid account address or index %q", account)
   966  	}
   967  	log.Warn("-------------------------------------------------------------------")
   968  	log.Warn("Referring to accounts by order in the keystore folder is dangerous!")
   969  	log.Warn("This functionality is deprecated and will be removed in the future!")
   970  	log.Warn("Please use explicit addresses! (can search via `geth account list`)")
   971  	log.Warn("-------------------------------------------------------------------")
   972  
   973  	accs := ks.Accounts()
   974  	if len(accs) <= index {
   975  		return accounts.Account{}, fmt.Errorf("index %d higher than number of accounts %d", index, len(accs))
   976  	}
   977  	return accs[index], nil
   978  }
   979  
   980  // setEtherbase retrieves the etherbase either from the directly specified
   981  // command line flags or from the keystore if CLI indexed.
   982  func setEtherbase(ctx *cli.Context, ks *keystore.KeyStore, cfg *eth.Config) {
   983  	// Extract the current etherbase, new flag overriding legacy one
   984  	var etherbase string
   985  	if ctx.GlobalIsSet(MinerLegacyEtherbaseFlag.Name) {
   986  		etherbase = ctx.GlobalString(MinerLegacyEtherbaseFlag.Name)
   987  	}
   988  	if ctx.GlobalIsSet(MinerEtherbaseFlag.Name) {
   989  		etherbase = ctx.GlobalString(MinerEtherbaseFlag.Name)
   990  	}
   991  	// Convert the etherbase into an address and configure it
   992  	if etherbase != "" {
   993  		account, err := MakeAddress(ks, etherbase)
   994  		if err != nil {
   995  			Fatalf("Invalid miner etherbase: %v", err)
   996  		}
   997  		cfg.Etherbase = account.Address
   998  	}
   999  }
  1000  
  1001  // MakePasswordList reads password lines from the file specified by the global --password flag.
  1002  func MakePasswordList(ctx *cli.Context) []string {
  1003  	path := ctx.GlobalString(PasswordFileFlag.Name)
  1004  	if path == "" {
  1005  		return nil
  1006  	}
  1007  	text, err := ioutil.ReadFile(path)
  1008  	if err != nil {
  1009  		Fatalf("Failed to read password file: %v", err)
  1010  	}
  1011  	lines := strings.Split(string(text), "\n")
  1012  	// Sanitise DOS line endings.
  1013  	for i := range lines {
  1014  		lines[i] = strings.TrimRight(lines[i], "\r")
  1015  	}
  1016  	return lines
  1017  }
  1018  
  1019  func SetP2PConfig(ctx *cli.Context, cfg *p2p.Config) {
  1020  	setNodeKey(ctx, cfg)
  1021  	setNAT(ctx, cfg)
  1022  	setListenAddress(ctx, cfg)
  1023  	setBootstrapNodes(ctx, cfg)
  1024  	setBootstrapNodesV5(ctx, cfg)
  1025  
  1026  	lightClient := ctx.GlobalString(SyncModeFlag.Name) == "light"
  1027  	lightServer := ctx.GlobalInt(LightServFlag.Name) != 0
  1028  	lightPeers := ctx.GlobalInt(LightPeersFlag.Name)
  1029  
  1030  	if ctx.GlobalIsSet(MaxPeersFlag.Name) {
  1031  		cfg.MaxPeers = ctx.GlobalInt(MaxPeersFlag.Name)
  1032  		if lightServer && !ctx.GlobalIsSet(LightPeersFlag.Name) {
  1033  			cfg.MaxPeers += lightPeers
  1034  		}
  1035  	} else {
  1036  		if lightServer {
  1037  			cfg.MaxPeers += lightPeers
  1038  		}
  1039  		if lightClient && ctx.GlobalIsSet(LightPeersFlag.Name) && cfg.MaxPeers < lightPeers {
  1040  			cfg.MaxPeers = lightPeers
  1041  		}
  1042  	}
  1043  	if !(lightClient || lightServer) {
  1044  		lightPeers = 0
  1045  	}
  1046  	ethPeers := cfg.MaxPeers - lightPeers
  1047  	if lightClient {
  1048  		ethPeers = 0
  1049  	}
  1050  	log.Info("Maximum peer count", "ETH", ethPeers, "LES", lightPeers, "total", cfg.MaxPeers)
  1051  
  1052  	if ctx.GlobalIsSet(MaxPendingPeersFlag.Name) {
  1053  		cfg.MaxPendingPeers = ctx.GlobalInt(MaxPendingPeersFlag.Name)
  1054  	}
  1055  	if ctx.GlobalIsSet(NoDiscoverFlag.Name) || lightClient {
  1056  		cfg.NoDiscovery = true
  1057  	}
  1058  
  1059  	// if we're running a light client or server, force enable the v5 peer discovery
  1060  	// unless it is explicitly disabled with --nodiscover note that explicitly specifying
  1061  	// --v5disc overrides --nodiscover, in which case the later only disables v4 discovery
  1062  	forceV5Discovery := (lightClient || lightServer) && !ctx.GlobalBool(NoDiscoverFlag.Name)
  1063  	if ctx.GlobalIsSet(DiscoveryV5Flag.Name) {
  1064  		cfg.DiscoveryV5 = ctx.GlobalBool(DiscoveryV5Flag.Name)
  1065  	} else if forceV5Discovery {
  1066  		cfg.DiscoveryV5 = true
  1067  	}
  1068  
  1069  	if netrestrict := ctx.GlobalString(NetrestrictFlag.Name); netrestrict != "" {
  1070  		list, err := netutil.ParseNetlist(netrestrict)
  1071  		if err != nil {
  1072  			Fatalf("Option %q: %v", NetrestrictFlag.Name, err)
  1073  		}
  1074  		cfg.NetRestrict = list
  1075  	}
  1076  
  1077  	if ctx.GlobalBool(DeveloperFlag.Name) {
  1078  		// --dev mode can't use p2p networking.
  1079  		cfg.MaxPeers = 0
  1080  		cfg.ListenAddr = ":0"
  1081  		cfg.NoDiscovery = true
  1082  		cfg.DiscoveryV5 = false
  1083  	}
  1084  }
  1085  
  1086  // SetNodeConfig applies node-related command line flags to the config.
  1087  func SetNodeConfig(ctx *cli.Context, cfg *node.Config) {
  1088  	SetP2PConfig(ctx, &cfg.P2P)
  1089  	setIPC(ctx, cfg)
  1090  	setHTTP(ctx, cfg)
  1091  	setGraphQL(ctx, cfg)
  1092  	setWS(ctx, cfg)
  1093  	setNodeUserIdent(ctx, cfg)
  1094  	setDataDir(ctx, cfg)
  1095  
  1096  	if ctx.GlobalIsSet(KeyStoreDirFlag.Name) {
  1097  		cfg.KeyStoreDir = ctx.GlobalString(KeyStoreDirFlag.Name)
  1098  	}
  1099  	if ctx.GlobalIsSet(LightKDFFlag.Name) {
  1100  		cfg.UseLightweightKDF = ctx.GlobalBool(LightKDFFlag.Name)
  1101  	}
  1102  	if ctx.GlobalIsSet(NoUSBFlag.Name) {
  1103  		cfg.NoUSB = ctx.GlobalBool(NoUSBFlag.Name)
  1104  	}
  1105  }
  1106  
  1107  func setDataDir(ctx *cli.Context, cfg *node.Config) {
  1108  	switch {
  1109  	case ctx.GlobalIsSet(DataDirFlag.Name):
  1110  		cfg.DataDir = ctx.GlobalString(DataDirFlag.Name)
  1111  	case ctx.GlobalBool(DeveloperFlag.Name):
  1112  		cfg.DataDir = "" // unless explicitly requested, use memory databases
  1113  	case ctx.GlobalBool(TestnetFlag.Name):
  1114  		cfg.DataDir = filepath.Join(node.DefaultDataDir(), "testnet")
  1115  	case ctx.GlobalBool(RinkebyFlag.Name):
  1116  		cfg.DataDir = filepath.Join(node.DefaultDataDir(), "rinkeby")
  1117  	case ctx.GlobalBool(GoerliFlag.Name):
  1118  		cfg.DataDir = filepath.Join(node.DefaultDataDir(), "goerli")
  1119  	}
  1120  }
  1121  
  1122  func setGPO(ctx *cli.Context, cfg *gasprice.Config) {
  1123  	if ctx.GlobalIsSet(GpoBlocksFlag.Name) {
  1124  		cfg.Blocks = ctx.GlobalInt(GpoBlocksFlag.Name)
  1125  	}
  1126  	if ctx.GlobalIsSet(GpoPercentileFlag.Name) {
  1127  		cfg.Percentile = ctx.GlobalInt(GpoPercentileFlag.Name)
  1128  	}
  1129  }
  1130  
  1131  func setTxPool(ctx *cli.Context, cfg *core.TxPoolConfig) {
  1132  	if ctx.GlobalIsSet(TxPoolLocalsFlag.Name) {
  1133  		locals := strings.Split(ctx.GlobalString(TxPoolLocalsFlag.Name), ",")
  1134  		for _, account := range locals {
  1135  			if trimmed := strings.TrimSpace(account); !common.IsHexAddress(trimmed) {
  1136  				Fatalf("Invalid account in --txpool.locals: %s", trimmed)
  1137  			} else {
  1138  				cfg.Locals = append(cfg.Locals, common.HexToAddress(account))
  1139  			}
  1140  		}
  1141  	}
  1142  	if ctx.GlobalIsSet(TxPoolNoLocalsFlag.Name) {
  1143  		cfg.NoLocals = ctx.GlobalBool(TxPoolNoLocalsFlag.Name)
  1144  	}
  1145  	if ctx.GlobalIsSet(TxPoolJournalFlag.Name) {
  1146  		cfg.Journal = ctx.GlobalString(TxPoolJournalFlag.Name)
  1147  	}
  1148  	if ctx.GlobalIsSet(TxPoolRejournalFlag.Name) {
  1149  		cfg.Rejournal = ctx.GlobalDuration(TxPoolRejournalFlag.Name)
  1150  	}
  1151  	if ctx.GlobalIsSet(TxPoolPriceLimitFlag.Name) {
  1152  		cfg.PriceLimit = ctx.GlobalUint64(TxPoolPriceLimitFlag.Name)
  1153  	}
  1154  	if ctx.GlobalIsSet(TxPoolPriceBumpFlag.Name) {
  1155  		cfg.PriceBump = ctx.GlobalUint64(TxPoolPriceBumpFlag.Name)
  1156  	}
  1157  	if ctx.GlobalIsSet(TxPoolAccountSlotsFlag.Name) {
  1158  		cfg.AccountSlots = ctx.GlobalUint64(TxPoolAccountSlotsFlag.Name)
  1159  	}
  1160  	if ctx.GlobalIsSet(TxPoolGlobalSlotsFlag.Name) {
  1161  		cfg.GlobalSlots = ctx.GlobalUint64(TxPoolGlobalSlotsFlag.Name)
  1162  	}
  1163  	if ctx.GlobalIsSet(TxPoolAccountQueueFlag.Name) {
  1164  		cfg.AccountQueue = ctx.GlobalUint64(TxPoolAccountQueueFlag.Name)
  1165  	}
  1166  	if ctx.GlobalIsSet(TxPoolGlobalQueueFlag.Name) {
  1167  		cfg.GlobalQueue = ctx.GlobalUint64(TxPoolGlobalQueueFlag.Name)
  1168  	}
  1169  	if ctx.GlobalIsSet(TxPoolLifetimeFlag.Name) {
  1170  		cfg.Lifetime = ctx.GlobalDuration(TxPoolLifetimeFlag.Name)
  1171  	}
  1172  }
  1173  
  1174  func setEthash(ctx *cli.Context, cfg *eth.Config) {
  1175  	if ctx.GlobalIsSet(EthashCacheDirFlag.Name) {
  1176  		cfg.Ethash.CacheDir = ctx.GlobalString(EthashCacheDirFlag.Name)
  1177  	}
  1178  	if ctx.GlobalIsSet(EthashDatasetDirFlag.Name) {
  1179  		cfg.Ethash.DatasetDir = ctx.GlobalString(EthashDatasetDirFlag.Name)
  1180  	}
  1181  	if ctx.GlobalIsSet(EthashCachesInMemoryFlag.Name) {
  1182  		cfg.Ethash.CachesInMem = ctx.GlobalInt(EthashCachesInMemoryFlag.Name)
  1183  	}
  1184  	if ctx.GlobalIsSet(EthashCachesOnDiskFlag.Name) {
  1185  		cfg.Ethash.CachesOnDisk = ctx.GlobalInt(EthashCachesOnDiskFlag.Name)
  1186  	}
  1187  	if ctx.GlobalIsSet(EthashDatasetsInMemoryFlag.Name) {
  1188  		cfg.Ethash.DatasetsInMem = ctx.GlobalInt(EthashDatasetsInMemoryFlag.Name)
  1189  	}
  1190  	if ctx.GlobalIsSet(EthashDatasetsOnDiskFlag.Name) {
  1191  		cfg.Ethash.DatasetsOnDisk = ctx.GlobalInt(EthashDatasetsOnDiskFlag.Name)
  1192  	}
  1193  }
  1194  
  1195  func setWhitelist(ctx *cli.Context, cfg *eth.Config) {
  1196  	whitelist := ctx.GlobalString(WhitelistFlag.Name)
  1197  	if whitelist == "" {
  1198  		return
  1199  	}
  1200  	cfg.Whitelist = make(map[uint64]common.Hash)
  1201  	for _, entry := range strings.Split(whitelist, ",") {
  1202  		parts := strings.Split(entry, "=")
  1203  		if len(parts) != 2 {
  1204  			Fatalf("Invalid whitelist entry: %s", entry)
  1205  		}
  1206  		number, err := strconv.ParseUint(parts[0], 0, 64)
  1207  		if err != nil {
  1208  			Fatalf("Invalid whitelist block number %s: %v", parts[0], err)
  1209  		}
  1210  		var hash common.Hash
  1211  		if err = hash.UnmarshalText([]byte(parts[1])); err != nil {
  1212  			Fatalf("Invalid whitelist hash %s: %v", parts[1], err)
  1213  		}
  1214  		cfg.Whitelist[number] = hash
  1215  	}
  1216  }
  1217  
  1218  // checkExclusive verifies that only a single instance of the provided flags was
  1219  // set by the user. Each flag might optionally be followed by a string type to
  1220  // specialize it further.
  1221  func checkExclusive(ctx *cli.Context, args ...interface{}) {
  1222  	set := make([]string, 0, 1)
  1223  	for i := 0; i < len(args); i++ {
  1224  		// Make sure the next argument is a flag and skip if not set
  1225  		flag, ok := args[i].(cli.Flag)
  1226  		if !ok {
  1227  			panic(fmt.Sprintf("invalid argument, not cli.Flag type: %T", args[i]))
  1228  		}
  1229  		// Check if next arg extends current and expand its name if so
  1230  		name := flag.GetName()
  1231  
  1232  		if i+1 < len(args) {
  1233  			switch option := args[i+1].(type) {
  1234  			case string:
  1235  				// Extended flag check, make sure value set doesn't conflict with passed in option
  1236  				if ctx.GlobalString(flag.GetName()) == option {
  1237  					name += "=" + option
  1238  					set = append(set, "--"+name)
  1239  				}
  1240  				// shift arguments and continue
  1241  				i++
  1242  				continue
  1243  
  1244  			case cli.Flag:
  1245  			default:
  1246  				panic(fmt.Sprintf("invalid argument, not cli.Flag or string extension: %T", args[i+1]))
  1247  			}
  1248  		}
  1249  		// Mark the flag if it's set
  1250  		if ctx.GlobalIsSet(flag.GetName()) {
  1251  			set = append(set, "--"+name)
  1252  		}
  1253  	}
  1254  	if len(set) > 1 {
  1255  		Fatalf("Flags %v can't be used at the same time", strings.Join(set, ", "))
  1256  	}
  1257  }
  1258  
  1259  // SetShhConfig applies shh-related command line flags to the config.
  1260  func SetShhConfig(ctx *cli.Context, stack *node.Node, cfg *whisper.Config) {
  1261  	if ctx.GlobalIsSet(WhisperMaxMessageSizeFlag.Name) {
  1262  		cfg.MaxMessageSize = uint32(ctx.GlobalUint(WhisperMaxMessageSizeFlag.Name))
  1263  	}
  1264  	if ctx.GlobalIsSet(WhisperMinPOWFlag.Name) {
  1265  		cfg.MinimumAcceptedPOW = ctx.GlobalFloat64(WhisperMinPOWFlag.Name)
  1266  	}
  1267  	if ctx.GlobalIsSet(WhisperRestrictConnectionBetweenLightClientsFlag.Name) {
  1268  		cfg.RestrictConnectionBetweenLightClients = true
  1269  	}
  1270  }
  1271  
  1272  // SetEthConfig applies eth-related command line flags to the config.
  1273  func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *eth.Config) {
  1274  	// Avoid conflicting network flags
  1275  	checkExclusive(ctx, DeveloperFlag, TestnetFlag, RinkebyFlag, GoerliFlag)
  1276  	checkExclusive(ctx, LightServFlag, SyncModeFlag, "light")
  1277  
  1278  	ks := stack.AccountManager().Backends(keystore.KeyStoreType)[0].(*keystore.KeyStore)
  1279  	setEtherbase(ctx, ks, cfg)
  1280  	setGPO(ctx, &cfg.GPO)
  1281  	setTxPool(ctx, &cfg.TxPool)
  1282  	setEthash(ctx, cfg)
  1283  	setWhitelist(ctx, cfg)
  1284  
  1285  	if ctx.GlobalIsSet(SyncModeFlag.Name) {
  1286  		cfg.SyncMode = *GlobalTextMarshaler(ctx, SyncModeFlag.Name).(*downloader.SyncMode)
  1287  	}
  1288  	if ctx.GlobalIsSet(LightServFlag.Name) {
  1289  		cfg.LightServ = ctx.GlobalInt(LightServFlag.Name)
  1290  	}
  1291  	if ctx.GlobalIsSet(LightPeersFlag.Name) {
  1292  		cfg.LightPeers = ctx.GlobalInt(LightPeersFlag.Name)
  1293  	}
  1294  	if ctx.GlobalIsSet(OnlyAnnounceModeFlag.Name) {
  1295  		cfg.OnlyAnnounce = ctx.GlobalBool(OnlyAnnounceModeFlag.Name)
  1296  	}
  1297  	if ctx.GlobalIsSet(NetworkIdFlag.Name) {
  1298  		cfg.NetworkId = ctx.GlobalUint64(NetworkIdFlag.Name)
  1299  	}
  1300  	if ctx.GlobalIsSet(CacheFlag.Name) || ctx.GlobalIsSet(CacheDatabaseFlag.Name) {
  1301  		cfg.DatabaseCache = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheDatabaseFlag.Name) / 100
  1302  	}
  1303  	cfg.DatabaseHandles = makeDatabaseHandles()
  1304  
  1305  	if gcmode := ctx.GlobalString(GCModeFlag.Name); gcmode != "full" && gcmode != "archive" {
  1306  		Fatalf("--%s must be either 'full' or 'archive'", GCModeFlag.Name)
  1307  	}
  1308  	cfg.NoPruning = ctx.GlobalString(GCModeFlag.Name) == "archive"
  1309  
  1310  	if ctx.GlobalIsSet(CacheFlag.Name) || ctx.GlobalIsSet(CacheTrieFlag.Name) {
  1311  		cfg.TrieCleanCache = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheTrieFlag.Name) / 100
  1312  	}
  1313  	if ctx.GlobalIsSet(CacheFlag.Name) || ctx.GlobalIsSet(CacheGCFlag.Name) {
  1314  		cfg.TrieDirtyCache = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheGCFlag.Name) / 100
  1315  	}
  1316  	if ctx.GlobalIsSet(MinerNotifyFlag.Name) {
  1317  		cfg.MinerNotify = strings.Split(ctx.GlobalString(MinerNotifyFlag.Name), ",")
  1318  	}
  1319  	if ctx.GlobalIsSet(DocRootFlag.Name) {
  1320  		cfg.DocRoot = ctx.GlobalString(DocRootFlag.Name)
  1321  	}
  1322  	if ctx.GlobalIsSet(MinerLegacyExtraDataFlag.Name) {
  1323  		cfg.MinerExtraData = []byte(ctx.GlobalString(MinerLegacyExtraDataFlag.Name))
  1324  	}
  1325  	if ctx.GlobalIsSet(MinerExtraDataFlag.Name) {
  1326  		cfg.MinerExtraData = []byte(ctx.GlobalString(MinerExtraDataFlag.Name))
  1327  	}
  1328  	if ctx.GlobalIsSet(MinerLegacyGasTargetFlag.Name) {
  1329  		cfg.MinerGasFloor = ctx.GlobalUint64(MinerLegacyGasTargetFlag.Name)
  1330  	}
  1331  	if ctx.GlobalIsSet(MinerGasTargetFlag.Name) {
  1332  		cfg.MinerGasFloor = ctx.GlobalUint64(MinerGasTargetFlag.Name)
  1333  	}
  1334  	if ctx.GlobalIsSet(MinerGasLimitFlag.Name) {
  1335  		cfg.MinerGasCeil = ctx.GlobalUint64(MinerGasLimitFlag.Name)
  1336  	}
  1337  	if ctx.GlobalIsSet(MinerLegacyGasPriceFlag.Name) {
  1338  		cfg.MinerGasPrice = GlobalBig(ctx, MinerLegacyGasPriceFlag.Name)
  1339  	}
  1340  	if ctx.GlobalIsSet(MinerGasPriceFlag.Name) {
  1341  		cfg.MinerGasPrice = GlobalBig(ctx, MinerGasPriceFlag.Name)
  1342  	}
  1343  	if ctx.GlobalIsSet(MinerRecommitIntervalFlag.Name) {
  1344  		cfg.MinerRecommit = ctx.Duration(MinerRecommitIntervalFlag.Name)
  1345  	}
  1346  	if ctx.GlobalIsSet(MinerNoVerfiyFlag.Name) {
  1347  		cfg.MinerNoverify = ctx.Bool(MinerNoVerfiyFlag.Name)
  1348  	}
  1349  	if ctx.GlobalIsSet(VMEnableDebugFlag.Name) {
  1350  		// TODO(fjl): force-enable this in --dev mode
  1351  		cfg.EnablePreimageRecording = ctx.GlobalBool(VMEnableDebugFlag.Name)
  1352  	}
  1353  
  1354  	if ctx.GlobalIsSet(EWASMInterpreterFlag.Name) {
  1355  		cfg.EWASMInterpreter = ctx.GlobalString(EWASMInterpreterFlag.Name)
  1356  	}
  1357  
  1358  	if ctx.GlobalIsSet(EVMInterpreterFlag.Name) {
  1359  		cfg.EVMInterpreter = ctx.GlobalString(EVMInterpreterFlag.Name)
  1360  	}
  1361  
  1362  	// Override any default configs for hard coded networks.
  1363  	switch {
  1364  	case ctx.GlobalBool(TestnetFlag.Name):
  1365  		if !ctx.GlobalIsSet(NetworkIdFlag.Name) {
  1366  			cfg.NetworkId = 3
  1367  		}
  1368  		cfg.Genesis = core.DefaultTestnetGenesisBlock()
  1369  	case ctx.GlobalBool(RinkebyFlag.Name):
  1370  		if !ctx.GlobalIsSet(NetworkIdFlag.Name) {
  1371  			cfg.NetworkId = 4
  1372  		}
  1373  		cfg.Genesis = core.DefaultRinkebyGenesisBlock()
  1374  	case ctx.GlobalBool(GoerliFlag.Name):
  1375  		if !ctx.GlobalIsSet(NetworkIdFlag.Name) {
  1376  			cfg.NetworkId = 5
  1377  		}
  1378  		cfg.Genesis = core.DefaultGoerliGenesisBlock()
  1379  	case ctx.GlobalBool(DeveloperFlag.Name):
  1380  		if !ctx.GlobalIsSet(NetworkIdFlag.Name) {
  1381  			cfg.NetworkId = 1337
  1382  		}
  1383  		// Create new developer account or reuse existing one
  1384  		var (
  1385  			developer accounts.Account
  1386  			err       error
  1387  		)
  1388  		if accs := ks.Accounts(); len(accs) > 0 {
  1389  			developer = ks.Accounts()[0]
  1390  		} else {
  1391  			developer, err = ks.NewAccount("")
  1392  			if err != nil {
  1393  				Fatalf("Failed to create developer account: %v", err)
  1394  			}
  1395  		}
  1396  		if err := ks.Unlock(developer, ""); err != nil {
  1397  			Fatalf("Failed to unlock developer account: %v", err)
  1398  		}
  1399  		log.Info("Using developer account", "address", developer.Address)
  1400  
  1401  		cfg.Genesis = core.DeveloperGenesisBlock(uint64(ctx.GlobalInt(DeveloperPeriodFlag.Name)), developer.Address)
  1402  		if !ctx.GlobalIsSet(MinerGasPriceFlag.Name) && !ctx.GlobalIsSet(MinerLegacyGasPriceFlag.Name) {
  1403  			cfg.MinerGasPrice = big.NewInt(1)
  1404  		}
  1405  	}
  1406  	// TODO(fjl): move trie cache generations into config
  1407  	if gen := ctx.GlobalInt(TrieCacheGenFlag.Name); gen > 0 {
  1408  		state.MaxTrieCacheGen = uint16(gen)
  1409  	}
  1410  }
  1411  
  1412  // SetDashboardConfig applies dashboard related command line flags to the config.
  1413  func SetDashboardConfig(ctx *cli.Context, cfg *dashboard.Config) {
  1414  	cfg.Host = ctx.GlobalString(DashboardAddrFlag.Name)
  1415  	cfg.Port = ctx.GlobalInt(DashboardPortFlag.Name)
  1416  	cfg.Refresh = ctx.GlobalDuration(DashboardRefreshFlag.Name)
  1417  }
  1418  
  1419  // RegisterEthService adds an Ethereum client to the stack.
  1420  func RegisterEthService(stack *node.Node, cfg *eth.Config) {
  1421  	var err error
  1422  	if cfg.SyncMode == downloader.LightSync {
  1423  		err = stack.Register(func(ctx *node.ServiceContext) (node.Service, error) {
  1424  			return les.New(ctx, cfg)
  1425  		})
  1426  	} else {
  1427  		err = stack.Register(func(ctx *node.ServiceContext) (node.Service, error) {
  1428  			fullNode, err := eth.New(ctx, cfg)
  1429  			if fullNode != nil && cfg.LightServ > 0 {
  1430  				ls, _ := les.NewLesServer(fullNode, cfg)
  1431  				fullNode.AddLesServer(ls)
  1432  			}
  1433  			return fullNode, err
  1434  		})
  1435  	}
  1436  	if err != nil {
  1437  		Fatalf("Failed to register the Ethereum service: %v", err)
  1438  	}
  1439  }
  1440  
  1441  // RegisterDashboardService adds a dashboard to the stack.
  1442  func RegisterDashboardService(stack *node.Node, cfg *dashboard.Config, commit string) {
  1443  	stack.Register(func(ctx *node.ServiceContext) (node.Service, error) {
  1444  		return dashboard.New(cfg, commit, ctx.ResolvePath("logs")), nil
  1445  	})
  1446  }
  1447  
  1448  // RegisterShhService configures Whisper and adds it to the given node.
  1449  func RegisterShhService(stack *node.Node, cfg *whisper.Config) {
  1450  	if err := stack.Register(func(n *node.ServiceContext) (node.Service, error) {
  1451  		return whisper.New(cfg), nil
  1452  	}); err != nil {
  1453  		Fatalf("Failed to register the Whisper service: %v", err)
  1454  	}
  1455  }
  1456  
  1457  // RegisterEthStatsService configures the Ethereum Stats daemon and adds it to
  1458  // the given node.
  1459  func RegisterEthStatsService(stack *node.Node, url string) {
  1460  	if err := stack.Register(func(ctx *node.ServiceContext) (node.Service, error) {
  1461  		// Retrieve both eth and les services
  1462  		var ethServ *eth.Ethereum
  1463  		ctx.Service(&ethServ)
  1464  
  1465  		var lesServ *les.LightEthereum
  1466  		ctx.Service(&lesServ)
  1467  
  1468  		return ethstats.New(url, ethServ, lesServ)
  1469  	}); err != nil {
  1470  		Fatalf("Failed to register the Ethereum Stats service: %v", err)
  1471  	}
  1472  }
  1473  
  1474  func SetupMetrics(ctx *cli.Context) {
  1475  	if metrics.Enabled {
  1476  		log.Info("Enabling metrics collection")
  1477  		var (
  1478  			enableExport = ctx.GlobalBool(MetricsEnableInfluxDBFlag.Name)
  1479  			endpoint     = ctx.GlobalString(MetricsInfluxDBEndpointFlag.Name)
  1480  			database     = ctx.GlobalString(MetricsInfluxDBDatabaseFlag.Name)
  1481  			username     = ctx.GlobalString(MetricsInfluxDBUsernameFlag.Name)
  1482  			password     = ctx.GlobalString(MetricsInfluxDBPasswordFlag.Name)
  1483  		)
  1484  
  1485  		if enableExport {
  1486  			tagsMap := SplitTagsFlag(ctx.GlobalString(MetricsInfluxDBTagsFlag.Name))
  1487  
  1488  			log.Info("Enabling metrics export to InfluxDB")
  1489  
  1490  			go influxdb.InfluxDBWithTags(metrics.DefaultRegistry, 10*time.Second, endpoint, database, username, password, "geth.", tagsMap)
  1491  		}
  1492  	}
  1493  }
  1494  
  1495  func SplitTagsFlag(tagsFlag string) map[string]string {
  1496  	tags := strings.Split(tagsFlag, ",")
  1497  	tagsMap := map[string]string{}
  1498  
  1499  	for _, t := range tags {
  1500  		if t != "" {
  1501  			kv := strings.Split(t, "=")
  1502  
  1503  			if len(kv) == 2 {
  1504  				tagsMap[kv[0]] = kv[1]
  1505  			}
  1506  		}
  1507  	}
  1508  
  1509  	return tagsMap
  1510  }
  1511  
  1512  // MakeChainDatabase open an LevelDB using the flags passed to the client and will hard crash if it fails.
  1513  func MakeChainDatabase(ctx *cli.Context, stack *node.Node) ethdb.Database {
  1514  	var (
  1515  		cache   = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheDatabaseFlag.Name) / 100
  1516  		handles = makeDatabaseHandles()
  1517  	)
  1518  	name := "chaindata"
  1519  	if ctx.GlobalString(SyncModeFlag.Name) == "light" {
  1520  		name = "lightchaindata"
  1521  	}
  1522  	chainDb, err := stack.OpenDatabase(name, cache, handles)
  1523  	if err != nil {
  1524  		Fatalf("Could not open database: %v", err)
  1525  	}
  1526  	return chainDb
  1527  }
  1528  
  1529  func MakeGenesis(ctx *cli.Context) *core.Genesis {
  1530  	var genesis *core.Genesis
  1531  	switch {
  1532  	case ctx.GlobalBool(TestnetFlag.Name):
  1533  		genesis = core.DefaultTestnetGenesisBlock()
  1534  	case ctx.GlobalBool(RinkebyFlag.Name):
  1535  		genesis = core.DefaultRinkebyGenesisBlock()
  1536  	case ctx.GlobalBool(GoerliFlag.Name):
  1537  		genesis = core.DefaultGoerliGenesisBlock()
  1538  	case ctx.GlobalBool(DeveloperFlag.Name):
  1539  		Fatalf("Developer chains are ephemeral")
  1540  	}
  1541  	return genesis
  1542  }
  1543  
  1544  // MakeChain creates a chain manager from set command line flags.
  1545  func MakeChain(ctx *cli.Context, stack *node.Node) (chain *core.BlockChain, chainDb ethdb.Database) {
  1546  	var err error
  1547  	chainDb = MakeChainDatabase(ctx, stack)
  1548  	config, _, err := core.SetupGenesisBlock(chainDb, MakeGenesis(ctx))
  1549  	if err != nil {
  1550  		Fatalf("%v", err)
  1551  	}
  1552  	var engine consensus.Engine
  1553  	if config.Clique != nil {
  1554  		engine = clique.New(config.Clique, chainDb)
  1555  	} else {
  1556  		engine = ethash.NewFaker()
  1557  		if !ctx.GlobalBool(FakePoWFlag.Name) {
  1558  			engine = ethash.New(ethash.Config{
  1559  				CacheDir:       stack.ResolvePath(eth.DefaultConfig.Ethash.CacheDir),
  1560  				CachesInMem:    eth.DefaultConfig.Ethash.CachesInMem,
  1561  				CachesOnDisk:   eth.DefaultConfig.Ethash.CachesOnDisk,
  1562  				DatasetDir:     stack.ResolvePath(eth.DefaultConfig.Ethash.DatasetDir),
  1563  				DatasetsInMem:  eth.DefaultConfig.Ethash.DatasetsInMem,
  1564  				DatasetsOnDisk: eth.DefaultConfig.Ethash.DatasetsOnDisk,
  1565  			}, nil, false)
  1566  		}
  1567  	}
  1568  	if gcmode := ctx.GlobalString(GCModeFlag.Name); gcmode != "full" && gcmode != "archive" {
  1569  		Fatalf("--%s must be either 'full' or 'archive'", GCModeFlag.Name)
  1570  	}
  1571  	cache := &core.CacheConfig{
  1572  		Disabled:       ctx.GlobalString(GCModeFlag.Name) == "archive",
  1573  		TrieCleanLimit: eth.DefaultConfig.TrieCleanCache,
  1574  		TrieDirtyLimit: eth.DefaultConfig.TrieDirtyCache,
  1575  		TrieTimeLimit:  eth.DefaultConfig.TrieTimeout,
  1576  	}
  1577  	if ctx.GlobalIsSet(CacheFlag.Name) || ctx.GlobalIsSet(CacheTrieFlag.Name) {
  1578  		cache.TrieCleanLimit = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheTrieFlag.Name) / 100
  1579  	}
  1580  	if ctx.GlobalIsSet(CacheFlag.Name) || ctx.GlobalIsSet(CacheGCFlag.Name) {
  1581  		cache.TrieDirtyLimit = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheGCFlag.Name) / 100
  1582  	}
  1583  	vmcfg := vm.Config{EnablePreimageRecording: ctx.GlobalBool(VMEnableDebugFlag.Name)}
  1584  	chain, err = core.NewBlockChain(chainDb, cache, config, engine, vmcfg, nil)
  1585  	if err != nil {
  1586  		Fatalf("Can't create BlockChain: %v", err)
  1587  	}
  1588  	return chain, chainDb
  1589  }
  1590  
  1591  // MakeConsolePreloads retrieves the absolute paths for the console JavaScript
  1592  // scripts to preload before starting.
  1593  func MakeConsolePreloads(ctx *cli.Context) []string {
  1594  	// Skip preloading if there's nothing to preload
  1595  	if ctx.GlobalString(PreloadJSFlag.Name) == "" {
  1596  		return nil
  1597  	}
  1598  	// Otherwise resolve absolute paths and return them
  1599  	preloads := []string{}
  1600  
  1601  	assets := ctx.GlobalString(JSpathFlag.Name)
  1602  	for _, file := range strings.Split(ctx.GlobalString(PreloadJSFlag.Name), ",") {
  1603  		preloads = append(preloads, common.AbsolutePath(assets, strings.TrimSpace(file)))
  1604  	}
  1605  	return preloads
  1606  }
  1607  
  1608  // MigrateFlags sets the global flag from a local flag when it's set.
  1609  // This is a temporary function used for migrating old command/flags to the
  1610  // new format.
  1611  //
  1612  // e.g. geth account new --keystore /tmp/mykeystore --lightkdf
  1613  //
  1614  // is equivalent after calling this method with:
  1615  //
  1616  // geth --keystore /tmp/mykeystore --lightkdf account new
  1617  //
  1618  // This allows the use of the existing configuration functionality.
  1619  // When all flags are migrated this function can be removed and the existing
  1620  // configuration functionality must be changed that is uses local flags
  1621  func MigrateFlags(action func(ctx *cli.Context) error) func(*cli.Context) error {
  1622  	return func(ctx *cli.Context) error {
  1623  		for _, name := range ctx.FlagNames() {
  1624  			if ctx.IsSet(name) {
  1625  				ctx.GlobalSet(name, ctx.String(name))
  1626  			}
  1627  		}
  1628  		return action(ctx)
  1629  	}
  1630  }