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