// Copyright 2015 The go-ethereum Authors // This file is part of go-ethereum. // // go-ethereum is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // go-ethereum is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with go-ethereum. If not, see . // Package utils contains internal helper functions for go-ethereum commands. package utils import ( "crypto/ecdsa" "fmt" "math" "math/big" "os" "path/filepath" "runtime" godebug "runtime/debug" "strconv" "strings" "github.com/XinFinOrg/XDPoSChain/XDCx" "github.com/XinFinOrg/XDPoSChain/accounts" "github.com/XinFinOrg/XDPoSChain/accounts/keystore" "github.com/XinFinOrg/XDPoSChain/common" "github.com/XinFinOrg/XDPoSChain/common/fdlimit" "github.com/XinFinOrg/XDPoSChain/consensus" "github.com/XinFinOrg/XDPoSChain/consensus/XDPoS" "github.com/XinFinOrg/XDPoSChain/consensus/ethash" "github.com/XinFinOrg/XDPoSChain/core" "github.com/XinFinOrg/XDPoSChain/core/vm" "github.com/XinFinOrg/XDPoSChain/crypto" "github.com/XinFinOrg/XDPoSChain/eth/downloader" "github.com/XinFinOrg/XDPoSChain/eth/ethconfig" "github.com/XinFinOrg/XDPoSChain/eth/filters" "github.com/XinFinOrg/XDPoSChain/eth/gasprice" "github.com/XinFinOrg/XDPoSChain/ethdb" "github.com/XinFinOrg/XDPoSChain/internal/ethapi" "github.com/XinFinOrg/XDPoSChain/log" "github.com/XinFinOrg/XDPoSChain/metrics" "github.com/XinFinOrg/XDPoSChain/metrics/exp" "github.com/XinFinOrg/XDPoSChain/node" "github.com/XinFinOrg/XDPoSChain/p2p" "github.com/XinFinOrg/XDPoSChain/p2p/discover" "github.com/XinFinOrg/XDPoSChain/p2p/discv5" "github.com/XinFinOrg/XDPoSChain/p2p/nat" "github.com/XinFinOrg/XDPoSChain/p2p/netutil" "github.com/XinFinOrg/XDPoSChain/params" "github.com/XinFinOrg/XDPoSChain/rpc" whisper "github.com/XinFinOrg/XDPoSChain/whisper/whisperv6" gopsutil "github.com/shirou/gopsutil/mem" "gopkg.in/urfave/cli.v1" ) var ( CommandHelpTemplate = `{{.cmd.Name}}{{if .cmd.Subcommands}} command{{end}}{{if .cmd.Flags}} [command options]{{end}} [arguments...] {{if .cmd.Description}}{{.cmd.Description}} {{end}}{{if .cmd.Subcommands}} SUBCOMMANDS: {{range .cmd.Subcommands}}{{.cmd.Name}}{{with .cmd.ShortName}}, {{.cmd}}{{end}}{{ "\t" }}{{.cmd.Usage}} {{end}}{{end}}{{if .categorizedFlags}} {{range $idx, $categorized := .categorizedFlags}}{{$categorized.Name}} OPTIONS: {{range $categorized.Flags}}{{"\t"}}{{.}} {{end}} {{end}}{{end}}` ) func init() { cli.AppHelpTemplate = `{{.Name}} {{if .Flags}}[global options] {{end}}command{{if .Flags}} [command options]{{end}} [arguments...] VERSION: {{.Version}} COMMANDS: {{range .Commands}}{{.Name}}{{with .ShortName}}, {{.}}{{end}}{{ "\t" }}{{.Usage}} {{end}}{{if .Flags}} GLOBAL OPTIONS: {{range .Flags}}{{.}} {{end}}{{end}} ` cli.CommandHelpTemplate = CommandHelpTemplate } // NewApp creates an app with sane defaults. func NewApp(gitCommit, usage string) *cli.App { app := cli.NewApp() app.Name = filepath.Base(os.Args[0]) app.Author = "" //app.Authors = nil app.Email = "" app.Version = params.Version if len(gitCommit) >= 8 { app.Version += "-" + gitCommit[:8] } app.Usage = usage return app } // These are all the command line flags we support. // If you add to this list, please remember to include the // flag in the appropriate command definition. // // The flags are defined here so their names and help texts // are the same for all commands. var ( // XDC flags. RollbackFlag = cli.StringFlag{ Name: "rollback", Usage: "Rollback chain at hash", Value: "", } Enable0xPrefixFlag = cli.BoolFlag{ Name: "enable-0x-prefix", Usage: "Addres use 0x-prefix (Deprecated: this is on by default, to use xdc prefix use --enable-xdc-prefix)", } EnableXDCPrefixFlag = cli.BoolFlag{ Name: "enable-xdc-prefix", Usage: "Addres use xdc-prefix (default = false)", } // General settings AnnounceTxsFlag = cli.BoolFlag{ Name: "announce-txs", Usage: "Always commit transactions", } StoreRewardFlag = cli.BoolFlag{ Name: "store-reward", Usage: "Store reward to file", } DataDirFlag = DirectoryFlag{ Name: "datadir", Usage: "Data directory for the databases and keystore", Value: DirectoryString{node.DefaultDataDir()}, } KeyStoreDirFlag = DirectoryFlag{ Name: "keystore", Usage: "Directory for the keystore (default = inside the datadir)", } NoUSBFlag = cli.BoolFlag{ Name: "nousb", Usage: "Disables monitoring for and managing USB hardware wallets", } NetworkIdFlag = cli.Uint64Flag{ Name: "networkid", Usage: "Network identifier (integer, 89=XDPoSChain)", Value: ethconfig.Defaults.NetworkId, } TestnetFlag = cli.BoolFlag{ Name: "testnet", Usage: "Ropsten network: pre-configured proof-of-work test network", } XDCTestnetFlag = cli.BoolFlag{ Name: "apothem", Usage: "XDC Apothem Network", } RinkebyFlag = cli.BoolFlag{ Name: "rinkeby", Usage: "Rinkeby network: pre-configured proof-of-authority test network", } DeveloperFlag = cli.BoolFlag{ Name: "dev", Usage: "Ephemeral proof-of-authority network with a pre-funded developer account, mining enabled", } DeveloperPeriodFlag = cli.IntFlag{ Name: "dev.period", Usage: "Block period to use in developer mode (0 = mine only if transaction pending)", } IdentityFlag = cli.StringFlag{ Name: "identity", Usage: "Custom node name", } DocRootFlag = DirectoryFlag{ Name: "docroot", Usage: "Document Root for HTTPClient file scheme", Value: DirectoryString{homeDir()}, } FastSyncFlag = cli.BoolFlag{ Name: "fast", Usage: "Enable fast syncing through state downloads", } LightModeFlag = cli.BoolFlag{ Name: "light", Usage: "Enable light client mode", } defaultSyncMode = ethconfig.Defaults.SyncMode SyncModeFlag = TextMarshalerFlag{ Name: "syncmode", Usage: `Blockchain sync mode ("fast", "full", or "light")`, Value: &defaultSyncMode, } GCModeFlag = cli.StringFlag{ Name: "gcmode", Usage: `Blockchain garbage collection mode ("full", "archive")`, Value: "full", } LightServFlag = cli.IntFlag{ Name: "lightserv", Usage: "Maximum percentage of time allowed for serving LES requests (0-90)", Value: 0, } LightPeersFlag = cli.IntFlag{ Name: "lightpeers", Usage: "Maximum number of LES client peers", Value: ethconfig.Defaults.LightPeers, } LightKDFFlag = cli.BoolFlag{ Name: "lightkdf", Usage: "Reduce key-derivation RAM & CPU usage at some expense of KDF strength", } // XDCX settings XDCXEnabledFlag = cli.BoolFlag{ Name: "XDCx", Usage: "Enable the XDCX protocol", } // Ethash settings EthashCacheDirFlag = DirectoryFlag{ Name: "ethash.cachedir", Usage: "Directory to store the ethash verification caches (default = inside the datadir)", } EthashCachesInMemoryFlag = cli.IntFlag{ Name: "ethash.cachesinmem", Usage: "Number of recent ethash caches to keep in memory (16MB each)", Value: ethconfig.Defaults.Ethash.CachesInMem, } EthashCachesOnDiskFlag = cli.IntFlag{ Name: "ethash.cachesondisk", Usage: "Number of recent ethash caches to keep on disk (16MB each)", Value: ethconfig.Defaults.Ethash.CachesOnDisk, } EthashDatasetDirFlag = DirectoryFlag{ Name: "ethash.dagdir", Usage: "Directory to store the ethash mining DAGs (default = inside home folder)", Value: DirectoryString{ethconfig.Defaults.Ethash.DatasetDir}, } EthashDatasetsInMemoryFlag = cli.IntFlag{ Name: "ethash.dagsinmem", Usage: "Number of recent ethash mining DAGs to keep in memory (1+GB each)", Value: ethconfig.Defaults.Ethash.DatasetsInMem, } EthashDatasetsOnDiskFlag = cli.IntFlag{ Name: "ethash.dagsondisk", Usage: "Number of recent ethash mining DAGs to keep on disk (1+GB each)", Value: ethconfig.Defaults.Ethash.DatasetsOnDisk, } // Transaction pool settings TxPoolNoLocalsFlag = cli.BoolFlag{ Name: "txpool.nolocals", Usage: "Disables price exemptions for locally submitted transactions", } TxPoolJournalFlag = cli.StringFlag{ Name: "txpool.journal", Usage: "Disk journal for local transaction to survive node restarts", Value: core.DefaultTxPoolConfig.Journal, } TxPoolRejournalFlag = cli.DurationFlag{ Name: "txpool.rejournal", Usage: "Time interval to regenerate the local transaction journal", Value: core.DefaultTxPoolConfig.Rejournal, } TxPoolPriceLimitFlag = cli.Uint64Flag{ Name: "txpool.pricelimit", Usage: "Minimum gas price limit to enforce for acceptance into the pool", Value: ethconfig.Defaults.TxPool.PriceLimit, } TxPoolPriceBumpFlag = cli.Uint64Flag{ Name: "txpool.pricebump", Usage: "Price bump percentage to replace an already existing transaction", Value: ethconfig.Defaults.TxPool.PriceBump, } TxPoolAccountSlotsFlag = cli.Uint64Flag{ Name: "txpool.accountslots", Usage: "Minimum number of executable transaction slots guaranteed per account", Value: ethconfig.Defaults.TxPool.AccountSlots, } TxPoolGlobalSlotsFlag = cli.Uint64Flag{ Name: "txpool.globalslots", Usage: "Maximum number of executable transaction slots for all accounts", Value: ethconfig.Defaults.TxPool.GlobalSlots, } TxPoolAccountQueueFlag = cli.Uint64Flag{ Name: "txpool.accountqueue", Usage: "Maximum number of non-executable transaction slots permitted per account", Value: ethconfig.Defaults.TxPool.AccountQueue, } TxPoolGlobalQueueFlag = cli.Uint64Flag{ Name: "txpool.globalqueue", Usage: "Maximum number of non-executable transaction slots for all accounts", Value: ethconfig.Defaults.TxPool.GlobalQueue, } TxPoolLifetimeFlag = cli.DurationFlag{ Name: "txpool.lifetime", Usage: "Maximum amount of time non-executable transaction are queued", Value: ethconfig.Defaults.TxPool.Lifetime, } // Performance tuning settings CacheFlag = cli.IntFlag{ Name: "cache", Usage: "Megabytes of memory allocated to internal caching", Value: 1024, } CacheDatabaseFlag = cli.IntFlag{ Name: "cache.database", Usage: "Percentage of cache memory allowance to use for database io", Value: 75, } CacheGCFlag = cli.IntFlag{ Name: "cache.gc", Usage: "Percentage of cache memory allowance to use for trie pruning", Value: 25, } CacheLogSizeFlag = &cli.IntFlag{ Name: "cache.blocklogs", Usage: "Size (in number of blocks) of the log cache for filtering", Value: ethconfig.Defaults.FilterLogCacheSize, } FDLimitFlag = cli.IntFlag{ Name: "fdlimit", Usage: "Raise the open file descriptor resource limit (default = system fd limit)", } // Miner settings StakingEnabledFlag = cli.BoolFlag{ Name: "mine", Usage: "Enable staking", } StakerThreadsFlag = cli.IntFlag{ Name: "minerthreads", Usage: "Number of CPU threads to use for staking", Value: runtime.NumCPU(), } TargetGasLimitFlag = cli.Uint64Flag{ Name: "targetgaslimit", Usage: "Target gas limit sets the artificial target gas floor for the blocks to mine", Value: params.XDCGenesisGasLimit, } EtherbaseFlag = cli.StringFlag{ Name: "etherbase", Usage: "Public address for block mining rewards (default = first account created)", Value: "0", } GasPriceFlag = BigFlag{ Name: "gasprice", Usage: "Minimal gas price to accept for mining a transactions", Value: ethconfig.Defaults.GasPrice, } ExtraDataFlag = cli.StringFlag{ Name: "extradata", Usage: "Block extra data set by the miner (default = client version)", } // Account settings UnlockedAccountFlag = cli.StringFlag{ Name: "unlock", Usage: "Comma separated list of accounts to unlock", Value: "", } PasswordFileFlag = cli.StringFlag{ Name: "password", Usage: "Password file to use for non-interactive password input", Value: "", } VMEnableDebugFlag = cli.BoolFlag{ Name: "vmdebug", Usage: "Record information useful for VM and contract debugging", } RPCGlobalGasCapFlag = cli.Uint64Flag{ Name: "rpc-gascap", Usage: "Sets a cap on gas that can be used in eth_call/estimateGas (0=infinite)", Value: ethconfig.Defaults.RPCGasCap, } RPCGlobalTxFeeCap = cli.Float64Flag{ Name: "rpc.txfeecap", Usage: "Sets a cap on transaction fee (in ether) that can be sent via the RPC APIs (0 = no cap)", Value: ethconfig.Defaults.RPCTxFeeCap, } // Logging and debug settings EthStatsURLFlag = cli.StringFlag{ Name: "ethstats", Usage: "Reporting URL of a ethstats service (nodename:secret@host:port)", } // MetricsHTTPFlag defines the endpoint for a stand-alone metrics HTTP endpoint. // Since the pprof service enables sensitive/vulnerable behavior, this allows a user // to enable a public-OK metrics endpoint without having to worry about ALSO exposing // other profiling behavior or information. MetricsHTTPFlag = cli.StringFlag{ Name: "metrics.addr", Usage: "Enable stand-alone metrics HTTP server listening interface", Value: metrics.DefaultConfig.HTTP, } MetricsPortFlag = cli.IntFlag{ Name: "metrics.port", Usage: "Metrics HTTP server listening port", Value: metrics.DefaultConfig.Port, } MetricsEnabledFlag = cli.BoolFlag{ Name: metrics.MetricsEnabledFlag, Usage: "Enable metrics collection and reporting", } FakePoWFlag = cli.BoolFlag{ Name: "fakepow", Usage: "Disables proof-of-work verification", } NoCompactionFlag = cli.BoolFlag{ Name: "nocompaction", Usage: "Disables db compaction after import", } // RPC settings RPCEnabledFlag = cli.BoolFlag{ Name: "rpc", Usage: "Enable the HTTP-RPC server", } RPCListenAddrFlag = cli.StringFlag{ Name: "rpcaddr", Usage: "HTTP-RPC server listening interface", Value: node.DefaultHTTPHost, } RewoundFlag = cli.IntFlag{ Name: "rewound", Usage: "Rewound blocks", Value: 0, } RPCPortFlag = cli.IntFlag{ Name: "rpcport", Usage: "HTTP-RPC server listening port", Value: node.DefaultHTTPPort, } RPCHttpWriteTimeoutFlag = cli.DurationFlag{ Name: "rpcwritetimeout", Usage: "HTTP-RPC server write timeout (default = 10s)", Value: node.DefaultHTTPWriteTimeOut, } RPCCORSDomainFlag = cli.StringFlag{ Name: "rpccorsdomain", Usage: "Comma separated list of domains from which to accept cross origin requests (browser enforced)", Value: "", } RPCVirtualHostsFlag = cli.StringFlag{ Name: "rpcvhosts", Usage: "Comma separated list of virtual hostnames from which to accept requests (server enforced). Accepts '*' wildcard.", Value: strings.Join(node.DefaultConfig.HTTPVirtualHosts, ","), } RPCApiFlag = cli.StringFlag{ Name: "rpcapi", Usage: "API's offered over the HTTP-RPC interface", Value: "", } IPCDisabledFlag = cli.BoolFlag{ Name: "ipcdisable", Usage: "Disable the IPC-RPC server", } IPCPathFlag = DirectoryFlag{ Name: "ipcpath", Usage: "Filename for IPC socket/pipe within the datadir (explicit paths escape it)", } WSEnabledFlag = cli.BoolFlag{ Name: "ws", Usage: "Enable the WS-RPC server", } WSListenAddrFlag = cli.StringFlag{ Name: "wsaddr", Usage: "WS-RPC server listening interface", Value: node.DefaultWSHost, } WSPortFlag = cli.IntFlag{ Name: "wsport", Usage: "WS-RPC server listening port", Value: node.DefaultWSPort, } WSApiFlag = cli.StringFlag{ Name: "wsapi", Usage: "API's offered over the WS-RPC interface", Value: "", } WSAllowedOriginsFlag = cli.StringFlag{ Name: "wsorigins", Usage: "Origins from which to accept websockets requests", Value: "", } ExecFlag = cli.StringFlag{ Name: "exec", Usage: "Execute JavaScript statement", } PreloadJSFlag = cli.StringFlag{ Name: "preload", Usage: "Comma separated list of JavaScript files to preload into the console", } // Network Settings MaxPeersFlag = cli.IntFlag{ Name: "maxpeers", Usage: "Maximum number of network peers (network disabled if set to 0)", Value: 25, } MaxPendingPeersFlag = cli.IntFlag{ Name: "maxpendpeers", Usage: "Maximum number of pending connection attempts (defaults used if set to 0)", Value: 0, } ListenPortFlag = cli.IntFlag{ Name: "port", Usage: "Network listening port", Value: 30303, } BootnodesFlag = cli.StringFlag{ Name: "bootnodes", Usage: "Comma separated enode URLs for P2P discovery bootstrap (set v4+v5 instead for light servers)", Value: "", } BootnodesV4Flag = cli.StringFlag{ Name: "bootnodesv4", Usage: "Comma separated enode URLs for P2P v4 discovery bootstrap (light server, full nodes)", Value: "", } BootnodesV5Flag = cli.StringFlag{ Name: "bootnodesv5", Usage: "Comma separated enode URLs for P2P v5 discovery bootstrap (light server, light nodes)", Value: "", } NodeKeyFileFlag = cli.StringFlag{ Name: "nodekey", Usage: "P2P node key file", } NodeKeyHexFlag = cli.StringFlag{ Name: "nodekeyhex", Usage: "P2P node key as hex (for testing)", } NATFlag = cli.StringFlag{ Name: "nat", Usage: "NAT port mapping mechanism (any|none|upnp|pmp|extip:)", Value: "any", } NoDiscoverFlag = cli.BoolFlag{ Name: "nodiscover", Usage: "Disables the peer discovery mechanism (manual peer addition)", } DiscoveryV5Flag = cli.BoolFlag{ Name: "v5disc", Usage: "Enables the experimental RLPx V5 (Topic Discovery) mechanism", } NetrestrictFlag = cli.StringFlag{ Name: "netrestrict", Usage: "Restricts network communication to the given IP networks (CIDR masks)", } // ATM the url is left to the user and deployment to JSpathFlag = cli.StringFlag{ Name: "jspath", Usage: "JavaScript root path for `loadScript`", Value: ".", } // Gas price oracle settings GpoBlocksFlag = cli.IntFlag{ Name: "gpoblocks", Usage: "Number of recent blocks to check for gas prices", Value: ethconfig.Defaults.GPO.Blocks, } GpoPercentileFlag = cli.IntFlag{ Name: "gpopercentile", Usage: "Suggested gas price is the given percentile of a set of recent transaction gas prices", Value: ethconfig.Defaults.GPO.Percentile, } GpoMaxGasPriceFlag = cli.Int64Flag{ Name: "gpo.maxprice", Usage: "Maximum gas price will be recommended by gpo", Value: ethconfig.Defaults.GPO.MaxPrice.Int64(), } GpoIgnoreGasPriceFlag = cli.Int64Flag{ Name: "gpo.ignoreprice", Usage: "Gas price below which gpo will ignore transactions", Value: ethconfig.Defaults.GPO.IgnorePrice.Int64(), } WhisperEnabledFlag = cli.BoolFlag{ Name: "shh", Usage: "Enable Whisper", } WhisperMaxMessageSizeFlag = cli.IntFlag{ Name: "shh.maxmessagesize", Usage: "Max message size accepted", Value: int(whisper.DefaultMaxMessageSize), } WhisperMinPOWFlag = cli.Float64Flag{ Name: "shh.pow", Usage: "Minimum POW accepted", Value: whisper.DefaultMinimumPoW, } XDCXDataDirFlag = DirectoryFlag{ Name: "XDCx.datadir", Usage: "Data directory for the XDCX databases", Value: DirectoryString{filepath.Join(DataDirFlag.Value.String(), "XDCx")}, } XDCXDBEngineFlag = cli.StringFlag{ Name: "XDCx.dbengine", Usage: "Database engine for XDCX (leveldb, mongodb)", Value: "leveldb", } XDCXDBNameFlag = cli.StringFlag{ Name: "XDCx.dbName", Usage: "Database name for XDCX", Value: "XDCdex", } XDCXDBConnectionUrlFlag = cli.StringFlag{ Name: "XDCx.dbConnectionUrl", Usage: "ConnectionUrl to database if dbEngine is mongodb. Host:port. If there are multiple instances, separated by comma. Eg: localhost:27017,localhost:27018", Value: "localhost:27017", } XDCXDBReplicaSetNameFlag = cli.StringFlag{ Name: "XDCx.dbReplicaSetName", Usage: "ReplicaSetName if Master-Slave is setup", } XDCSlaveModeFlag = cli.BoolFlag{ Name: "slave", Usage: "Enable slave mode", } ) // MakeDataDir retrieves the currently requested data directory, terminating // if none (or the empty string) is specified. If the node is starting a testnet, // the a subdirectory of the specified datadir will be used. func MakeDataDir(ctx *cli.Context) string { if path := ctx.GlobalString(DataDirFlag.Name); path != "" { if ctx.GlobalBool(TestnetFlag.Name) { return filepath.Join(path, "testnet") } if ctx.GlobalBool(RinkebyFlag.Name) { return filepath.Join(path, "rinkeby") } return path } Fatalf("Cannot determine default data directory, please set manually (--datadir)") return "" } // setNodeKey creates a node key from set command line flags, either loading it // from a file or as a specified hex value. If neither flags were provided, this // method returns nil and an emphemeral key is to be generated. func setNodeKey(ctx *cli.Context, cfg *p2p.Config) { var ( hex = ctx.GlobalString(NodeKeyHexFlag.Name) file = ctx.GlobalString(NodeKeyFileFlag.Name) key *ecdsa.PrivateKey err error ) switch { case file != "" && hex != "": Fatalf("Options %q and %q are mutually exclusive", NodeKeyFileFlag.Name, NodeKeyHexFlag.Name) case file != "": if key, err = crypto.LoadECDSA(file); err != nil { Fatalf("Option %q: %v", NodeKeyFileFlag.Name, err) } cfg.PrivateKey = key case hex != "": if key, err = crypto.HexToECDSA(hex); err != nil { Fatalf("Option %q: %v", NodeKeyHexFlag.Name, err) } cfg.PrivateKey = key } } // setNodeUserIdent creates the user identifier from CLI flags. func setNodeUserIdent(ctx *cli.Context, cfg *node.Config) { if identity := ctx.GlobalString(IdentityFlag.Name); len(identity) > 0 { cfg.UserIdent = identity } } // setBootstrapNodes creates a list of bootstrap nodes from the command line // flags, reverting to pre-configured ones if none have been specified. func setBootstrapNodes(ctx *cli.Context, cfg *p2p.Config) { urls := []string{} switch { case ctx.GlobalIsSet(BootnodesFlag.Name) || ctx.GlobalIsSet(BootnodesV4Flag.Name): if ctx.GlobalIsSet(BootnodesV4Flag.Name) { urls = strings.Split(ctx.GlobalString(BootnodesV4Flag.Name), ",") } else { urls = strings.Split(ctx.GlobalString(BootnodesFlag.Name), ",") } // case ctx.GlobalBool(TestnetFlag.Name): // urls = params.TestnetBootnodes // case ctx.GlobalBool(RinkebyFlag.Name): // urls = params.RinkebyBootnodes case cfg.BootstrapNodes != nil: return // already set, don't apply defaults. case !ctx.GlobalIsSet(BootnodesFlag.Name): urls = params.MainnetBootnodes case ctx.GlobalBool(XDCTestnetFlag.Name): urls = params.TestnetBootnodes } cfg.BootstrapNodes = make([]*discover.Node, 0, len(urls)) for _, url := range urls { node, err := discover.ParseNode(url) if err != nil { log.Error("Bootstrap URL invalid", "enode", url, "err", err) continue } cfg.BootstrapNodes = append(cfg.BootstrapNodes, node) } } // setBootstrapNodesV5 creates a list of bootstrap nodes from the command line // flags, reverting to pre-configured ones if none have been specified. func setBootstrapNodesV5(ctx *cli.Context, cfg *p2p.Config) { urls := params.DiscoveryV5Bootnodes switch { case ctx.GlobalIsSet(BootnodesFlag.Name) || ctx.GlobalIsSet(BootnodesV5Flag.Name): if ctx.GlobalIsSet(BootnodesV5Flag.Name) { urls = strings.Split(ctx.GlobalString(BootnodesV5Flag.Name), ",") } else { urls = strings.Split(ctx.GlobalString(BootnodesFlag.Name), ",") } case ctx.GlobalBool(RinkebyFlag.Name): urls = params.RinkebyBootnodes case cfg.BootstrapNodesV5 != nil: return // already set, don't apply defaults. } cfg.BootstrapNodesV5 = make([]*discv5.Node, 0, len(urls)) for _, url := range urls { node, err := discv5.ParseNode(url) if err != nil { log.Error("Bootstrap URL invalid", "enode", url, "err", err) continue } cfg.BootstrapNodesV5 = append(cfg.BootstrapNodesV5, node) } } // setListenAddress creates a TCP listening address string from set command // line flags. func setListenAddress(ctx *cli.Context, cfg *p2p.Config) { if ctx.GlobalIsSet(ListenPortFlag.Name) { cfg.ListenAddr = fmt.Sprintf(":%d", ctx.GlobalInt(ListenPortFlag.Name)) } } // setNAT creates a port mapper from command line flags. func setNAT(ctx *cli.Context, cfg *p2p.Config) { if ctx.GlobalIsSet(NATFlag.Name) { log.Info("NAT is setted", "value", ctx.GlobalString(NATFlag.Name)) natif, err := nat.Parse(ctx.GlobalString(NATFlag.Name)) if err != nil { Fatalf("Option %s: %v", NATFlag.Name, err) } cfg.NAT = natif } } // splitAndTrim splits input separated by a comma // and trims excessive white space from the substrings. func splitAndTrim(input string) []string { result := strings.Split(input, ",") for i, r := range result { result[i] = strings.TrimSpace(r) } return result } // setHTTP creates the HTTP RPC listener interface string from the set // command line flags, returning empty if the HTTP endpoint is disabled. func setHTTP(ctx *cli.Context, cfg *node.Config) { if ctx.GlobalBool(RPCEnabledFlag.Name) && cfg.HTTPHost == "" { cfg.HTTPHost = "127.0.0.1" if ctx.GlobalIsSet(RPCListenAddrFlag.Name) { cfg.HTTPHost = ctx.GlobalString(RPCListenAddrFlag.Name) } } if ctx.GlobalIsSet(RPCPortFlag.Name) { cfg.HTTPPort = ctx.GlobalInt(RPCPortFlag.Name) } if ctx.GlobalIsSet(RPCHttpWriteTimeoutFlag.Name) { cfg.HTTPWriteTimeout = ctx.GlobalDuration(RPCHttpWriteTimeoutFlag.Name) } if ctx.GlobalIsSet(RPCCORSDomainFlag.Name) { cfg.HTTPCors = splitAndTrim(ctx.GlobalString(RPCCORSDomainFlag.Name)) } if ctx.GlobalIsSet(RPCApiFlag.Name) { cfg.HTTPModules = splitAndTrim(ctx.GlobalString(RPCApiFlag.Name)) } if ctx.GlobalIsSet(RPCVirtualHostsFlag.Name) { cfg.HTTPVirtualHosts = splitAndTrim(ctx.GlobalString(RPCVirtualHostsFlag.Name)) } } // setWS creates the WebSocket RPC listener interface string from the set // command line flags, returning empty if the HTTP endpoint is disabled. func setWS(ctx *cli.Context, cfg *node.Config) { if ctx.GlobalBool(WSEnabledFlag.Name) && cfg.WSHost == "" { cfg.WSHost = "127.0.0.1" if ctx.GlobalIsSet(WSListenAddrFlag.Name) { cfg.WSHost = ctx.GlobalString(WSListenAddrFlag.Name) } } if ctx.GlobalIsSet(WSPortFlag.Name) { cfg.WSPort = ctx.GlobalInt(WSPortFlag.Name) } if ctx.GlobalIsSet(WSAllowedOriginsFlag.Name) { cfg.WSOrigins = splitAndTrim(ctx.GlobalString(WSAllowedOriginsFlag.Name)) } if ctx.GlobalIsSet(WSApiFlag.Name) { cfg.WSModules = splitAndTrim(ctx.GlobalString(WSApiFlag.Name)) } } // setIPC creates an IPC path configuration from the set command line flags, // returning an empty string if IPC was explicitly disabled, or the set path. func setIPC(ctx *cli.Context, cfg *node.Config) { checkExclusive(ctx, IPCDisabledFlag, IPCPathFlag) switch { case ctx.GlobalBool(IPCDisabledFlag.Name): cfg.IPCPath = "" case ctx.GlobalIsSet(IPCPathFlag.Name): cfg.IPCPath = ctx.GlobalString(IPCPathFlag.Name) } } func setPrefix(ctx *cli.Context, cfg *node.Config) { checkExclusive(ctx, Enable0xPrefixFlag, EnableXDCPrefixFlag) } // MakeDatabaseHandles raises out the number of allowed file handles per process // for XDC and returns half of the allowance to assign to the database. func MakeDatabaseHandles(max int) int { limit, err := fdlimit.Maximum() if err != nil { Fatalf("Failed to retrieve file descriptor allowance: %v", err) } switch { case max == 0: // User didn't specify a meaningful value, use system limits case max < 128: // User specified something unhealthy, just use system defaults log.Error("File descriptor limit invalid (<128)", "had", max, "updated", limit) case max > limit: // User requested more than the OS allows, notify that we can't allocate it log.Warn("Requested file descriptors denied by OS", "req", max, "limit", limit) default: // User limit is meaningful and within allowed range, use that limit = max } raised, err := fdlimit.Raise(uint64(limit)) if err != nil { Fatalf("Failed to raise file descriptor allowance: %v", err) } return int(raised / 2) // Leave half for networking and other stuff } // MakeAddress converts an account specified directly as a hex encoded string or // a key index in the key store to an internal account representation. func MakeAddress(ks *keystore.KeyStore, account string) (accounts.Account, error) { // If the specified account is a valid address, return it if common.IsHexAddress(account) { return accounts.Account{Address: common.HexToAddress(account)}, nil } // Otherwise try to interpret the account as a keystore index index, err := strconv.Atoi(account) if err != nil || index < 0 { return accounts.Account{}, fmt.Errorf("invalid account address or index %q", account) } log.Warn("-------------------------------------------------------------------") log.Warn("Referring to accounts by order in the keystore folder is dangerous!") log.Warn("This functionality is deprecated and will be removed in the future!") log.Warn("Please use explicit addresses! (can search via `XDC account list`)") log.Warn("-------------------------------------------------------------------") accs := ks.Accounts() if len(accs) <= index { return accounts.Account{}, fmt.Errorf("index %d higher than number of accounts %d", index, len(accs)) } return accs[index], nil } // setEtherbase retrieves the etherbase either from the directly specified // command line flags or from the keystore if CLI indexed. func setEtherbase(ctx *cli.Context, ks *keystore.KeyStore, cfg *ethconfig.Config) { if ctx.GlobalIsSet(EtherbaseFlag.Name) { account, err := MakeAddress(ks, ctx.GlobalString(EtherbaseFlag.Name)) if err != nil { Fatalf("Option %q: %v", EtherbaseFlag.Name, err) } cfg.Etherbase = account.Address } } // MakePasswordList reads password lines from the file specified by the global --password flag. func MakePasswordList(ctx *cli.Context) []string { path := ctx.GlobalString(PasswordFileFlag.Name) if path == "" { return nil } text, err := os.ReadFile(path) if err != nil { Fatalf("Failed to read password file: %v", err) } lines := strings.Split(string(text), "\n") // Sanitise DOS line endings. for i := range lines { lines[i] = strings.TrimRight(lines[i], "\r") } return lines } func SetP2PConfig(ctx *cli.Context, cfg *p2p.Config) { setNodeKey(ctx, cfg) setNAT(ctx, cfg) setListenAddress(ctx, cfg) setBootstrapNodes(ctx, cfg) // setBootstrapNodesV5(ctx, cfg) lightClient := ctx.GlobalBool(LightModeFlag.Name) || ctx.GlobalString(SyncModeFlag.Name) == "light" lightServer := ctx.GlobalInt(LightServFlag.Name) != 0 lightPeers := ctx.GlobalInt(LightPeersFlag.Name) if ctx.GlobalIsSet(MaxPeersFlag.Name) { cfg.MaxPeers = ctx.GlobalInt(MaxPeersFlag.Name) if lightServer && !ctx.GlobalIsSet(LightPeersFlag.Name) { cfg.MaxPeers += lightPeers } } else { if lightServer { cfg.MaxPeers += lightPeers } if lightClient && ctx.GlobalIsSet(LightPeersFlag.Name) && cfg.MaxPeers < lightPeers { cfg.MaxPeers = lightPeers } } if !(lightClient || lightServer) { lightPeers = 0 } ethPeers := cfg.MaxPeers - lightPeers if lightClient { ethPeers = 0 } log.Info("Maximum peer count", "ETH", ethPeers, "LES", lightPeers, "total", cfg.MaxPeers) if ctx.GlobalIsSet(MaxPendingPeersFlag.Name) { cfg.MaxPendingPeers = ctx.GlobalInt(MaxPendingPeersFlag.Name) } if ctx.GlobalIsSet(NoDiscoverFlag.Name) || lightClient { cfg.NoDiscovery = true } // if we're running a light client or server, force enable the v5 peer discovery // unless it is explicitly disabled with --nodiscover note that explicitly specifying // --v5disc overrides --nodiscover, in which case the later only disables v4 discovery forceV5Discovery := (lightClient || lightServer) && !ctx.GlobalBool(NoDiscoverFlag.Name) if ctx.GlobalIsSet(DiscoveryV5Flag.Name) { cfg.DiscoveryV5 = ctx.GlobalBool(DiscoveryV5Flag.Name) } else if forceV5Discovery { cfg.DiscoveryV5 = true } if netrestrict := ctx.GlobalString(NetrestrictFlag.Name); netrestrict != "" { list, err := netutil.ParseNetlist(netrestrict) if err != nil { Fatalf("Option %q: %v", NetrestrictFlag.Name, err) } cfg.NetRestrict = list } if ctx.GlobalBool(DeveloperFlag.Name) { // --dev mode can't use p2p networking. cfg.MaxPeers = 0 cfg.ListenAddr = ":0" cfg.NoDiscovery = true cfg.DiscoveryV5 = false } } // SetNodeConfig applies node-related command line flags to the config. func SetNodeConfig(ctx *cli.Context, cfg *node.Config) { SetP2PConfig(ctx, &cfg.P2P) setIPC(ctx, cfg) setHTTP(ctx, cfg) setWS(ctx, cfg) setNodeUserIdent(ctx, cfg) setPrefix(ctx, cfg) switch { case ctx.GlobalIsSet(DataDirFlag.Name): cfg.DataDir = ctx.GlobalString(DataDirFlag.Name) case ctx.GlobalBool(DeveloperFlag.Name): cfg.DataDir = "" // unless explicitly requested, use memory databases case ctx.GlobalBool(TestnetFlag.Name): cfg.DataDir = filepath.Join(node.DefaultDataDir(), "testnet") case ctx.GlobalBool(RinkebyFlag.Name): cfg.DataDir = filepath.Join(node.DefaultDataDir(), "rinkeby") } if ctx.GlobalIsSet(KeyStoreDirFlag.Name) { cfg.KeyStoreDir = ctx.GlobalString(KeyStoreDirFlag.Name) } if ctx.GlobalIsSet(LightKDFFlag.Name) { cfg.UseLightweightKDF = ctx.GlobalBool(LightKDFFlag.Name) } if ctx.GlobalIsSet(NoUSBFlag.Name) { cfg.NoUSB = ctx.GlobalBool(NoUSBFlag.Name) } if ctx.GlobalIsSet(AnnounceTxsFlag.Name) { cfg.AnnounceTxs = ctx.GlobalBool(AnnounceTxsFlag.Name) } } func setGPO(ctx *cli.Context, cfg *gasprice.Config, light bool) { // If we are running the light client, apply another group // settings for gas oracle. if light { cfg.Blocks = ethconfig.LightClientGPO.Blocks cfg.Percentile = ethconfig.LightClientGPO.Percentile } if ctx.GlobalIsSet(GpoBlocksFlag.Name) { cfg.Blocks = ctx.GlobalInt(GpoBlocksFlag.Name) } if ctx.GlobalIsSet(GpoPercentileFlag.Name) { cfg.Percentile = ctx.GlobalInt(GpoPercentileFlag.Name) } if ctx.GlobalIsSet(GpoMaxGasPriceFlag.Name) { cfg.MaxPrice = big.NewInt(ctx.GlobalInt64(GpoMaxGasPriceFlag.Name)) } if ctx.GlobalIsSet(GpoIgnoreGasPriceFlag.Name) { cfg.IgnorePrice = big.NewInt(ctx.GlobalInt64(GpoIgnoreGasPriceFlag.Name)) } } func setTxPool(ctx *cli.Context, cfg *core.TxPoolConfig) { if ctx.GlobalIsSet(TxPoolNoLocalsFlag.Name) { cfg.NoLocals = ctx.GlobalBool(TxPoolNoLocalsFlag.Name) } if ctx.GlobalIsSet(TxPoolJournalFlag.Name) { cfg.Journal = ctx.GlobalString(TxPoolJournalFlag.Name) } if ctx.GlobalIsSet(TxPoolRejournalFlag.Name) { cfg.Rejournal = ctx.GlobalDuration(TxPoolRejournalFlag.Name) } if ctx.GlobalIsSet(TxPoolPriceLimitFlag.Name) { cfg.PriceLimit = ctx.GlobalUint64(TxPoolPriceLimitFlag.Name) } if ctx.GlobalIsSet(TxPoolPriceBumpFlag.Name) { cfg.PriceBump = ctx.GlobalUint64(TxPoolPriceBumpFlag.Name) } if ctx.GlobalIsSet(TxPoolAccountSlotsFlag.Name) { cfg.AccountSlots = ctx.GlobalUint64(TxPoolAccountSlotsFlag.Name) } if ctx.GlobalIsSet(TxPoolGlobalSlotsFlag.Name) { cfg.GlobalSlots = ctx.GlobalUint64(TxPoolGlobalSlotsFlag.Name) } if ctx.GlobalIsSet(TxPoolAccountQueueFlag.Name) { cfg.AccountQueue = ctx.GlobalUint64(TxPoolAccountQueueFlag.Name) } if ctx.GlobalIsSet(TxPoolGlobalQueueFlag.Name) { cfg.GlobalQueue = ctx.GlobalUint64(TxPoolGlobalQueueFlag.Name) } if ctx.GlobalIsSet(TxPoolLifetimeFlag.Name) { cfg.Lifetime = ctx.GlobalDuration(TxPoolLifetimeFlag.Name) } } func setEthash(ctx *cli.Context, cfg *ethconfig.Config) { if ctx.GlobalIsSet(EthashCacheDirFlag.Name) { cfg.Ethash.CacheDir = ctx.GlobalString(EthashCacheDirFlag.Name) } if ctx.GlobalIsSet(EthashDatasetDirFlag.Name) { cfg.Ethash.DatasetDir = ctx.GlobalString(EthashDatasetDirFlag.Name) } if ctx.GlobalIsSet(EthashCachesInMemoryFlag.Name) { cfg.Ethash.CachesInMem = ctx.GlobalInt(EthashCachesInMemoryFlag.Name) } if ctx.GlobalIsSet(EthashCachesOnDiskFlag.Name) { cfg.Ethash.CachesOnDisk = ctx.GlobalInt(EthashCachesOnDiskFlag.Name) } if ctx.GlobalIsSet(EthashDatasetsInMemoryFlag.Name) { cfg.Ethash.DatasetsInMem = ctx.GlobalInt(EthashDatasetsInMemoryFlag.Name) } if ctx.GlobalIsSet(EthashDatasetsOnDiskFlag.Name) { cfg.Ethash.DatasetsOnDisk = ctx.GlobalInt(EthashDatasetsOnDiskFlag.Name) } } // checkExclusive verifies that only a single isntance of the provided flags was // set by the user. Each flag might optionally be followed by a string type to // specialize it further. func checkExclusive(ctx *cli.Context, args ...interface{}) { set := make([]string, 0, 1) for i := 0; i < len(args); i++ { // Make sure the next argument is a flag and skip if not set flag, ok := args[i].(cli.Flag) if !ok { panic(fmt.Sprintf("invalid argument, not cli.Flag type: %T", args[i])) } // Check if next arg extends current and expand its name if so name := flag.GetName() if i+1 < len(args) { switch option := args[i+1].(type) { case string: // Extended flag, expand the name and shift the arguments if ctx.GlobalString(flag.GetName()) == option { name += "=" + option } i++ case cli.Flag: default: panic(fmt.Sprintf("invalid argument, not cli.Flag or string extension: %T", args[i+1])) } } // Mark the flag if it's set if ctx.GlobalIsSet(flag.GetName()) { set = append(set, "--"+name) } } if len(set) > 1 { Fatalf("Flags %v can't be used at the same time", strings.Join(set, ", ")) } } // SetShhConfig applies shh-related command line flags to the config. func SetShhConfig(ctx *cli.Context, stack *node.Node, cfg *whisper.Config) { if ctx.GlobalIsSet(WhisperMaxMessageSizeFlag.Name) { cfg.MaxMessageSize = uint32(ctx.GlobalUint(WhisperMaxMessageSizeFlag.Name)) } if ctx.GlobalIsSet(WhisperMinPOWFlag.Name) { cfg.MinimumAcceptedPOW = ctx.GlobalFloat64(WhisperMinPOWFlag.Name) } } func SetXDCXConfig(ctx *cli.Context, cfg *XDCx.Config, XDCDataDir string) { if ctx.GlobalIsSet(XDCXDataDirFlag.Name) { cfg.DataDir = ctx.GlobalString(XDCXDataDirFlag.Name) } else { // default XDCx datadir: DATADIR/XDCx defaultXDCXDataDir := filepath.Join(XDCDataDir, "XDCx") filesInXDCXDefaultDir, _ := WalkMatch(defaultXDCXDataDir, "*.ldb") filesInNodeDefaultDir, _ := WalkMatch(node.DefaultDataDir(), "*.ldb") if len(filesInXDCXDefaultDir) == 0 && len(filesInNodeDefaultDir) > 0 { cfg.DataDir = node.DefaultDataDir() } else { cfg.DataDir = defaultXDCXDataDir } } log.Info("XDCX datadir", "path", cfg.DataDir) if ctx.GlobalIsSet(XDCXDBEngineFlag.Name) { cfg.DBEngine = ctx.GlobalString(XDCXDBEngineFlag.Name) } else { cfg.DBEngine = XDCXDBEngineFlag.Value } if ctx.GlobalIsSet(XDCXDBNameFlag.Name) { cfg.DBName = ctx.GlobalString(XDCXDBNameFlag.Name) } else { cfg.DBName = XDCXDBNameFlag.Value } if ctx.GlobalIsSet(XDCXDBConnectionUrlFlag.Name) { cfg.ConnectionUrl = ctx.GlobalString(XDCXDBConnectionUrlFlag.Name) } else { cfg.ConnectionUrl = XDCXDBConnectionUrlFlag.Value } if ctx.GlobalIsSet(XDCXDBReplicaSetNameFlag.Name) { cfg.ReplicaSetName = ctx.GlobalString(XDCXDBReplicaSetNameFlag.Name) } } // SetEthConfig applies eth-related command line flags to the config. func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) { // Avoid conflicting network flags checkExclusive(ctx, DeveloperFlag, TestnetFlag, RinkebyFlag) checkExclusive(ctx, FastSyncFlag, LightModeFlag, SyncModeFlag) checkExclusive(ctx, LightServFlag, LightModeFlag) checkExclusive(ctx, LightServFlag, SyncModeFlag, "light") ks := stack.AccountManager().Backends(keystore.KeyStoreType)[0].(*keystore.KeyStore) setEtherbase(ctx, ks, cfg) setGPO(ctx, &cfg.GPO, ctx.GlobalString(SyncModeFlag.Name) == "light") setTxPool(ctx, &cfg.TxPool) setEthash(ctx, cfg) // Cap the cache allowance and tune the garbage collector mem, err := gopsutil.VirtualMemory() if err == nil { if 32<<(^uintptr(0)>>63) == 32 && mem.Total > 2*1024*1024*1024 { log.Warn("Lowering memory allowance on 32bit arch", "available", mem.Total/1024/1024, "addressable", 2*1024) mem.Total = 2 * 1024 * 1024 * 1024 } allowance := int(mem.Total / 1024 / 1024 / 3) if cache := ctx.Int(CacheFlag.Name); cache > allowance { log.Warn("Sanitizing cache to Go's GC limits", "provided", cache, "updated", allowance) ctx.Set(CacheFlag.Name, strconv.Itoa(allowance)) } } // Ensure Go's GC ignores the database cache for trigger percentage cache := ctx.Int(CacheFlag.Name) gogc := math.Max(20, math.Min(100, 100/(float64(cache)/1024))) log.Debug("Sanitizing Go's GC trigger", "percent", int(gogc)) godebug.SetGCPercent(int(gogc)) switch { case ctx.GlobalIsSet(SyncModeFlag.Name): cfg.SyncMode = *GlobalTextMarshaler(ctx, SyncModeFlag.Name).(*downloader.SyncMode) case ctx.GlobalBool(FastSyncFlag.Name): cfg.SyncMode = downloader.FastSync case ctx.GlobalBool(LightModeFlag.Name): cfg.SyncMode = downloader.LightSync } if ctx.GlobalIsSet(LightServFlag.Name) { cfg.LightServ = ctx.GlobalInt(LightServFlag.Name) } if ctx.GlobalIsSet(LightPeersFlag.Name) { cfg.LightPeers = ctx.GlobalInt(LightPeersFlag.Name) } if ctx.GlobalIsSet(NetworkIdFlag.Name) { cfg.NetworkId = ctx.GlobalUint64(NetworkIdFlag.Name) } if ctx.GlobalIsSet(CacheFlag.Name) || ctx.GlobalIsSet(CacheDatabaseFlag.Name) { cfg.DatabaseCache = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheDatabaseFlag.Name) / 100 } cfg.DatabaseHandles = MakeDatabaseHandles(ctx.GlobalInt(FDLimitFlag.Name)) if gcmode := ctx.GlobalString(GCModeFlag.Name); gcmode != "full" && gcmode != "archive" { Fatalf("--%s must be either 'full' or 'archive'", GCModeFlag.Name) } cfg.NoPruning = ctx.GlobalString(GCModeFlag.Name) == "archive" if ctx.GlobalIsSet(CacheFlag.Name) || ctx.GlobalIsSet(CacheGCFlag.Name) { cfg.TrieCache = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheGCFlag.Name) / 100 } if ctx.GlobalIsSet(StakerThreadsFlag.Name) { cfg.MinerThreads = ctx.GlobalInt(StakerThreadsFlag.Name) } if ctx.GlobalIsSet(DocRootFlag.Name) { cfg.DocRoot = ctx.GlobalString(DocRootFlag.Name) } if ctx.GlobalIsSet(RPCGlobalGasCapFlag.Name) { cfg.RPCGasCap = ctx.GlobalUint64(RPCGlobalGasCapFlag.Name) } if ctx.GlobalIsSet(RPCGlobalTxFeeCap.Name) { cfg.RPCTxFeeCap = ctx.GlobalFloat64(RPCGlobalTxFeeCap.Name) } if ctx.GlobalIsSet(RPCGlobalGasCapFlag.Name) { cfg.RPCGasCap = ctx.GlobalUint64(RPCGlobalGasCapFlag.Name) } if ctx.GlobalIsSet(ExtraDataFlag.Name) { cfg.ExtraData = []byte(ctx.GlobalString(ExtraDataFlag.Name)) } if ctx.GlobalIsSet(GasPriceFlag.Name) { cfg.GasPrice = GlobalBig(ctx, GasPriceFlag.Name) } if ctx.IsSet(CacheLogSizeFlag.Name) { cfg.FilterLogCacheSize = ctx.Int(CacheLogSizeFlag.Name) } if ctx.GlobalIsSet(VMEnableDebugFlag.Name) { // TODO(fjl): force-enable this in --dev mode cfg.EnablePreimageRecording = ctx.GlobalBool(VMEnableDebugFlag.Name) } if cfg.RPCGasCap != 0 { log.Info("Set global gas cap", "cap", cfg.RPCGasCap) } else { log.Info("Global gas cap disabled") } if ctx.GlobalIsSet(StoreRewardFlag.Name) { common.StoreRewardFolder = filepath.Join(stack.DataDir(), "XDC", "rewards") if _, err := os.Stat(common.StoreRewardFolder); os.IsNotExist(err) { os.Mkdir(common.StoreRewardFolder, os.ModePerm) } } // Override any default configs for hard coded networks. switch { case ctx.GlobalBool(TestnetFlag.Name): if !ctx.GlobalIsSet(NetworkIdFlag.Name) { cfg.NetworkId = 3 } cfg.Genesis = core.DefaultTestnetGenesisBlock() case ctx.GlobalBool(RinkebyFlag.Name): if !ctx.GlobalIsSet(NetworkIdFlag.Name) { cfg.NetworkId = 4 } cfg.Genesis = core.DefaultRinkebyGenesisBlock() case ctx.GlobalBool(DeveloperFlag.Name): // Create new developer account or reuse existing one var ( developer accounts.Account err error ) if accs := ks.Accounts(); len(accs) > 0 { developer = ks.Accounts()[0] } else { developer, err = ks.NewAccount("") if err != nil { Fatalf("Failed to create developer account: %v", err) } } if err := ks.Unlock(developer, ""); err != nil { Fatalf("Failed to unlock developer account: %v", err) } log.Info("Using developer account", "address", developer.Address) cfg.Genesis = core.DeveloperGenesisBlock(uint64(ctx.GlobalInt(DeveloperPeriodFlag.Name)), developer.Address) if !ctx.GlobalIsSet(GasPriceFlag.Name) { cfg.GasPrice = big.NewInt(1) } } // TODO(fjl): move trie cache generations into config } // SetupNetwork configures the system for either the main net or some test network. func SetupNetwork(ctx *cli.Context) { // TODO(fjl): move target gas limit into config params.TargetGasLimit = ctx.GlobalUint64(TargetGasLimitFlag.Name) } // MakeChainDatabase open an LevelDB using the flags passed to the client and will hard crash if it fails. func MakeChainDatabase(ctx *cli.Context, stack *node.Node) ethdb.Database { var ( cache = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheDatabaseFlag.Name) / 100 handles = MakeDatabaseHandles(ctx.GlobalInt(FDLimitFlag.Name)) ) name := "chaindata" if ctx.GlobalBool(LightModeFlag.Name) { name = "lightchaindata" } chainDb, err := stack.OpenDatabase(name, cache, handles, "") if err != nil { Fatalf("Could not open database: %v", err) } return chainDb } func MakeGenesis(ctx *cli.Context) *core.Genesis { var genesis *core.Genesis switch { case ctx.GlobalBool(TestnetFlag.Name): genesis = core.DefaultTestnetGenesisBlock() case ctx.GlobalBool(RinkebyFlag.Name): genesis = core.DefaultRinkebyGenesisBlock() case ctx.GlobalBool(DeveloperFlag.Name): Fatalf("Developer chains are ephemeral") } return genesis } // MakeChain creates a chain manager from set command line flags. func MakeChain(ctx *cli.Context, stack *node.Node) (chain *core.BlockChain, chainDb ethdb.Database) { var err error chainDb = MakeChainDatabase(ctx, stack) config, _, err := core.SetupGenesisBlock(chainDb, MakeGenesis(ctx)) if err != nil { Fatalf("%v", err) } var engine consensus.Engine if config.XDPoS != nil { engine = XDPoS.New(config, chainDb) } else { engine = ethash.NewFaker() if !ctx.GlobalBool(FakePoWFlag.Name) { engine = ethash.New(ethash.Config{ CacheDir: stack.ResolvePath(ethconfig.Defaults.Ethash.CacheDir), CachesInMem: ethconfig.Defaults.Ethash.CachesInMem, CachesOnDisk: ethconfig.Defaults.Ethash.CachesOnDisk, DatasetDir: stack.ResolvePath(ethconfig.Defaults.Ethash.DatasetDir), DatasetsInMem: ethconfig.Defaults.Ethash.DatasetsInMem, DatasetsOnDisk: ethconfig.Defaults.Ethash.DatasetsOnDisk, }) } Fatalf("Only support XDPoS consensus") } if gcmode := ctx.GlobalString(GCModeFlag.Name); gcmode != "full" && gcmode != "archive" { Fatalf("--%s must be either 'full' or 'archive'", GCModeFlag.Name) } cache := &core.CacheConfig{ Disabled: ctx.GlobalString(GCModeFlag.Name) == "archive", TrieNodeLimit: ethconfig.Defaults.TrieCache, TrieTimeLimit: ethconfig.Defaults.TrieTimeout, } if ctx.GlobalIsSet(CacheFlag.Name) || ctx.GlobalIsSet(CacheGCFlag.Name) { cache.TrieNodeLimit = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheGCFlag.Name) / 100 } vmcfg := vm.Config{EnablePreimageRecording: ctx.GlobalBool(VMEnableDebugFlag.Name)} chain, err = core.NewBlockChain(chainDb, cache, config, engine, vmcfg) if err != nil { Fatalf("Can't create BlockChain: %v", err) } return chain, chainDb } // MakeConsolePreloads retrieves the absolute paths for the console JavaScript // scripts to preload before starting. func MakeConsolePreloads(ctx *cli.Context) []string { // Skip preloading if there's nothing to preload if ctx.GlobalString(PreloadJSFlag.Name) == "" { return nil } // Otherwise resolve absolute paths and return them preloads := []string{} assets := ctx.GlobalString(JSpathFlag.Name) for _, file := range strings.Split(ctx.GlobalString(PreloadJSFlag.Name), ",") { preloads = append(preloads, common.AbsolutePath(assets, strings.TrimSpace(file))) } return preloads } // MigrateFlags sets the global flag from a local flag when it's set. // This is a temporary function used for migrating old command/flags to the // new format. // // e.g. XDC account new --keystore /tmp/mykeystore --lightkdf // // is equivalent after calling this method with: // // XDC --keystore /tmp/mykeystore --lightkdf account new // // This allows the use of the existing configuration functionality. // When all flags are migrated this function can be removed and the existing // configuration functionality must be changed that is uses local flags func MigrateFlags(action func(ctx *cli.Context) error) func(*cli.Context) error { return func(ctx *cli.Context) error { for _, name := range ctx.FlagNames() { if ctx.IsSet(name) { ctx.GlobalSet(name, ctx.String(name)) } } return action(ctx) } } // find all filenames match the given pattern in the given root directory func WalkMatch(root, pattern string) ([]string, error) { matches := []string{} err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error { if err != nil { return err } if info.IsDir() { return nil } if matched, err := filepath.Match(pattern, filepath.Base(path)); err != nil { return err } else if matched { matches = append(matches, path) } return nil }) if err != nil { return nil, err } return matches, nil } // RegisterFilterAPI adds the eth log filtering RPC API to the node. func RegisterFilterAPI(stack *node.Node, backend ethapi.Backend, ethcfg *ethconfig.Config) *filters.FilterSystem { isLightClient := ethcfg.SyncMode == downloader.LightSync filterSystem := filters.NewFilterSystem(backend, filters.Config{ LogCacheSize: ethcfg.FilterLogCacheSize, }) stack.RegisterAPIs([]rpc.API{{ Namespace: "eth", Service: filters.NewFilterAPI(filterSystem, isLightClient), }}) return filterSystem } func SetupMetrics(ctx *cli.Context) { if metrics.Enabled { log.Info("Enabling metrics collection") if ctx.GlobalIsSet(MetricsHTTPFlag.Name) { address := fmt.Sprintf("%s:%d", ctx.GlobalString(MetricsHTTPFlag.Name), ctx.GlobalInt(MetricsPortFlag.Name)) log.Info("Enabling stand-alone metrics HTTP endpoint", "address", address) exp.Setup(address) } } }