github.com/aquanetwork/aquachain@v1.7.8/cmd/utils/flags.go (about)

     1  // Copyright 2015 The aquachain Authors
     2  // This file is part of aquachain.
     3  //
     4  // aquachain 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  // aquachain 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 aquachain. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  // Package utils contains internal helper functions for aquachain commands.
    18  package utils
    19  
    20  import (
    21  	"crypto/ecdsa"
    22  	"fmt"
    23  	"io/ioutil"
    24  	"math/big"
    25  	"os"
    26  	"path/filepath"
    27  	"runtime"
    28  	"strconv"
    29  	"strings"
    30  
    31  	"gitlab.com/aquachain/aquachain/aqua"
    32  	"gitlab.com/aquachain/aquachain/aqua/accounts"
    33  	"gitlab.com/aquachain/aquachain/aqua/accounts/keystore"
    34  	"gitlab.com/aquachain/aquachain/aqua/downloader"
    35  	"gitlab.com/aquachain/aquachain/aqua/gasprice"
    36  	"gitlab.com/aquachain/aquachain/aquadb"
    37  	"gitlab.com/aquachain/aquachain/common"
    38  	"gitlab.com/aquachain/aquachain/common/fdlimit"
    39  	"gitlab.com/aquachain/aquachain/common/log"
    40  	"gitlab.com/aquachain/aquachain/common/metrics"
    41  	"gitlab.com/aquachain/aquachain/consensus"
    42  	"gitlab.com/aquachain/aquachain/consensus/aquahash"
    43  	"gitlab.com/aquachain/aquachain/core"
    44  	"gitlab.com/aquachain/aquachain/core/state"
    45  	"gitlab.com/aquachain/aquachain/core/vm"
    46  	"gitlab.com/aquachain/aquachain/crypto"
    47  	"gitlab.com/aquachain/aquachain/node"
    48  	"gitlab.com/aquachain/aquachain/opt/aquastats"
    49  	whisper "gitlab.com/aquachain/aquachain/opt/whisper/whisperv6"
    50  	"gitlab.com/aquachain/aquachain/p2p"
    51  	"gitlab.com/aquachain/aquachain/p2p/discover"
    52  	"gitlab.com/aquachain/aquachain/p2p/discv5"
    53  	"gitlab.com/aquachain/aquachain/p2p/nat"
    54  	"gitlab.com/aquachain/aquachain/p2p/netutil"
    55  	"gitlab.com/aquachain/aquachain/params"
    56  	"gopkg.in/urfave/cli.v1"
    57  )
    58  
    59  var (
    60  	CommandHelpTemplate = `{{.cmd.Name}}{{if .cmd.Subcommands}} command{{end}}{{if .cmd.Flags}} [command options]{{end}} [arguments...]
    61  {{if .cmd.Description}}{{.cmd.Description}}
    62  {{end}}{{if .cmd.Subcommands}}
    63  SUBCOMMANDS:
    64  	{{range .cmd.Subcommands}}{{.cmd.Name}}{{with .cmd.ShortName}}, {{.cmd}}{{end}}{{ "\t" }}{{.cmd.Usage}}
    65  	{{end}}{{end}}{{if .categorizedFlags}}
    66  {{range $idx, $categorized := .categorizedFlags}}{{$categorized.Name}} OPTIONS:
    67  {{range $categorized.Flags}}{{"\t"}}{{.}}
    68  {{end}}
    69  {{end}}{{end}}`
    70  )
    71  
    72  func init() {
    73  	cli.AppHelpTemplate = `{{.Name}} {{if .Flags}}[global options] {{end}}command{{if .Flags}} [command options]{{end}} [arguments...]
    74  
    75  VERSION:
    76     {{.Version}}
    77  
    78  COMMANDS:
    79     {{range .Commands}}{{.Name}}{{with .ShortName}}, {{.}}{{end}}{{ "\t" }}{{.Usage}}
    80     {{end}}{{if .Flags}}
    81  GLOBAL OPTIONS:
    82     {{range .Flags}}{{.}}
    83     {{end}}{{end}}
    84  `
    85  
    86  	cli.CommandHelpTemplate = CommandHelpTemplate
    87  }
    88  
    89  // NewApp creates an app with sane defaults.
    90  func NewApp(gitCommit, usage string) *cli.App {
    91  	app := cli.NewApp()
    92  	app.Name = filepath.Base(os.Args[0])
    93  	app.Author = ""
    94  	//app.Authors = nil
    95  	app.Email = ""
    96  	app.Version = params.Version
    97  	if len(gitCommit) >= 8 {
    98  		app.Version += "-" + gitCommit[:8]
    99  	}
   100  	app.Usage = usage
   101  	return app
   102  }
   103  
   104  // These are all the command line flags we support.
   105  // If you add to this list, please remember to include the
   106  // flag in the appropriate command definition.
   107  //
   108  // The flags are defined here so their names and help texts
   109  // are the same for all commands.
   110  
   111  var (
   112  	// General settings
   113  	JsonFlag = cli.BoolFlag{
   114  		Name:  "json",
   115  		Usage: "Print paper keypair as json",
   116  	}
   117  	VanityFlag = cli.StringFlag{
   118  		Name:  "vanity",
   119  		Usage: "Prefix for generating a vanity address",
   120  	}
   121  	// General settings
   122  	DataDirFlag = DirectoryFlag{
   123  		Name:  "datadir",
   124  		Usage: "Data directory for the databases and keystore",
   125  		Value: DirectoryString{node.DefaultDataDir()},
   126  	}
   127  	KeyStoreDirFlag = DirectoryFlag{
   128  		Name:  "keystore",
   129  		Usage: "Directory for the keystore (default = inside the datadir)",
   130  	}
   131  	UseUSBFlag = cli.BoolFlag{
   132  		Name:  "usb",
   133  		Usage: "Enables monitoring for and managing USB hardware wallets",
   134  	}
   135  	NetworkIdFlag = cli.Uint64Flag{
   136  		Name:  "networkid",
   137  		Usage: "Network identifier (integer, 1=Frontier, 2=Morden (disused), 3=Ropsten, 4=Testnet2)",
   138  		Value: aqua.DefaultConfig.NetworkId,
   139  	}
   140  	TestnetFlag = cli.BoolFlag{
   141  		Name:  "testnet",
   142  		Usage: "Testnet: pre-configured proof-of-work test network",
   143  	}
   144  	Testnet2Flag = cli.BoolFlag{
   145  		Name:  "testnet2",
   146  		Usage: "Testnet2: pre-configured proof-of-authority test network",
   147  	}
   148  	DeveloperFlag = cli.BoolFlag{
   149  		Name:  "dev",
   150  		Usage: "Ephemeral proof-of-authority network with a pre-funded developer account, mining enabled",
   151  	}
   152  	DeveloperPeriodFlag = cli.IntFlag{
   153  		Name:  "dev.period",
   154  		Usage: "Block period to use in developer mode (0 = mine only if transaction pending)",
   155  	}
   156  	IdentityFlag = cli.StringFlag{
   157  		Name:  "identity",
   158  		Usage: "Custom node name",
   159  	}
   160  	DocRootFlag = DirectoryFlag{
   161  		Name:  "docroot",
   162  		Usage: "Document Root for HTTPClient file scheme",
   163  		Value: DirectoryString{homeDir()},
   164  	}
   165  	FastSyncFlag = cli.BoolFlag{
   166  		Name:  "fast",
   167  		Usage: "Enable fast syncing through state downloads",
   168  	}
   169  	defaultSyncMode = aqua.DefaultConfig.SyncMode
   170  	SyncModeFlag    = TextMarshalerFlag{
   171  		Name:  "syncmode",
   172  		Usage: `Blockchain sync mode ("fast", "full")`,
   173  		Value: &defaultSyncMode,
   174  	}
   175  	GCModeFlag = cli.StringFlag{
   176  		Name:  "gcmode",
   177  		Usage: `Blockchain garbage collection mode ("full", "archive") *SYNC WITH '-gcmode archive' FOR COMPLETE CIRCULATING SUPPLY*`,
   178  		Value: "full",
   179  	}
   180  	// Aquahash settings
   181  	AquahashCacheDirFlag = DirectoryFlag{
   182  		Name:  "aquahash.cachedir",
   183  		Usage: "Directory to store the aquahash verification caches (default = inside the datadir)",
   184  	}
   185  	AquahashCachesInMemoryFlag = cli.IntFlag{
   186  		Name:  "aquahash.cachesinmem",
   187  		Usage: "Number of recent aquahash caches to keep in memory (16MB each)",
   188  		Value: aqua.DefaultConfig.Aquahash.CachesInMem,
   189  	}
   190  	AquahashCachesOnDiskFlag = cli.IntFlag{
   191  		Name:  "aquahash.cachesondisk",
   192  		Usage: "Number of recent aquahash caches to keep on disk (16MB each)",
   193  		Value: aqua.DefaultConfig.Aquahash.CachesOnDisk,
   194  	}
   195  	AquahashDatasetDirFlag = DirectoryFlag{
   196  		Name:  "aquahash.dagdir",
   197  		Usage: "Directory to store the aquahash mining DAGs (default = inside home folder)",
   198  		Value: DirectoryString{aqua.DefaultConfig.Aquahash.DatasetDir},
   199  	}
   200  	AquahashDatasetsInMemoryFlag = cli.IntFlag{
   201  		Name:  "aquahash.dagsinmem",
   202  		Usage: "Number of recent aquahash mining DAGs to keep in memory (1+GB each)",
   203  		Value: aqua.DefaultConfig.Aquahash.DatasetsInMem,
   204  	}
   205  	AquahashDatasetsOnDiskFlag = cli.IntFlag{
   206  		Name:  "aquahash.dagsondisk",
   207  		Usage: "Number of recent aquahash mining DAGs to keep on disk (1+GB each)",
   208  		Value: aqua.DefaultConfig.Aquahash.DatasetsOnDisk,
   209  	}
   210  	// Transaction pool settings
   211  	TxPoolNoLocalsFlag = cli.BoolFlag{
   212  		Name:  "txpool.nolocals",
   213  		Usage: "Disables price exemptions for locally submitted transactions",
   214  	}
   215  	TxPoolJournalFlag = cli.StringFlag{
   216  		Name:  "txpool.journal",
   217  		Usage: "Disk journal for local transaction to survive node restarts",
   218  		Value: core.DefaultTxPoolConfig.Journal,
   219  	}
   220  	TxPoolRejournalFlag = cli.DurationFlag{
   221  		Name:  "txpool.rejournal",
   222  		Usage: "Time interval to regenerate the local transaction journal",
   223  		Value: core.DefaultTxPoolConfig.Rejournal,
   224  	}
   225  	TxPoolPriceLimitFlag = cli.Uint64Flag{
   226  		Name:  "txpool.pricelimit",
   227  		Usage: "Minimum gas price limit to enforce for acceptance into the pool",
   228  		Value: aqua.DefaultConfig.TxPool.PriceLimit,
   229  	}
   230  	TxPoolPriceBumpFlag = cli.Uint64Flag{
   231  		Name:  "txpool.pricebump",
   232  		Usage: "Price bump percentage to replace an already existing transaction",
   233  		Value: aqua.DefaultConfig.TxPool.PriceBump,
   234  	}
   235  	TxPoolAccountSlotsFlag = cli.Uint64Flag{
   236  		Name:  "txpool.accountslots",
   237  		Usage: "Minimum number of executable transaction slots guaranteed per account",
   238  		Value: aqua.DefaultConfig.TxPool.AccountSlots,
   239  	}
   240  	TxPoolGlobalSlotsFlag = cli.Uint64Flag{
   241  		Name:  "txpool.globalslots",
   242  		Usage: "Maximum number of executable transaction slots for all accounts",
   243  		Value: aqua.DefaultConfig.TxPool.GlobalSlots,
   244  	}
   245  	TxPoolAccountQueueFlag = cli.Uint64Flag{
   246  		Name:  "txpool.accountqueue",
   247  		Usage: "Maximum number of non-executable transaction slots permitted per account",
   248  		Value: aqua.DefaultConfig.TxPool.AccountQueue,
   249  	}
   250  	TxPoolGlobalQueueFlag = cli.Uint64Flag{
   251  		Name:  "txpool.globalqueue",
   252  		Usage: "Maximum number of non-executable transaction slots for all accounts",
   253  		Value: aqua.DefaultConfig.TxPool.GlobalQueue,
   254  	}
   255  	TxPoolLifetimeFlag = cli.DurationFlag{
   256  		Name:  "txpool.lifetime",
   257  		Usage: "Maximum amount of time non-executable transaction are queued",
   258  		Value: aqua.DefaultConfig.TxPool.Lifetime,
   259  	}
   260  	// Performance tuning settings
   261  	CacheFlag = cli.IntFlag{
   262  		Name:  "cache",
   263  		Usage: "Megabytes of memory allocated to internal caching (consider 2048)",
   264  		Value: 1024,
   265  	}
   266  	CacheDatabaseFlag = cli.IntFlag{
   267  		Name:  "cache.database",
   268  		Usage: "Percentage of cache memory allowance to use for database io",
   269  		Value: 75,
   270  	}
   271  	CacheGCFlag = cli.IntFlag{
   272  		Name:  "cache.gc",
   273  		Usage: "Percentage of cache memory allowance to use for trie pruning",
   274  		Value: 25,
   275  	}
   276  	TrieCacheGenFlag = cli.IntFlag{
   277  		Name:  "trie-cache-gens",
   278  		Usage: "Number of trie node generations to keep in memory",
   279  		Value: int(state.MaxTrieCacheGen),
   280  	}
   281  	// Miner settings
   282  	MiningEnabledFlag = cli.BoolFlag{
   283  		Name:  "mine",
   284  		Usage: "Enable mining",
   285  	}
   286  	MinerThreadsFlag = cli.IntFlag{
   287  		Name:  "minerthreads",
   288  		Usage: "Number of CPU threads to use for mining",
   289  		Value: runtime.NumCPU(),
   290  	}
   291  	TargetGasLimitFlag = cli.Uint64Flag{
   292  		Name:  "targetgaslimit",
   293  		Usage: "Target gas limit sets the artificial target gas floor for the blocks to mine",
   294  		Value: params.GenesisGasLimit,
   295  	}
   296  	AquabaseFlag = cli.StringFlag{
   297  		Name:  "aquabase",
   298  		Usage: "Public address for block mining rewards (default = first account created)",
   299  		Value: "0",
   300  	}
   301  	GasPriceFlag = BigFlag{
   302  		Name:  "gasprice",
   303  		Usage: "Minimal gas price to accept for mining a transactions",
   304  		Value: aqua.DefaultConfig.GasPrice,
   305  	}
   306  	ExtraDataFlag = cli.StringFlag{
   307  		Name:  "extradata",
   308  		Usage: "Block extra data set by the miner (default = client version)",
   309  	}
   310  	// Account settings
   311  	UnlockedAccountFlag = cli.StringFlag{
   312  		Name:  "unlock",
   313  		Usage: "Comma separated list of accounts to unlock",
   314  		Value: "",
   315  	}
   316  	PasswordFileFlag = cli.StringFlag{
   317  		Name:  "password",
   318  		Usage: "Password file to use for non-interactive password input",
   319  		Value: "",
   320  	}
   321  
   322  	VMEnableDebugFlag = cli.BoolFlag{
   323  		Name:  "vmdebug",
   324  		Usage: "Record information useful for VM and contract debugging",
   325  	}
   326  	// Logging and debug settings
   327  	AquaStatsURLFlag = cli.StringFlag{
   328  		Name:  "aquastats",
   329  		Usage: "Reporting URL of a aquastats service (nodename:secret@host:port)",
   330  	}
   331  	MetricsEnabledFlag = cli.BoolFlag{
   332  		Name:  metrics.MetricsEnabledFlag,
   333  		Usage: "Enable metrics collection and reporting",
   334  	}
   335  	FakePoWFlag = cli.BoolFlag{
   336  		Name:  "fakepow",
   337  		Usage: "Disables proof-of-work verification",
   338  	}
   339  	NoCompactionFlag = cli.BoolFlag{
   340  		Name:  "nocompaction",
   341  		Usage: "Disables db compaction after import",
   342  	}
   343  	// RPC settings
   344  	RPCEnabledFlag = cli.BoolFlag{
   345  		Name:  "rpc",
   346  		Usage: "Enable the HTTP-RPC server",
   347  	}
   348  	RPCListenAddrFlag = cli.StringFlag{
   349  		Name:  "rpcaddr",
   350  		Usage: "HTTP-RPC server listening interface",
   351  		Value: node.DefaultHTTPHost,
   352  	}
   353  	RPCPortFlag = cli.IntFlag{
   354  		Name:  "rpcport",
   355  		Usage: "HTTP-RPC server listening port",
   356  		Value: node.DefaultHTTPPort,
   357  	}
   358  	RPCCORSDomainFlag = cli.StringFlag{
   359  		Name:  "rpccorsdomain",
   360  		Usage: "Comma separated list of domains from which to accept cross origin requests (browser enforced)",
   361  		Value: "",
   362  	}
   363  	RPCVirtualHostsFlag = cli.StringFlag{
   364  		Name:  "rpcvhosts",
   365  		Usage: "Comma separated list of virtual hostnames from which to accept requests (server enforced). Accepts '*' wildcard.",
   366  		Value: "localhost",
   367  	}
   368  
   369  	RPCApiFlag = cli.StringFlag{
   370  		Name:  "rpcapi",
   371  		Usage: "API's offered over the HTTP-RPC interface",
   372  		Value: "",
   373  	}
   374  	RPCUnlockFlag = cli.BoolFlag{
   375  		Name:  "UNSAFE_RPC_UNLOCK",
   376  		Usage: "",
   377  	}
   378  	IPCDisabledFlag = cli.BoolFlag{
   379  		Name:  "ipcdisable",
   380  		Usage: "Disable the IPC-RPC server",
   381  	}
   382  	IPCPathFlag = DirectoryFlag{
   383  		Name:  "ipcpath",
   384  		Usage: "Filename for IPC socket/pipe within the datadir (explicit paths escape it)",
   385  	}
   386  	WSEnabledFlag = cli.BoolFlag{
   387  		Name:  "ws",
   388  		Usage: "Enable the WS-RPC server",
   389  	}
   390  	WSListenAddrFlag = cli.StringFlag{
   391  		Name:  "wsaddr",
   392  		Usage: "WS-RPC server listening interface",
   393  		Value: node.DefaultWSHost,
   394  	}
   395  	WSPortFlag = cli.IntFlag{
   396  		Name:  "wsport",
   397  		Usage: "WS-RPC server listening port",
   398  		Value: node.DefaultWSPort,
   399  	}
   400  	WSApiFlag = cli.StringFlag{
   401  		Name:  "wsapi",
   402  		Usage: "API's offered over the WS-RPC interface",
   403  		Value: "",
   404  	}
   405  	WSAllowedOriginsFlag = cli.StringFlag{
   406  		Name:  "wsorigins",
   407  		Usage: "Origins from which to accept websockets requests",
   408  		Value: "",
   409  	}
   410  	RPCAllowIPFlag = cli.StringFlag{
   411  		Name:  "allowip",
   412  		Usage: "Comma separated list of IP allowed to access RPC (http/ws)",
   413  		Value: "127.0.0.1",
   414  	}
   415  	ExecFlag = cli.StringFlag{
   416  		Name:  "exec",
   417  		Usage: "Execute JavaScript statement",
   418  	}
   419  	PreloadJSFlag = cli.StringFlag{
   420  		Name:  "preload",
   421  		Usage: "Comma separated list of JavaScript files to preload into the console",
   422  	}
   423  
   424  	// Network Settings
   425  	MaxPeersFlag = cli.IntFlag{
   426  		Name:  "maxpeers",
   427  		Usage: "Maximum number of network peers (network disabled if set to 0)",
   428  		Value: 25,
   429  	}
   430  	MaxPendingPeersFlag = cli.IntFlag{
   431  		Name:  "maxpendpeers",
   432  		Usage: "Maximum number of pending connection attempts (defaults used if set to 0)",
   433  		Value: 0,
   434  	}
   435  	ListenPortFlag = cli.IntFlag{
   436  		Name:  "port",
   437  		Usage: "Network listening port",
   438  		Value: 21303,
   439  	}
   440  	BootnodesFlag = cli.StringFlag{
   441  		Name:  "bootnodes",
   442  		Usage: "Comma separated enode URLs for P2P discovery bootstrap (set v4+v5 instead for light servers)",
   443  		Value: "",
   444  	}
   445  	BootnodesV4Flag = cli.StringFlag{
   446  		Name:  "bootnodesv4",
   447  		Usage: "Comma separated enode URLs for P2P v4 discovery bootstrap (light server, full nodes)",
   448  		Value: "",
   449  	}
   450  	BootnodesV5Flag = cli.StringFlag{
   451  		Name:  "bootnodesv5",
   452  		Usage: "Comma separated enode URLs for P2P v5 discovery bootstrap (light server, light nodes)",
   453  		Value: "",
   454  	}
   455  	NodeKeyFileFlag = cli.StringFlag{
   456  		Name:  "nodekey",
   457  		Usage: "P2P node key file",
   458  	}
   459  	NodeKeyHexFlag = cli.StringFlag{
   460  		Name:  "nodekeyhex",
   461  		Usage: "P2P node key as hex (for testing)",
   462  	}
   463  	NATFlag = cli.StringFlag{
   464  		Name:  "nat",
   465  		Usage: "NAT port mapping mechanism (any|none|upnp|pmp|extip:<IP>)",
   466  		Value: "any",
   467  	}
   468  	NoDiscoverFlag = cli.BoolFlag{
   469  		Name:  "nodiscover",
   470  		Usage: "Disables the peer discovery mechanism (manual peer addition)",
   471  	}
   472  	OfflineFlag = cli.BoolFlag{
   473  		Name:  "offline",
   474  		Usage: "Disables peer discovery and sets nat=none, still listens on tcp/udp port",
   475  	}
   476  	DiscoveryV5Flag = cli.BoolFlag{
   477  		Name:  "v5disc",
   478  		Usage: "Enables the experimental RLPx V5 (Topic Discovery) mechanism",
   479  	}
   480  	NetrestrictFlag = cli.StringFlag{
   481  		Name:  "netrestrict",
   482  		Usage: "Restricts network communication to the given IP networks (CIDR masks)",
   483  	}
   484  
   485  	// ATM the url is left to the user and deployment to
   486  	JSpathFlag = cli.StringFlag{
   487  		Name:  "jspath",
   488  		Usage: "JavaScript root path for `loadScript`",
   489  		Value: ".",
   490  	}
   491  
   492  	// Gas price oracle settings
   493  	GpoBlocksFlag = cli.IntFlag{
   494  		Name:  "gpoblocks",
   495  		Usage: "Number of recent blocks to check for gas prices",
   496  		Value: aqua.DefaultConfig.GPO.Blocks,
   497  	}
   498  	GpoPercentileFlag = cli.IntFlag{
   499  		Name:  "gpopercentile",
   500  		Usage: "Suggested gas price is the given percentile of a set of recent transaction gas prices",
   501  		Value: aqua.DefaultConfig.GPO.Percentile,
   502  	}
   503  	WhisperEnabledFlag = cli.BoolFlag{
   504  		Name:  "shh",
   505  		Usage: "Enable Whisper",
   506  	}
   507  	WhisperMaxMessageSizeFlag = cli.IntFlag{
   508  		Name:  "shh.maxmessagesize",
   509  		Usage: "Max message size accepted",
   510  		Value: int(whisper.DefaultMaxMessageSize),
   511  	}
   512  	WhisperMinPOWFlag = cli.Float64Flag{
   513  		Name:  "shh.pow",
   514  		Usage: "Minimum POW accepted",
   515  		Value: whisper.DefaultMinimumPoW,
   516  	}
   517  )
   518  
   519  // MakeDataDir retrieves the currently requested data directory, terminating
   520  // if none (or the empty string) is specified. If the node is starting a testnet,
   521  // the a subdirectory of the specified datadir will be used.
   522  func MakeDataDir(ctx *cli.Context) string {
   523  	if path := ctx.GlobalString(DataDirFlag.Name); path != "" {
   524  		if ctx.GlobalBool(TestnetFlag.Name) {
   525  			return filepath.Join(path, "testnet")
   526  		}
   527  		if ctx.GlobalBool(Testnet2Flag.Name) {
   528  			return filepath.Join(path, "testnet2")
   529  		}
   530  		return path
   531  	}
   532  	Fatalf("Cannot determine default data directory, please set manually (--datadir)")
   533  	return ""
   534  }
   535  
   536  // setNodeKey creates a node key from set command line flags, either loading it
   537  // from a file or as a specified hex value. If neither flags were provided, this
   538  // method returns nil and an emphemeral key is to be generated.
   539  func setNodeKey(ctx *cli.Context, cfg *p2p.Config) {
   540  	var (
   541  		hex  = ctx.GlobalString(NodeKeyHexFlag.Name)
   542  		file = ctx.GlobalString(NodeKeyFileFlag.Name)
   543  		key  *ecdsa.PrivateKey
   544  		err  error
   545  	)
   546  	switch {
   547  	case file != "" && hex != "":
   548  		Fatalf("Options %q and %q are mutually exclusive", NodeKeyFileFlag.Name, NodeKeyHexFlag.Name)
   549  	case file != "":
   550  		if key, err = crypto.LoadECDSA(file); err != nil {
   551  			Fatalf("Option %q: %v", NodeKeyFileFlag.Name, err)
   552  		}
   553  		cfg.PrivateKey = key
   554  	case hex != "":
   555  		if key, err = crypto.HexToECDSA(hex); err != nil {
   556  			Fatalf("Option %q: %v", NodeKeyHexFlag.Name, err)
   557  		}
   558  		cfg.PrivateKey = key
   559  	}
   560  }
   561  
   562  // setNodeUserIdent creates the user identifier from CLI flags.
   563  func setNodeUserIdent(ctx *cli.Context, cfg *node.Config) {
   564  	if identity := ctx.GlobalString(IdentityFlag.Name); len(identity) > 0 {
   565  		cfg.UserIdent = identity
   566  	}
   567  }
   568  
   569  // setBootstrapNodes creates a list of bootstrap nodes from the command line
   570  // flags, reverting to pre-configured ones if none have been specified.
   571  func setBootstrapNodes(ctx *cli.Context, cfg *p2p.Config) {
   572  	urls := params.MainnetBootnodes
   573  	switch {
   574  	case ctx.GlobalIsSet(BootnodesFlag.Name) || ctx.GlobalIsSet(BootnodesV4Flag.Name):
   575  		if ctx.GlobalIsSet(BootnodesV4Flag.Name) {
   576  			urls = strings.Split(ctx.GlobalString(BootnodesV4Flag.Name), ",")
   577  		} else {
   578  			urls = strings.Split(ctx.GlobalString(BootnodesFlag.Name), ",")
   579  		}
   580  	case ctx.GlobalBool(TestnetFlag.Name):
   581  		urls = params.TestnetBootnodes
   582  	case ctx.GlobalBool(Testnet2Flag.Name):
   583  		urls = params.Testnet2Bootnodes
   584  	case cfg.BootstrapNodes != nil:
   585  		return // already set, don't apply defaults.
   586  	}
   587  
   588  	cfg.BootstrapNodes = make([]*discover.Node, 0, len(urls))
   589  	for _, url := range urls {
   590  		node, err := discover.ParseNode(url)
   591  		if err != nil {
   592  			log.Crit("Bootstrap URL invalid", "enode", url, "err", err)
   593  		}
   594  		cfg.BootstrapNodes = append(cfg.BootstrapNodes, node)
   595  	}
   596  }
   597  
   598  // setBootstrapNodesV5 creates a list of bootstrap nodes from the command line
   599  // flags, reverting to pre-configured ones if none have been specified.
   600  func setBootstrapNodesV5(ctx *cli.Context, cfg *p2p.Config) {
   601  	urls := params.DiscoveryV5Bootnodes
   602  	switch {
   603  	case ctx.GlobalIsSet(BootnodesFlag.Name) || ctx.GlobalIsSet(BootnodesV5Flag.Name):
   604  		if ctx.GlobalIsSet(BootnodesV5Flag.Name) {
   605  			urls = strings.Split(ctx.GlobalString(BootnodesV5Flag.Name), ",")
   606  		} else {
   607  			urls = strings.Split(ctx.GlobalString(BootnodesFlag.Name), ",")
   608  		}
   609  	case ctx.GlobalBool(Testnet2Flag.Name):
   610  		urls = params.Testnet2Bootnodes
   611  	case cfg.BootstrapNodesV5 != nil:
   612  		return // already set, don't apply defaults.
   613  	}
   614  
   615  	cfg.BootstrapNodesV5 = make([]*discv5.Node, 0, len(urls))
   616  	for _, url := range urls {
   617  		node, err := discv5.ParseNode(url)
   618  		if err != nil {
   619  			log.Error("Bootstrap URL invalid", "enode", url, "err", err)
   620  			continue
   621  		}
   622  		cfg.BootstrapNodesV5 = append(cfg.BootstrapNodesV5, node)
   623  	}
   624  }
   625  
   626  // setListenAddress creates a TCP listening address string from set command
   627  // line flags.
   628  func setListenAddress(ctx *cli.Context, cfg *p2p.Config) {
   629  	if ctx.GlobalIsSet(ListenPortFlag.Name) {
   630  		cfg.ListenAddr = fmt.Sprintf(":%d", ctx.GlobalInt(ListenPortFlag.Name))
   631  	}
   632  }
   633  
   634  // setNAT creates a port mapper from command line flags.
   635  func setNAT(ctx *cli.Context, cfg *p2p.Config) {
   636  	if ctx.GlobalIsSet(NATFlag.Name) {
   637  		natif, err := nat.Parse(ctx.GlobalString(NATFlag.Name))
   638  		if err != nil {
   639  			Fatalf("Option %s: %v", NATFlag.Name, err)
   640  		}
   641  		cfg.NAT = natif
   642  	}
   643  	if ctx.GlobalIsSet(OfflineFlag.Name) {
   644  		cfg.NAT = nil
   645  	}
   646  }
   647  
   648  // splitAndTrim splits input separated by a comma
   649  // and trims excessive white space from the substrings.
   650  func splitAndTrim(input string) []string {
   651  	result := strings.Split(input, ",")
   652  	for i, r := range result {
   653  		result[i] = strings.TrimSpace(r)
   654  	}
   655  	return result
   656  }
   657  
   658  // setHTTP creates the HTTP RPC listener interface string from the set
   659  // command line flags, returning empty if the HTTP endpoint is disabled.
   660  func setHTTP(ctx *cli.Context, cfg *node.Config) {
   661  	if ctx.GlobalBool(RPCEnabledFlag.Name) && cfg.HTTPHost == "" {
   662  		cfg.HTTPHost = "127.0.0.1"
   663  		if ctx.GlobalIsSet(RPCListenAddrFlag.Name) && ctx.GlobalIsSet(UnlockedAccountFlag.Name) && !ctx.GlobalIsSet(RPCUnlockFlag.Name) {
   664  			Fatalf("Woah there! By default, using -rpc and -unlock is \"safe\", (localhost).\n" +
   665  				"But you shouldn't use --rpcaddr with --unlock flag.\n" +
   666  				"If you really know what you are doing and would like to unlock a wallet while" +
   667  				"hosting a public HTTP RPC node, use the -UNSAFE_RPC_UNLOCK flag.")
   668  		}
   669  		if ctx.GlobalIsSet(RPCListenAddrFlag.Name) {
   670  			cfg.HTTPHost = ctx.GlobalString(RPCListenAddrFlag.Name)
   671  		}
   672  	}
   673  
   674  	if ctx.GlobalIsSet(RPCPortFlag.Name) {
   675  		cfg.HTTPPort = ctx.GlobalInt(RPCPortFlag.Name)
   676  	}
   677  	if ctx.GlobalIsSet(RPCCORSDomainFlag.Name) {
   678  		cfg.HTTPCors = splitAndTrim(ctx.GlobalString(RPCCORSDomainFlag.Name))
   679  	}
   680  	if ctx.GlobalIsSet(RPCApiFlag.Name) {
   681  		cfg.HTTPModules = splitAndTrim(ctx.GlobalString(RPCApiFlag.Name))
   682  	}
   683  
   684  	cfg.HTTPVirtualHosts = splitAndTrim(ctx.GlobalString(RPCVirtualHostsFlag.Name))
   685  	cfg.RPCAllowIP = splitAndTrim(ctx.GlobalString(RPCAllowIPFlag.Name))
   686  }
   687  
   688  // setWS creates the WebSocket RPC listener interface string from the set
   689  // command line flags, returning empty if the HTTP endpoint is disabled.
   690  func setWS(ctx *cli.Context, cfg *node.Config) {
   691  	if ctx.GlobalBool(WSEnabledFlag.Name) && cfg.WSHost == "" {
   692  		cfg.WSHost = "127.0.0.1"
   693  		if ctx.GlobalIsSet(WSListenAddrFlag.Name) {
   694  			cfg.WSHost = ctx.GlobalString(WSListenAddrFlag.Name)
   695  		}
   696  	}
   697  
   698  	if ctx.GlobalIsSet(WSPortFlag.Name) {
   699  		cfg.WSPort = ctx.GlobalInt(WSPortFlag.Name)
   700  	}
   701  	if ctx.GlobalIsSet(WSAllowedOriginsFlag.Name) {
   702  		cfg.WSOrigins = splitAndTrim(ctx.GlobalString(WSAllowedOriginsFlag.Name))
   703  	}
   704  	if ctx.GlobalIsSet(WSApiFlag.Name) {
   705  		cfg.WSModules = splitAndTrim(ctx.GlobalString(WSApiFlag.Name))
   706  	}
   707  }
   708  
   709  // setIPC creates an IPC path configuration from the set command line flags,
   710  // returning an empty string if IPC was explicitly disabled, or the set path.
   711  func setIPC(ctx *cli.Context, cfg *node.Config) {
   712  	checkExclusive(ctx, IPCDisabledFlag, IPCPathFlag)
   713  	switch {
   714  	case ctx.GlobalBool(IPCDisabledFlag.Name):
   715  		cfg.IPCPath = ""
   716  	case ctx.GlobalIsSet(IPCPathFlag.Name):
   717  		cfg.IPCPath = ctx.GlobalString(IPCPathFlag.Name)
   718  	}
   719  }
   720  
   721  // makeDatabaseHandles raises out the number of allowed file handles per process
   722  // for AquaChain and returns half of the allowance to assign to the database.
   723  func makeDatabaseHandles() int {
   724  	limit, err := fdlimit.Current()
   725  	if err != nil {
   726  		Fatalf("Failed to retrieve file descriptor allowance: %v", err)
   727  	}
   728  	if limit < 2048 {
   729  		if err := fdlimit.Raise(2048); err != nil {
   730  			Fatalf("Failed to raise file descriptor allowance: %v", err)
   731  		}
   732  	}
   733  	if limit > 2048 { // cap database file descriptors even if more is available
   734  		limit = 2048
   735  	}
   736  	return limit / 2 // Leave half for networking and other stuff
   737  }
   738  
   739  // MakeAddress converts an account specified directly as a hex encoded string or
   740  // a key index in the key store to an internal account representation.
   741  func MakeAddress(ks *keystore.KeyStore, account string) (accounts.Account, error) {
   742  	// If the specified account is a valid address, return it
   743  	if common.IsHexAddress(account) {
   744  		return accounts.Account{Address: common.HexToAddress(account)}, nil
   745  	}
   746  	// Otherwise try to interpret the account as a keystore index
   747  	index, err := strconv.Atoi(account)
   748  	if err != nil || index < 0 {
   749  		return accounts.Account{}, fmt.Errorf("invalid account address or index %q", account)
   750  	}
   751  	log.Warn("-------------------------------------------------------------------")
   752  	log.Warn("Referring to accounts by order in the keystore folder is dangerous!")
   753  	log.Warn("This functionality is deprecated and will be removed in the future!")
   754  	log.Warn("Please use explicit addresses! (can search via `aquachain account list`)")
   755  	log.Warn("-------------------------------------------------------------------")
   756  
   757  	accs := ks.Accounts()
   758  	if len(accs) <= index {
   759  		return accounts.Account{}, fmt.Errorf("index %d higher than number of accounts %d", index, len(accs))
   760  	}
   761  	return accs[index], nil
   762  }
   763  
   764  // setAquabase retrieves the aquabase either from the directly specified
   765  // command line flags or from the keystore if CLI indexed.
   766  func setAquabase(ctx *cli.Context, ks *keystore.KeyStore, cfg *aqua.Config) {
   767  	if ctx.GlobalIsSet(AquabaseFlag.Name) {
   768  		account, err := MakeAddress(ks, ctx.GlobalString(AquabaseFlag.Name))
   769  		if err != nil {
   770  			Fatalf("Option %q: %v", AquabaseFlag.Name, err)
   771  		}
   772  		cfg.Aquabase = account.Address
   773  	}
   774  }
   775  
   776  // MakePasswordList reads password lines from the file specified by the global --password flag.
   777  func MakePasswordList(ctx *cli.Context) []string {
   778  	path := ctx.GlobalString(PasswordFileFlag.Name)
   779  	if path == "" {
   780  		return nil
   781  	}
   782  	text, err := ioutil.ReadFile(path)
   783  	if err != nil {
   784  		Fatalf("Failed to read password file: %v", err)
   785  	}
   786  	lines := strings.Split(string(text), "\n")
   787  	// Sanitise DOS line endings.
   788  	for i := range lines {
   789  		lines[i] = strings.TrimRight(lines[i], "\r")
   790  	}
   791  	return lines
   792  }
   793  
   794  func SetP2PConfig(ctx *cli.Context, cfg *p2p.Config) {
   795  	setNodeKey(ctx, cfg)
   796  	setNAT(ctx, cfg)
   797  	setListenAddress(ctx, cfg)
   798  	setBootstrapNodes(ctx, cfg)
   799  	setBootstrapNodesV5(ctx, cfg)
   800  
   801  	if ctx.GlobalIsSet(MaxPeersFlag.Name) {
   802  		cfg.MaxPeers = ctx.GlobalInt(MaxPeersFlag.Name)
   803  	}
   804  
   805  	log.Info("Maximum peer count", "AQUA", cfg.MaxPeers)
   806  
   807  	if ctx.GlobalIsSet(MaxPendingPeersFlag.Name) {
   808  		cfg.MaxPendingPeers = ctx.GlobalInt(MaxPendingPeersFlag.Name)
   809  	}
   810  
   811  	if ctx.GlobalIsSet(OfflineFlag.Name) {
   812  		cfg.NoDiscovery = true
   813  	}
   814  
   815  	if ctx.GlobalIsSet(NoDiscoverFlag.Name) {
   816  		cfg.NoDiscovery = true
   817  	}
   818  	if ctx.GlobalBool(Testnet2Flag.Name) {
   819  		cfg.NoDiscovery = true
   820  	}
   821  	if ctx.GlobalIsSet(DiscoveryV5Flag.Name) {
   822  		cfg.DiscoveryV5 = ctx.GlobalBool(DiscoveryV5Flag.Name)
   823  	}
   824  
   825  	if netrestrict := ctx.GlobalString(NetrestrictFlag.Name); netrestrict != "" {
   826  		list, err := netutil.ParseNetlist(netrestrict)
   827  		if err != nil {
   828  			Fatalf("Option %q: %v", NetrestrictFlag.Name, err)
   829  		}
   830  		cfg.NetRestrict = list
   831  	}
   832  
   833  	if ctx.GlobalBool(DeveloperFlag.Name) {
   834  		// --dev mode can't use p2p networking.
   835  		cfg.MaxPeers = 0
   836  		cfg.ListenAddr = ":0"
   837  		cfg.NoDiscovery = true
   838  		cfg.DiscoveryV5 = false
   839  	}
   840  
   841  	if ctx.GlobalBool(TestnetFlag.Name) && !ctx.GlobalIsSet(ListenPortFlag.Name) {
   842  		cfg.ListenAddr = ":21304"
   843  	}
   844  
   845  }
   846  
   847  // SetNodeConfig applies node-related command line flags to the config.
   848  func SetNodeConfig(ctx *cli.Context, cfg *node.Config) {
   849  	SetP2PConfig(ctx, &cfg.P2P)
   850  	setIPC(ctx, cfg)
   851  	setHTTP(ctx, cfg)
   852  	setWS(ctx, cfg)
   853  	setNodeUserIdent(ctx, cfg)
   854  
   855  	switch {
   856  	case ctx.GlobalIsSet(DataDirFlag.Name):
   857  		cfg.DataDir = ctx.GlobalString(DataDirFlag.Name)
   858  	case ctx.GlobalBool(DeveloperFlag.Name):
   859  		cfg.DataDir = "" // unless explicitly requested, use memory databases
   860  	case ctx.GlobalBool(TestnetFlag.Name):
   861  		cfg.DataDir = filepath.Join(node.DefaultDataDir(), "testnet")
   862  	case ctx.GlobalBool(Testnet2Flag.Name):
   863  		cfg.DataDir = filepath.Join(node.DefaultDataDir(), "testnet2")
   864  	}
   865  
   866  	if ctx.GlobalIsSet(KeyStoreDirFlag.Name) {
   867  		cfg.KeyStoreDir = ctx.GlobalString(KeyStoreDirFlag.Name)
   868  	}
   869  	if ctx.GlobalIsSet(UseUSBFlag.Name) {
   870  		cfg.UseUSB = ctx.GlobalBool(UseUSBFlag.Name)
   871  	}
   872  }
   873  
   874  func setGPO(ctx *cli.Context, cfg *gasprice.Config) {
   875  	if ctx.GlobalIsSet(GpoBlocksFlag.Name) {
   876  		cfg.Blocks = ctx.GlobalInt(GpoBlocksFlag.Name)
   877  	}
   878  	if ctx.GlobalIsSet(GpoPercentileFlag.Name) {
   879  		cfg.Percentile = ctx.GlobalInt(GpoPercentileFlag.Name)
   880  	}
   881  }
   882  
   883  func setTxPool(ctx *cli.Context, cfg *core.TxPoolConfig) {
   884  	if ctx.GlobalIsSet(TxPoolNoLocalsFlag.Name) {
   885  		cfg.NoLocals = ctx.GlobalBool(TxPoolNoLocalsFlag.Name)
   886  	}
   887  	if ctx.GlobalIsSet(TxPoolJournalFlag.Name) {
   888  		cfg.Journal = ctx.GlobalString(TxPoolJournalFlag.Name)
   889  	}
   890  	if ctx.GlobalIsSet(TxPoolRejournalFlag.Name) {
   891  		cfg.Rejournal = ctx.GlobalDuration(TxPoolRejournalFlag.Name)
   892  	}
   893  	if ctx.GlobalIsSet(TxPoolPriceLimitFlag.Name) {
   894  		cfg.PriceLimit = ctx.GlobalUint64(TxPoolPriceLimitFlag.Name)
   895  	}
   896  	if ctx.GlobalIsSet(TxPoolPriceBumpFlag.Name) {
   897  		cfg.PriceBump = ctx.GlobalUint64(TxPoolPriceBumpFlag.Name)
   898  	}
   899  	if ctx.GlobalIsSet(TxPoolAccountSlotsFlag.Name) {
   900  		cfg.AccountSlots = ctx.GlobalUint64(TxPoolAccountSlotsFlag.Name)
   901  	}
   902  	if ctx.GlobalIsSet(TxPoolGlobalSlotsFlag.Name) {
   903  		cfg.GlobalSlots = ctx.GlobalUint64(TxPoolGlobalSlotsFlag.Name)
   904  	}
   905  	if ctx.GlobalIsSet(TxPoolAccountQueueFlag.Name) {
   906  		cfg.AccountQueue = ctx.GlobalUint64(TxPoolAccountQueueFlag.Name)
   907  	}
   908  	if ctx.GlobalIsSet(TxPoolGlobalQueueFlag.Name) {
   909  		cfg.GlobalQueue = ctx.GlobalUint64(TxPoolGlobalQueueFlag.Name)
   910  	}
   911  	if ctx.GlobalIsSet(TxPoolLifetimeFlag.Name) {
   912  		cfg.Lifetime = ctx.GlobalDuration(TxPoolLifetimeFlag.Name)
   913  	}
   914  }
   915  
   916  func setAquahash(ctx *cli.Context, cfg *aqua.Config) {
   917  	if ctx.GlobalIsSet(AquahashCacheDirFlag.Name) {
   918  		cfg.Aquahash.CacheDir = ctx.GlobalString(AquahashCacheDirFlag.Name)
   919  	}
   920  	if ctx.GlobalIsSet(AquahashDatasetDirFlag.Name) {
   921  		cfg.Aquahash.DatasetDir = ctx.GlobalString(AquahashDatasetDirFlag.Name)
   922  	}
   923  	if ctx.GlobalIsSet(AquahashCachesInMemoryFlag.Name) {
   924  		cfg.Aquahash.CachesInMem = ctx.GlobalInt(AquahashCachesInMemoryFlag.Name)
   925  	}
   926  	if ctx.GlobalIsSet(AquahashCachesOnDiskFlag.Name) {
   927  		cfg.Aquahash.CachesOnDisk = ctx.GlobalInt(AquahashCachesOnDiskFlag.Name)
   928  	}
   929  	if ctx.GlobalIsSet(AquahashDatasetsInMemoryFlag.Name) {
   930  		cfg.Aquahash.DatasetsInMem = ctx.GlobalInt(AquahashDatasetsInMemoryFlag.Name)
   931  	}
   932  	if ctx.GlobalIsSet(AquahashDatasetsOnDiskFlag.Name) {
   933  		cfg.Aquahash.DatasetsOnDisk = ctx.GlobalInt(AquahashDatasetsOnDiskFlag.Name)
   934  	}
   935  }
   936  
   937  // checkExclusive verifies that only a single isntance of the provided flags was
   938  // set by the user. Each flag might optionally be followed by a string type to
   939  // specialize it further.
   940  func checkExclusive(ctx *cli.Context, args ...interface{}) {
   941  	set := make([]string, 0, 1)
   942  	for i := 0; i < len(args); i++ {
   943  		// Make sure the next argument is a flag and skip if not set
   944  		flag, ok := args[i].(cli.Flag)
   945  		if !ok {
   946  			panic(fmt.Sprintf("invalid argument, not cli.Flag type: %T", args[i]))
   947  		}
   948  		// Check if next arg extends current and expand its name if so
   949  		name := flag.GetName()
   950  
   951  		if i+1 < len(args) {
   952  			switch option := args[i+1].(type) {
   953  			case string:
   954  				// Extended flag, expand the name and shift the arguments
   955  				if ctx.GlobalString(flag.GetName()) == option {
   956  					name += "=" + option
   957  				}
   958  				i++
   959  
   960  			case cli.Flag:
   961  			default:
   962  				panic(fmt.Sprintf("invalid argument, not cli.Flag or string extension: %T", args[i+1]))
   963  			}
   964  		}
   965  		// Mark the flag if it's set
   966  		if ctx.GlobalIsSet(flag.GetName()) {
   967  			set = append(set, "--"+name)
   968  		}
   969  	}
   970  	if len(set) > 1 {
   971  		Fatalf("Flags %v can't be used at the same time", strings.Join(set, ", "))
   972  	}
   973  }
   974  
   975  // SetShhConfig applies shh-related command line flags to the config.
   976  func SetShhConfig(ctx *cli.Context, stack *node.Node, cfg *whisper.Config) {
   977  	if ctx.GlobalIsSet(WhisperMaxMessageSizeFlag.Name) {
   978  		cfg.MaxMessageSize = uint32(ctx.GlobalUint(WhisperMaxMessageSizeFlag.Name))
   979  	}
   980  	if ctx.GlobalIsSet(WhisperMinPOWFlag.Name) {
   981  		cfg.MinimumAcceptedPOW = ctx.GlobalFloat64(WhisperMinPOWFlag.Name)
   982  	}
   983  }
   984  
   985  // SetAquaConfig applies aqua-related command line flags to the config.
   986  func SetAquaConfig(ctx *cli.Context, stack *node.Node, cfg *aqua.Config) {
   987  	// Avoid conflicting network flags
   988  	checkExclusive(ctx, DeveloperFlag, TestnetFlag, Testnet2Flag)
   989  	checkExclusive(ctx, FastSyncFlag, SyncModeFlag)
   990  	// checkExclusive(ctx, LightServFlag, LightModeFlag)
   991  	// checkExclusive(ctx, LightServFlag, SyncModeFlag, "light")
   992  
   993  	ks := stack.AccountManager().Backends(keystore.KeyStoreType)[0].(*keystore.KeyStore)
   994  	setAquabase(ctx, ks, cfg)
   995  	setGPO(ctx, &cfg.GPO)
   996  	setTxPool(ctx, &cfg.TxPool)
   997  	setAquahash(ctx, cfg)
   998  
   999  	switch {
  1000  	case ctx.GlobalIsSet(SyncModeFlag.Name):
  1001  		cfg.SyncMode = *GlobalTextMarshaler(ctx, SyncModeFlag.Name).(*downloader.SyncMode)
  1002  	case ctx.GlobalBool(FastSyncFlag.Name):
  1003  		cfg.SyncMode = downloader.FastSync
  1004  	}
  1005  
  1006  	if ctx.GlobalIsSet(NetworkIdFlag.Name) {
  1007  		cfg.NetworkId = ctx.GlobalUint64(NetworkIdFlag.Name)
  1008  	}
  1009  
  1010  	if ctx.GlobalIsSet(CacheFlag.Name) || ctx.GlobalIsSet(CacheDatabaseFlag.Name) {
  1011  		cfg.DatabaseCache = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheDatabaseFlag.Name) / 100
  1012  	}
  1013  	cfg.DatabaseHandles = makeDatabaseHandles()
  1014  
  1015  	if gcmode := ctx.GlobalString(GCModeFlag.Name); gcmode != "full" && gcmode != "archive" {
  1016  		Fatalf("--%s must be either 'full' or 'archive'", GCModeFlag.Name)
  1017  	}
  1018  	cfg.NoPruning = ctx.GlobalString(GCModeFlag.Name) == "archive"
  1019  
  1020  	if ctx.GlobalIsSet(CacheFlag.Name) || ctx.GlobalIsSet(CacheGCFlag.Name) {
  1021  		cfg.TrieCache = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheGCFlag.Name) / 100
  1022  	}
  1023  	if ctx.GlobalIsSet(MinerThreadsFlag.Name) {
  1024  		cfg.MinerThreads = ctx.GlobalInt(MinerThreadsFlag.Name)
  1025  	}
  1026  	if ctx.GlobalIsSet(DocRootFlag.Name) {
  1027  		cfg.DocRoot = ctx.GlobalString(DocRootFlag.Name)
  1028  	}
  1029  	if ctx.GlobalIsSet(ExtraDataFlag.Name) {
  1030  		cfg.ExtraData = []byte(ctx.GlobalString(ExtraDataFlag.Name))
  1031  	}
  1032  	if ctx.GlobalIsSet(GasPriceFlag.Name) {
  1033  		cfg.GasPrice = GlobalBig(ctx, GasPriceFlag.Name)
  1034  	}
  1035  	if ctx.GlobalIsSet(VMEnableDebugFlag.Name) {
  1036  		// TODO(fjl): force-enable this in --dev mode
  1037  		cfg.EnablePreimageRecording = ctx.GlobalBool(VMEnableDebugFlag.Name)
  1038  	}
  1039  
  1040  	// Override any default configs for hard coded networks.
  1041  	switch {
  1042  	case ctx.GlobalBool(TestnetFlag.Name):
  1043  		if !ctx.GlobalIsSet(NetworkIdFlag.Name) {
  1044  			cfg.NetworkId = params.TestnetChainConfig.ChainId.Uint64()
  1045  		}
  1046  		cfg.Genesis = core.DefaultTestnetGenesisBlock()
  1047  	case ctx.GlobalBool(Testnet2Flag.Name):
  1048  		if !ctx.GlobalIsSet(NetworkIdFlag.Name) {
  1049  			cfg.NetworkId = params.Testnet2ChainConfig.ChainId.Uint64()
  1050  		}
  1051  		cfg.Genesis = core.DefaultTestnet2GenesisBlock()
  1052  	case ctx.GlobalBool(DeveloperFlag.Name):
  1053  		// Create new developer account or reuse existing one
  1054  		var (
  1055  			developer accounts.Account
  1056  			err       error
  1057  		)
  1058  		if accs := ks.Accounts(); len(accs) > 0 {
  1059  			developer = ks.Accounts()[0]
  1060  		} else {
  1061  			developer, err = ks.NewAccount("")
  1062  			if err != nil {
  1063  				Fatalf("Failed to create developer account: %v", err)
  1064  			}
  1065  		}
  1066  		if err := ks.Unlock(developer, ""); err != nil {
  1067  			Fatalf("Failed to unlock developer account: %v", err)
  1068  		}
  1069  		log.Info("Using developer account", "address", developer.Address)
  1070  
  1071  		cfg.Genesis = core.DeveloperGenesisBlock(uint64(ctx.GlobalInt(DeveloperPeriodFlag.Name)), developer.Address)
  1072  		if !ctx.GlobalIsSet(GasPriceFlag.Name) {
  1073  			cfg.GasPrice = big.NewInt(1)
  1074  		}
  1075  	}
  1076  	// TODO(fjl): move trie cache generations into config
  1077  	if gen := ctx.GlobalInt(TrieCacheGenFlag.Name); gen > 0 {
  1078  		state.MaxTrieCacheGen = uint16(gen)
  1079  	}
  1080  }
  1081  
  1082  // RegisterAquaService adds an AquaChain client to the stack.
  1083  func RegisterAquaService(stack *node.Node, cfg *aqua.Config) {
  1084  	err := stack.Register(func(ctx *node.ServiceContext) (node.Service, error) {
  1085  		return aqua.New(ctx, cfg)
  1086  	})
  1087  	if err != nil {
  1088  		Fatalf("Failed to register the AquaChain service: %v", err)
  1089  	}
  1090  }
  1091  
  1092  // RegisterShhService configures Whisper and adds it to the given node.
  1093  func RegisterShhService(stack *node.Node, cfg *whisper.Config) {
  1094  	if err := stack.Register(func(n *node.ServiceContext) (node.Service, error) {
  1095  		return whisper.New(cfg), nil
  1096  	}); err != nil {
  1097  		Fatalf("Failed to register the Whisper service: %v", err)
  1098  	}
  1099  }
  1100  
  1101  // RegisterAquaStatsService configures the AquaChain Stats daemon and adds it to
  1102  // th egiven node.
  1103  func RegisterAquaStatsService(stack *node.Node, url string) {
  1104  	if err := stack.Register(func(ctx *node.ServiceContext) (node.Service, error) {
  1105  		// Retrieve both aqua and les services
  1106  		var ethServ *aqua.AquaChain
  1107  		ctx.Service(&ethServ)
  1108  
  1109  		return aquastats.New(url, ethServ)
  1110  	}); err != nil {
  1111  		Fatalf("Failed to register the AquaChain Stats service: %v", err)
  1112  	}
  1113  }
  1114  
  1115  // SetupNetwork configures the system for either the main net or some test network.
  1116  func SetupNetwork(ctx *cli.Context) {
  1117  	// TODO(fjl): move target gas limit into config
  1118  	params.TargetGasLimit = ctx.GlobalUint64(TargetGasLimitFlag.Name)
  1119  }
  1120  
  1121  // MakeChainDatabase open an LevelDB using the flags passed to the client and will hard crash if it fails.
  1122  func MakeChainDatabase(ctx *cli.Context, stack *node.Node) aquadb.Database {
  1123  	var (
  1124  		cache   = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheDatabaseFlag.Name) / 100
  1125  		handles = makeDatabaseHandles()
  1126  	)
  1127  	name := "chaindata"
  1128  	chainDb, err := stack.OpenDatabase(name, cache, handles)
  1129  	if err != nil {
  1130  		Fatalf("Could not open database: %v", err)
  1131  	}
  1132  	return chainDb
  1133  }
  1134  
  1135  func MakeGenesis(ctx *cli.Context) *core.Genesis {
  1136  	var genesis *core.Genesis
  1137  	switch {
  1138  	case ctx.GlobalBool(TestnetFlag.Name):
  1139  		genesis = core.DefaultTestnetGenesisBlock()
  1140  	case ctx.GlobalBool(Testnet2Flag.Name):
  1141  		genesis = core.DefaultTestnet2GenesisBlock()
  1142  	case ctx.GlobalBool(DeveloperFlag.Name):
  1143  		Fatalf("Developer chains are ephemeral")
  1144  	}
  1145  	return genesis
  1146  }
  1147  
  1148  // MakeChain creates a chain manager from set command line flags.
  1149  func MakeChain(ctx *cli.Context, stack *node.Node) (chain *core.BlockChain, chainDb aquadb.Database) {
  1150  	var err error
  1151  	chainDb = MakeChainDatabase(ctx, stack)
  1152  
  1153  	config, _, err := core.SetupGenesisBlock(chainDb, MakeGenesis(ctx))
  1154  	if err != nil {
  1155  		Fatalf("%v", err)
  1156  	}
  1157  
  1158  	var engine consensus.Engine = aquahash.NewFaker()
  1159  
  1160  	if !ctx.GlobalBool(FakePoWFlag.Name) {
  1161  		engine = aquahash.New(aquahash.Config{
  1162  			CacheDir:       stack.ResolvePath(aqua.DefaultConfig.Aquahash.CacheDir),
  1163  			CachesInMem:    aqua.DefaultConfig.Aquahash.CachesInMem,
  1164  			CachesOnDisk:   aqua.DefaultConfig.Aquahash.CachesOnDisk,
  1165  			DatasetDir:     stack.ResolvePath(aqua.DefaultConfig.Aquahash.DatasetDir),
  1166  			DatasetsInMem:  aqua.DefaultConfig.Aquahash.DatasetsInMem,
  1167  			DatasetsOnDisk: aqua.DefaultConfig.Aquahash.DatasetsOnDisk,
  1168  		})
  1169  	}
  1170  
  1171  	if gcmode := ctx.GlobalString(GCModeFlag.Name); gcmode != "full" && gcmode != "archive" {
  1172  		Fatalf("--%s must be either 'full' or 'archive'", GCModeFlag.Name)
  1173  	}
  1174  	cache := &core.CacheConfig{
  1175  		Disabled:      ctx.GlobalString(GCModeFlag.Name) == "archive",
  1176  		TrieNodeLimit: aqua.DefaultConfig.TrieCache,
  1177  		TrieTimeLimit: aqua.DefaultConfig.TrieTimeout,
  1178  	}
  1179  	if ctx.GlobalIsSet(CacheFlag.Name) || ctx.GlobalIsSet(CacheGCFlag.Name) {
  1180  		cache.TrieNodeLimit = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheGCFlag.Name) / 100
  1181  	}
  1182  	vmcfg := vm.Config{EnablePreimageRecording: ctx.GlobalBool(VMEnableDebugFlag.Name)}
  1183  	chain, err = core.NewBlockChain(chainDb, cache, config, engine, vmcfg)
  1184  	if err != nil {
  1185  		Fatalf("Can't create BlockChain: %v", err)
  1186  	}
  1187  	return chain, chainDb
  1188  }
  1189  
  1190  // MakeConsolePreloads retrieves the absolute paths for the console JavaScript
  1191  // scripts to preload before starting.
  1192  func MakeConsolePreloads(ctx *cli.Context) []string {
  1193  	// Skip preloading if there's nothing to preload
  1194  	if ctx.GlobalString(PreloadJSFlag.Name) == "" {
  1195  		return nil
  1196  	}
  1197  	// Otherwise resolve absolute paths and return them
  1198  	preloads := []string{}
  1199  
  1200  	assets := ctx.GlobalString(JSpathFlag.Name)
  1201  	for _, file := range strings.Split(ctx.GlobalString(PreloadJSFlag.Name), ",") {
  1202  		preloads = append(preloads, common.AbsolutePath(assets, strings.TrimSpace(file)))
  1203  	}
  1204  	return preloads
  1205  }
  1206  
  1207  // MigrateFlags sets the global flag from a local flag when it's set.
  1208  // This is a temporary function used for migrating old command/flags to the
  1209  // new format.
  1210  //
  1211  // e.g. aquachain account new --keystore /tmp/mykeystore
  1212  //
  1213  // is equivalent after calling this method with:
  1214  //
  1215  // aquachain --keystore /tmp/mykeystore account new
  1216  //
  1217  // This allows the use of the existing configuration functionality.
  1218  // When all flags are migrated this function can be removed and the existing
  1219  // configuration functionality must be changed that is uses local flags
  1220  func MigrateFlags(action func(ctx *cli.Context) error) func(*cli.Context) error {
  1221  	return func(ctx *cli.Context) error {
  1222  		for _, name := range ctx.FlagNames() {
  1223  			if ctx.IsSet(name) {
  1224  				ctx.GlobalSet(name, ctx.String(name))
  1225  			}
  1226  		}
  1227  		return action(ctx)
  1228  	}
  1229  }