github.com/ebceco/ebc@v1.8.19-0.20190309150932-8cb0b9e06484/cmd/utils/flags.go (about)

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