gitlab.com/aquachain/aquachain@v1.17.16-rc3.0.20221018032414-e3ddf1e1c055/cmd/utils/flags.go (about)

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