github.com/Elemental-core/elementalcore@v0.0.0-20191206075037-63891242267a/cmd/utils/flags.go (about) 1 // Copyright 2015 The elementalcore Authors 2 // This file is part of elementalcore. 3 // 4 // elementalcore 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 // elementalcore 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 elementalcore. If not, see <http://www.gnu.org/licenses/>. 16 17 // Package utils contains internal helper functions for elementalcore commands. 18 package utils 19 20 import ( 21 "crypto/ecdsa" 22 "fmt" 23 "io/ioutil" 24 "math/big" 25 "os" 26 "path/filepath" 27 "strconv" 28 "strings" 29 30 "github.com/Elemental-core/elementalcore/accounts" 31 "github.com/Elemental-core/elementalcore/accounts/keystore" 32 "github.com/Elemental-core/elementalcore/common" 33 "github.com/Elemental-core/elementalcore/consensus/dpos" 34 "github.com/Elemental-core/elementalcore/core" 35 "github.com/Elemental-core/elementalcore/core/state" 36 "github.com/Elemental-core/elementalcore/core/vm" 37 "github.com/Elemental-core/elementalcore/crypto" 38 "github.com/Elemental-core/elementalcore/dashboard" 39 "github.com/Elemental-core/elementalcore/eth" 40 "github.com/Elemental-core/elementalcore/eth/downloader" 41 "github.com/Elemental-core/elementalcore/eth/gasprice" 42 "github.com/Elemental-core/elementalcore/ethdb" 43 "github.com/Elemental-core/elementalcore/ethstats" 44 "github.com/Elemental-core/elementalcore/les" 45 "github.com/Elemental-core/elementalcore/log" 46 "github.com/Elemental-core/elementalcore/metrics" 47 "github.com/Elemental-core/elementalcore/node" 48 "github.com/Elemental-core/elementalcore/p2p" 49 "github.com/Elemental-core/elementalcore/p2p/discover" 50 "github.com/Elemental-core/elementalcore/p2p/discv5" 51 "github.com/Elemental-core/elementalcore/p2p/nat" 52 "github.com/Elemental-core/elementalcore/p2p/netutil" 53 "github.com/Elemental-core/elementalcore/params" 54 whisper "github.com/Elemental-core/elementalcore/whisper/whisperv5" 55 "gopkg.in/urfave/cli.v1" 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 gitCommit != "" { 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 DataDirFlag = DirectoryFlag{ 113 Name: "datadir", 114 Usage: "Data directory for the databases and keystore", 115 Value: DirectoryString{node.DefaultDataDir()}, 116 } 117 KeyStoreDirFlag = DirectoryFlag{ 118 Name: "keystore", 119 Usage: "Directory for the keystore (default = inside the datadir)", 120 } 121 NoUSBFlag = cli.BoolFlag{ 122 Name: "nousb", 123 Usage: "Disables monitoring for and managing USB hardware wallets", 124 } 125 NetworkIdFlag = cli.Uint64Flag{ 126 Name: "networkid", 127 Usage: "Network identifier (integer, 1=Frontier, 2=Morden (disused), 3=Ropsten, 4=Rinkeby)", 128 Value: eth.DefaultConfig.NetworkId, 129 } 130 IdentityFlag = cli.StringFlag{ 131 Name: "identity", 132 Usage: "Custom node name", 133 } 134 DocRootFlag = DirectoryFlag{ 135 Name: "docroot", 136 Usage: "Document Root for HTTPClient file scheme", 137 Value: DirectoryString{homeDir()}, 138 } 139 FastSyncFlag = cli.BoolFlag{ 140 Name: "fast", 141 Usage: "Enable fast syncing through state downloads", 142 } 143 LightModeFlag = cli.BoolFlag{ 144 Name: "light", 145 Usage: "Enable light client mode", 146 } 147 defaultSyncMode = eth.DefaultConfig.SyncMode 148 SyncModeFlag = TextMarshalerFlag{ 149 Name: "syncmode", 150 Usage: `Blockchain sync mode ("fast", "full", or "light")`, 151 Value: &defaultSyncMode, 152 } 153 154 LightServFlag = cli.IntFlag{ 155 Name: "lightserv", 156 Usage: "Maximum percentage of time allowed for serving LES requests (0-90)", 157 Value: 0, 158 } 159 LightPeersFlag = cli.IntFlag{ 160 Name: "lightpeers", 161 Usage: "Maximum number of LES client peers", 162 Value: 20, 163 } 164 LightKDFFlag = cli.BoolFlag{ 165 Name: "lightkdf", 166 Usage: "Reduce key-derivation RAM & CPU usage at some expense of KDF strength", 167 } 168 // Dashboard settings 169 DashboardEnabledFlag = cli.BoolFlag{ 170 Name: "dashboard", 171 Usage: "Enable the dashboard", 172 } 173 DashboardAddrFlag = cli.StringFlag{ 174 Name: "dashboard.addr", 175 Usage: "Dashboard listening interface", 176 Value: dashboard.DefaultConfig.Host, 177 } 178 DashboardPortFlag = cli.IntFlag{ 179 Name: "dashboard.host", 180 Usage: "Dashboard listening port", 181 Value: dashboard.DefaultConfig.Port, 182 } 183 DashboardRefreshFlag = cli.DurationFlag{ 184 Name: "dashboard.refresh", 185 Usage: "Dashboard metrics collection refresh rate", 186 Value: dashboard.DefaultConfig.Refresh, 187 } 188 // Transaction pool settings 189 TxPoolNoLocalsFlag = cli.BoolFlag{ 190 Name: "txpool.nolocals", 191 Usage: "Disables price exemptions for locally submitted transactions", 192 } 193 TxPoolJournalFlag = cli.StringFlag{ 194 Name: "txpool.journal", 195 Usage: "Disk journal for local transaction to survive node restarts", 196 Value: core.DefaultTxPoolConfig.Journal, 197 } 198 TxPoolRejournalFlag = cli.DurationFlag{ 199 Name: "txpool.rejournal", 200 Usage: "Time interval to regenerate the local transaction journal", 201 Value: core.DefaultTxPoolConfig.Rejournal, 202 } 203 TxPoolPriceLimitFlag = cli.Uint64Flag{ 204 Name: "txpool.pricelimit", 205 Usage: "Minimum gas price limit to enforce for acceptance into the pool", 206 Value: eth.DefaultConfig.TxPool.PriceLimit, 207 } 208 TxPoolPriceBumpFlag = cli.Uint64Flag{ 209 Name: "txpool.pricebump", 210 Usage: "Price bump percentage to replace an already existing transaction", 211 Value: eth.DefaultConfig.TxPool.PriceBump, 212 } 213 TxPoolAccountSlotsFlag = cli.Uint64Flag{ 214 Name: "txpool.accountslots", 215 Usage: "Minimum number of executable transaction slots guaranteed per account", 216 Value: eth.DefaultConfig.TxPool.AccountSlots, 217 } 218 TxPoolGlobalSlotsFlag = cli.Uint64Flag{ 219 Name: "txpool.globalslots", 220 Usage: "Maximum number of executable transaction slots for all accounts", 221 Value: eth.DefaultConfig.TxPool.GlobalSlots, 222 } 223 TxPoolAccountQueueFlag = cli.Uint64Flag{ 224 Name: "txpool.accountqueue", 225 Usage: "Maximum number of non-executable transaction slots permitted per account", 226 Value: eth.DefaultConfig.TxPool.AccountQueue, 227 } 228 TxPoolGlobalQueueFlag = cli.Uint64Flag{ 229 Name: "txpool.globalqueue", 230 Usage: "Maximum number of non-executable transaction slots for all accounts", 231 Value: eth.DefaultConfig.TxPool.GlobalQueue, 232 } 233 TxPoolLifetimeFlag = cli.DurationFlag{ 234 Name: "txpool.lifetime", 235 Usage: "Maximum amount of time non-executable transaction are queued", 236 Value: eth.DefaultConfig.TxPool.Lifetime, 237 } 238 // Performance tuning settings 239 CacheFlag = cli.IntFlag{ 240 Name: "cache", 241 Usage: "Megabytes of memory allocated to internal caching (min 16MB / database forced)", 242 Value: 128, 243 } 244 TrieCacheGenFlag = cli.IntFlag{ 245 Name: "trie-cache-gens", 246 Usage: "Number of trie node generations to keep in memory", 247 Value: int(state.MaxTrieCacheGen), 248 } 249 // Miner settings 250 MiningEnabledFlag = cli.BoolFlag{ 251 Name: "mine", 252 Usage: "Enable mining", 253 } 254 TargetGasLimitFlag = cli.Uint64Flag{ 255 Name: "targetgaslimit", 256 Usage: "Target gas limit sets the artificial target gas floor for the blocks to mine", 257 Value: params.GenesisGasLimit.Uint64(), 258 } 259 ValidatorFlag = cli.StringFlag{ 260 Name: "validator", 261 Usage: "Public address for block mining signer (default = first account created)", 262 Value: "0", 263 } 264 CoinbaseFlag = cli.StringFlag{ 265 Name: "coinbase", 266 Usage: "Public address for block mining rewards (default = first account created)", 267 Value: "0", 268 } 269 GasPriceFlag = BigFlag{ 270 Name: "gasprice", 271 Usage: "Minimal gas price to accept for mining a transactions", 272 Value: eth.DefaultConfig.GasPrice, 273 } 274 ExtraDataFlag = cli.StringFlag{ 275 Name: "extradata", 276 Usage: "Block extra data set by the miner (default = client version)", 277 } 278 // Account settings 279 UnlockedAccountFlag = cli.StringFlag{ 280 Name: "unlock", 281 Usage: "Comma separated list of accounts to unlock", 282 Value: "", 283 } 284 PasswordFileFlag = cli.StringFlag{ 285 Name: "password", 286 Usage: "Password file to use for non-interactive password input", 287 Value: "", 288 } 289 290 VMEnableDebugFlag = cli.BoolFlag{ 291 Name: "vmdebug", 292 Usage: "Record information useful for VM and contract debugging", 293 } 294 // Logging and debug settings 295 EthStatsURLFlag = cli.StringFlag{ 296 Name: "ethstats", 297 Usage: "Reporting URL of a ethstats service (nodename:secret@host:port)", 298 } 299 MetricsEnabledFlag = cli.BoolFlag{ 300 Name: metrics.MetricsEnabledFlag, 301 Usage: "Enable metrics collection and reporting", 302 } 303 NoCompactionFlag = cli.BoolFlag{ 304 Name: "nocompaction", 305 Usage: "Disables db compaction after import", 306 } 307 // RPC settings 308 RPCEnabledFlag = cli.BoolFlag{ 309 Name: "rpc", 310 Usage: "Enable the HTTP-RPC server", 311 } 312 RPCListenAddrFlag = cli.StringFlag{ 313 Name: "rpcaddr", 314 Usage: "HTTP-RPC server listening interface", 315 Value: node.DefaultHTTPHost, 316 } 317 RPCPortFlag = cli.IntFlag{ 318 Name: "rpcport", 319 Usage: "HTTP-RPC server listening port", 320 Value: node.DefaultHTTPPort, 321 } 322 RPCCORSDomainFlag = cli.StringFlag{ 323 Name: "rpccorsdomain", 324 Usage: "Comma separated list of domains from which to accept cross origin requests (browser enforced)", 325 Value: "", 326 } 327 RPCApiFlag = cli.StringFlag{ 328 Name: "rpcapi", 329 Usage: "API's offered over the HTTP-RPC interface", 330 Value: "", 331 } 332 IPCDisabledFlag = cli.BoolFlag{ 333 Name: "ipcdisable", 334 Usage: "Disable the IPC-RPC server", 335 } 336 IPCPathFlag = DirectoryFlag{ 337 Name: "ipcpath", 338 Usage: "Filename for IPC socket/pipe within the datadir (explicit paths escape it)", 339 } 340 WSEnabledFlag = cli.BoolFlag{ 341 Name: "ws", 342 Usage: "Enable the WS-RPC server", 343 } 344 WSListenAddrFlag = cli.StringFlag{ 345 Name: "wsaddr", 346 Usage: "WS-RPC server listening interface", 347 Value: node.DefaultWSHost, 348 } 349 WSPortFlag = cli.IntFlag{ 350 Name: "wsport", 351 Usage: "WS-RPC server listening port", 352 Value: node.DefaultWSPort, 353 } 354 WSApiFlag = cli.StringFlag{ 355 Name: "wsapi", 356 Usage: "API's offered over the WS-RPC interface", 357 Value: "", 358 } 359 WSAllowedOriginsFlag = cli.StringFlag{ 360 Name: "wsorigins", 361 Usage: "Origins from which to accept websockets requests", 362 Value: "", 363 } 364 ExecFlag = cli.StringFlag{ 365 Name: "exec", 366 Usage: "Execute JavaScript statement", 367 } 368 PreloadJSFlag = cli.StringFlag{ 369 Name: "preload", 370 Usage: "Comma separated list of JavaScript files to preload into the console", 371 } 372 373 // Network Settings 374 MaxPeersFlag = cli.IntFlag{ 375 Name: "maxpeers", 376 Usage: "Maximum number of network peers (network disabled if set to 0)", 377 Value: 25, 378 } 379 MaxPendingPeersFlag = cli.IntFlag{ 380 Name: "maxpendpeers", 381 Usage: "Maximum number of pending connection attempts (defaults used if set to 0)", 382 Value: 0, 383 } 384 ListenPortFlag = cli.IntFlag{ 385 Name: "port", 386 Usage: "Network listening port", 387 Value: 30303, 388 } 389 BootnodesFlag = cli.StringFlag{ 390 Name: "bootnodes", 391 Usage: "Comma separated enode URLs for P2P discovery bootstrap (set v4+v5 instead for light servers)", 392 Value: "", 393 } 394 BootnodesV4Flag = cli.StringFlag{ 395 Name: "bootnodesv4", 396 Usage: "Comma separated enode URLs for P2P v4 discovery bootstrap (light server, full nodes)", 397 Value: "", 398 } 399 BootnodesV5Flag = cli.StringFlag{ 400 Name: "bootnodesv5", 401 Usage: "Comma separated enode URLs for P2P v5 discovery bootstrap (light server, light nodes)", 402 Value: "", 403 } 404 NodeKeyFileFlag = cli.StringFlag{ 405 Name: "nodekey", 406 Usage: "P2P node key file", 407 } 408 NodeKeyHexFlag = cli.StringFlag{ 409 Name: "nodekeyhex", 410 Usage: "P2P node key as hex (for testing)", 411 } 412 NATFlag = cli.StringFlag{ 413 Name: "nat", 414 Usage: "NAT port mapping mechanism (any|none|upnp|pmp|extip:<IP>)", 415 Value: "any", 416 } 417 NoDiscoverFlag = cli.BoolFlag{ 418 Name: "nodiscover", 419 Usage: "Disables the peer discovery mechanism (manual peer addition)", 420 } 421 DiscoveryV5Flag = cli.BoolFlag{ 422 Name: "v5disc", 423 Usage: "Enables the experimental RLPx V5 (Topic Discovery) mechanism", 424 } 425 NetrestrictFlag = cli.StringFlag{ 426 Name: "netrestrict", 427 Usage: "Restricts network communication to the given IP networks (CIDR masks)", 428 } 429 430 // ATM the url is left to the user and deployment to 431 JSpathFlag = cli.StringFlag{ 432 Name: "jspath", 433 Usage: "JavaScript root path for `loadScript`", 434 Value: ".", 435 } 436 437 // Gas price oracle settings 438 GpoBlocksFlag = cli.IntFlag{ 439 Name: "gpoblocks", 440 Usage: "Number of recent blocks to check for gas prices", 441 Value: eth.DefaultConfig.GPO.Blocks, 442 } 443 GpoPercentileFlag = cli.IntFlag{ 444 Name: "gpopercentile", 445 Usage: "Suggested gas price is the given percentile of a set of recent transaction gas prices", 446 Value: eth.DefaultConfig.GPO.Percentile, 447 } 448 WhisperEnabledFlag = cli.BoolFlag{ 449 Name: "shh", 450 Usage: "Enable Whisper", 451 } 452 WhisperMaxMessageSizeFlag = cli.IntFlag{ 453 Name: "shh.maxmessagesize", 454 Usage: "Max message size accepted", 455 Value: int(whisper.DefaultMaxMessageSize), 456 } 457 WhisperMinPOWFlag = cli.Float64Flag{ 458 Name: "shh.pow", 459 Usage: "Minimum POW accepted", 460 Value: whisper.DefaultMinimumPoW, 461 } 462 ) 463 464 // MakeDataDir retrieves the currently requested data directory, terminating 465 // if none (or the empty string) is specified. 466 func MakeDataDir(ctx *cli.Context) string { 467 if path := ctx.GlobalString(DataDirFlag.Name); path != "" { 468 return path 469 } 470 Fatalf("Cannot determine default data directory, please set manually (--datadir)") 471 return "" 472 } 473 474 // setNodeKey creates a node key from set command line flags, either loading it 475 // from a file or as a specified hex value. If neither flags were provided, this 476 // method returns nil and an emphemeral key is to be generated. 477 func setNodeKey(ctx *cli.Context, cfg *p2p.Config) { 478 var ( 479 hex = ctx.GlobalString(NodeKeyHexFlag.Name) 480 file = ctx.GlobalString(NodeKeyFileFlag.Name) 481 key *ecdsa.PrivateKey 482 err error 483 ) 484 switch { 485 case file != "" && hex != "": 486 Fatalf("Options %q and %q are mutually exclusive", NodeKeyFileFlag.Name, NodeKeyHexFlag.Name) 487 case file != "": 488 if key, err = crypto.LoadECDSA(file); err != nil { 489 Fatalf("Option %q: %v", NodeKeyFileFlag.Name, err) 490 } 491 cfg.PrivateKey = key 492 case hex != "": 493 if key, err = crypto.HexToECDSA(hex); err != nil { 494 Fatalf("Option %q: %v", NodeKeyHexFlag.Name, err) 495 } 496 cfg.PrivateKey = key 497 } 498 } 499 500 // setNodeUserIdent creates the user identifier from CLI flags. 501 func setNodeUserIdent(ctx *cli.Context, cfg *node.Config) { 502 if identity := ctx.GlobalString(IdentityFlag.Name); len(identity) > 0 { 503 cfg.UserIdent = identity 504 } 505 } 506 507 // setBootstrapNodes creates a list of bootstrap nodes from the command line 508 // flags, reverting to pre-configured ones if none have been specified. 509 func setBootstrapNodes(ctx *cli.Context, cfg *p2p.Config) { 510 urls := params.MainnetBootnodes 511 switch { 512 case ctx.GlobalIsSet(BootnodesFlag.Name) || ctx.GlobalIsSet(BootnodesV4Flag.Name): 513 if ctx.GlobalIsSet(BootnodesV4Flag.Name) { 514 urls = strings.Split(ctx.GlobalString(BootnodesV4Flag.Name), ",") 515 } else { 516 urls = strings.Split(ctx.GlobalString(BootnodesFlag.Name), ",") 517 } 518 } 519 520 cfg.BootstrapNodes = make([]*discover.Node, 0, len(urls)) 521 for _, url := range urls { 522 node, err := discover.ParseNode(url) 523 if err != nil { 524 log.Error("Bootstrap URL invalid", "enode", url, "err", err) 525 continue 526 } 527 cfg.BootstrapNodes = append(cfg.BootstrapNodes, node) 528 } 529 } 530 531 // setBootstrapNodesV5 creates a list of bootstrap nodes from the command line 532 // flags, reverting to pre-configured ones if none have been specified. 533 func setBootstrapNodesV5(ctx *cli.Context, cfg *p2p.Config) { 534 urls := params.DiscoveryV5Bootnodes 535 switch { 536 case ctx.GlobalIsSet(BootnodesFlag.Name) || ctx.GlobalIsSet(BootnodesV5Flag.Name): 537 if ctx.GlobalIsSet(BootnodesV5Flag.Name) { 538 urls = strings.Split(ctx.GlobalString(BootnodesV5Flag.Name), ",") 539 } else { 540 urls = strings.Split(ctx.GlobalString(BootnodesFlag.Name), ",") 541 } 542 case cfg.BootstrapNodesV5 != nil: 543 return // already set, don't apply defaults. 544 } 545 546 cfg.BootstrapNodesV5 = make([]*discv5.Node, 0, len(urls)) 547 for _, url := range urls { 548 node, err := discv5.ParseNode(url) 549 if err != nil { 550 log.Error("Bootstrap URL invalid", "enode", url, "err", err) 551 continue 552 } 553 cfg.BootstrapNodesV5 = append(cfg.BootstrapNodesV5, node) 554 } 555 } 556 557 // setListenAddress creates a TCP listening address string from set command 558 // line flags. 559 func setListenAddress(ctx *cli.Context, cfg *p2p.Config) { 560 if ctx.GlobalIsSet(ListenPortFlag.Name) { 561 cfg.ListenAddr = fmt.Sprintf(":%d", ctx.GlobalInt(ListenPortFlag.Name)) 562 } 563 } 564 565 // setDiscoveryV5Address creates a UDP listening address string from set command 566 // line flags for the V5 discovery protocol. 567 func setDiscoveryV5Address(ctx *cli.Context, cfg *p2p.Config) { 568 if ctx.GlobalIsSet(ListenPortFlag.Name) { 569 cfg.DiscoveryV5Addr = fmt.Sprintf(":%d", ctx.GlobalInt(ListenPortFlag.Name)+1) 570 } 571 } 572 573 // setNAT creates a port mapper from command line flags. 574 func setNAT(ctx *cli.Context, cfg *p2p.Config) { 575 if ctx.GlobalIsSet(NATFlag.Name) { 576 natif, err := nat.Parse(ctx.GlobalString(NATFlag.Name)) 577 if err != nil { 578 Fatalf("Option %s: %v", NATFlag.Name, err) 579 } 580 cfg.NAT = natif 581 } 582 } 583 584 // splitAndTrim splits input separated by a comma 585 // and trims excessive white space from the substrings. 586 func splitAndTrim(input string) []string { 587 result := strings.Split(input, ",") 588 for i, r := range result { 589 result[i] = strings.TrimSpace(r) 590 } 591 return result 592 } 593 594 // setHTTP creates the HTTP RPC listener interface string from the set 595 // command line flags, returning empty if the HTTP endpoint is disabled. 596 func setHTTP(ctx *cli.Context, cfg *node.Config) { 597 if ctx.GlobalBool(RPCEnabledFlag.Name) && cfg.HTTPHost == "" { 598 cfg.HTTPHost = "127.0.0.1" 599 if ctx.GlobalIsSet(RPCListenAddrFlag.Name) { 600 cfg.HTTPHost = ctx.GlobalString(RPCListenAddrFlag.Name) 601 } 602 } 603 604 if ctx.GlobalIsSet(RPCPortFlag.Name) { 605 cfg.HTTPPort = ctx.GlobalInt(RPCPortFlag.Name) 606 } 607 if ctx.GlobalIsSet(RPCCORSDomainFlag.Name) { 608 cfg.HTTPCors = splitAndTrim(ctx.GlobalString(RPCCORSDomainFlag.Name)) 609 } 610 if ctx.GlobalIsSet(RPCApiFlag.Name) { 611 cfg.HTTPModules = splitAndTrim(ctx.GlobalString(RPCApiFlag.Name)) 612 } 613 } 614 615 // setWS creates the WebSocket RPC listener interface string from the set 616 // command line flags, returning empty if the HTTP endpoint is disabled. 617 func setWS(ctx *cli.Context, cfg *node.Config) { 618 if ctx.GlobalBool(WSEnabledFlag.Name) && cfg.WSHost == "" { 619 cfg.WSHost = "127.0.0.1" 620 if ctx.GlobalIsSet(WSListenAddrFlag.Name) { 621 cfg.WSHost = ctx.GlobalString(WSListenAddrFlag.Name) 622 } 623 } 624 625 if ctx.GlobalIsSet(WSPortFlag.Name) { 626 cfg.WSPort = ctx.GlobalInt(WSPortFlag.Name) 627 } 628 if ctx.GlobalIsSet(WSAllowedOriginsFlag.Name) { 629 cfg.WSOrigins = splitAndTrim(ctx.GlobalString(WSAllowedOriginsFlag.Name)) 630 } 631 if ctx.GlobalIsSet(WSApiFlag.Name) { 632 cfg.WSModules = splitAndTrim(ctx.GlobalString(WSApiFlag.Name)) 633 } 634 } 635 636 // setIPC creates an IPC path configuration from the set command line flags, 637 // returning an empty string if IPC was explicitly disabled, or the set path. 638 func setIPC(ctx *cli.Context, cfg *node.Config) { 639 checkExclusive(ctx, IPCDisabledFlag, IPCPathFlag) 640 switch { 641 case ctx.GlobalBool(IPCDisabledFlag.Name): 642 cfg.IPCPath = "" 643 case ctx.GlobalIsSet(IPCPathFlag.Name): 644 cfg.IPCPath = ctx.GlobalString(IPCPathFlag.Name) 645 } 646 } 647 648 // makeDatabaseHandles raises out the number of allowed file handles per process 649 // for Geth and returns half of the allowance to assign to the database. 650 func makeDatabaseHandles() int { 651 if err := raiseFdLimit(2048); err != nil { 652 Fatalf("Failed to raise file descriptor allowance: %v", err) 653 } 654 limit, err := getFdLimit() 655 if err != nil { 656 Fatalf("Failed to retrieve file descriptor allowance: %v", err) 657 } 658 if limit > 2048 { // cap database file descriptors even if more is available 659 limit = 2048 660 } 661 return limit / 2 // Leave half for networking and other stuff 662 } 663 664 // MakeAddress converts an account specified directly as a hex encoded string or 665 // a key index in the key store to an internal account representation. 666 func MakeAddress(ks *keystore.KeyStore, account string) (accounts.Account, error) { 667 // If the specified account is a valid address, return it 668 if common.IsHexAddress(account) { 669 return accounts.Account{Address: common.HexToAddress(account)}, nil 670 } 671 // Otherwise try to interpret the account as a keystore index 672 index, err := strconv.Atoi(account) 673 if err != nil || index < 0 { 674 return accounts.Account{}, fmt.Errorf("invalid account address or index %q", account) 675 } 676 accs := ks.Accounts() 677 if len(accs) <= index { 678 return accounts.Account{}, fmt.Errorf("index %d higher than number of accounts %d", index, len(accs)) 679 } 680 return accs[index], nil 681 } 682 683 // setValidator retrieves the validator either from the directly specified 684 // command line flags or from the keystore if CLI indexed. 685 func setValidator(ctx *cli.Context, ks *keystore.KeyStore, cfg *eth.Config) { 686 if ctx.GlobalIsSet(ValidatorFlag.Name) { 687 account, err := MakeAddress(ks, ctx.GlobalString(ValidatorFlag.Name)) 688 if err != nil { 689 Fatalf("Option %q: %v", ValidatorFlag.Name, err) 690 } 691 cfg.Validator = account.Address 692 return 693 } 694 accounts := ks.Accounts() 695 if (cfg.Validator == common.Address{}) { 696 if len(accounts) > 0 { 697 cfg.Validator = accounts[0].Address 698 } else { 699 log.Warn("No validator set and no accounts found as default") 700 } 701 } 702 } 703 704 // setCoinbase retrieves the coinbase either from the directly specified 705 // command line flags or from the keystore if CLI indexed. 706 func setCoinbase(ctx *cli.Context, ks *keystore.KeyStore, cfg *eth.Config) { 707 if ctx.GlobalIsSet(CoinbaseFlag.Name) { 708 account, err := MakeAddress(ks, ctx.GlobalString(CoinbaseFlag.Name)) 709 if err != nil { 710 Fatalf("Option %q: %v", CoinbaseFlag.Name, err) 711 } 712 cfg.Coinbase = account.Address 713 return 714 } 715 accounts := ks.Accounts() 716 if (cfg.Coinbase == common.Address{}) { 717 if len(accounts) > 0 { 718 cfg.Coinbase = accounts[0].Address 719 } else { 720 log.Warn("No coinbase set and no accounts found as default") 721 } 722 } 723 } 724 725 // MakePasswordList reads password lines from the file specified by the global --password flag. 726 func MakePasswordList(ctx *cli.Context) []string { 727 path := ctx.GlobalString(PasswordFileFlag.Name) 728 if path == "" { 729 return nil 730 } 731 text, err := ioutil.ReadFile(path) 732 if err != nil { 733 Fatalf("Failed to read password file: %v", err) 734 } 735 lines := strings.Split(string(text), "\n") 736 // Sanitise DOS line endings. 737 for i := range lines { 738 lines[i] = strings.TrimRight(lines[i], "\r") 739 } 740 return lines 741 } 742 743 func SetP2PConfig(ctx *cli.Context, cfg *p2p.Config) { 744 setNodeKey(ctx, cfg) 745 setNAT(ctx, cfg) 746 setListenAddress(ctx, cfg) 747 setDiscoveryV5Address(ctx, cfg) 748 setBootstrapNodes(ctx, cfg) 749 setBootstrapNodesV5(ctx, cfg) 750 751 if ctx.GlobalIsSet(MaxPeersFlag.Name) { 752 cfg.MaxPeers = ctx.GlobalInt(MaxPeersFlag.Name) 753 } 754 if ctx.GlobalIsSet(MaxPendingPeersFlag.Name) { 755 cfg.MaxPendingPeers = ctx.GlobalInt(MaxPendingPeersFlag.Name) 756 } 757 if ctx.GlobalIsSet(NoDiscoverFlag.Name) || ctx.GlobalBool(LightModeFlag.Name) { 758 cfg.NoDiscovery = true 759 } 760 761 // if we're running a light client or server, force enable the v5 peer discovery 762 // unless it is explicitly disabled with --nodiscover note that explicitly specifying 763 // --v5disc overrides --nodiscover, in which case the later only disables v4 discovery 764 forceV5Discovery := (ctx.GlobalBool(LightModeFlag.Name) || ctx.GlobalInt(LightServFlag.Name) > 0) && !ctx.GlobalBool(NoDiscoverFlag.Name) 765 if ctx.GlobalIsSet(DiscoveryV5Flag.Name) { 766 cfg.DiscoveryV5 = ctx.GlobalBool(DiscoveryV5Flag.Name) 767 } else if forceV5Discovery { 768 cfg.DiscoveryV5 = true 769 } 770 771 if netrestrict := ctx.GlobalString(NetrestrictFlag.Name); netrestrict != "" { 772 list, err := netutil.ParseNetlist(netrestrict) 773 if err != nil { 774 Fatalf("Option %q: %v", NetrestrictFlag.Name, err) 775 } 776 cfg.NetRestrict = list 777 } 778 } 779 780 // SetNodeConfig applies node-related command line flags to the config. 781 func SetNodeConfig(ctx *cli.Context, cfg *node.Config) { 782 SetP2PConfig(ctx, &cfg.P2P) 783 setIPC(ctx, cfg) 784 setHTTP(ctx, cfg) 785 setWS(ctx, cfg) 786 setNodeUserIdent(ctx, cfg) 787 788 switch { 789 case ctx.GlobalIsSet(DataDirFlag.Name): 790 cfg.DataDir = ctx.GlobalString(DataDirFlag.Name) 791 } 792 793 if ctx.GlobalIsSet(KeyStoreDirFlag.Name) { 794 cfg.KeyStoreDir = ctx.GlobalString(KeyStoreDirFlag.Name) 795 } 796 if ctx.GlobalIsSet(LightKDFFlag.Name) { 797 cfg.UseLightweightKDF = ctx.GlobalBool(LightKDFFlag.Name) 798 } 799 if ctx.GlobalIsSet(NoUSBFlag.Name) { 800 cfg.NoUSB = ctx.GlobalBool(NoUSBFlag.Name) 801 } 802 } 803 804 func setGPO(ctx *cli.Context, cfg *gasprice.Config) { 805 if ctx.GlobalIsSet(GpoBlocksFlag.Name) { 806 cfg.Blocks = ctx.GlobalInt(GpoBlocksFlag.Name) 807 } 808 if ctx.GlobalIsSet(GpoPercentileFlag.Name) { 809 cfg.Percentile = ctx.GlobalInt(GpoPercentileFlag.Name) 810 } 811 } 812 813 func setTxPool(ctx *cli.Context, cfg *core.TxPoolConfig) { 814 if ctx.GlobalIsSet(TxPoolNoLocalsFlag.Name) { 815 cfg.NoLocals = ctx.GlobalBool(TxPoolNoLocalsFlag.Name) 816 } 817 if ctx.GlobalIsSet(TxPoolJournalFlag.Name) { 818 cfg.Journal = ctx.GlobalString(TxPoolJournalFlag.Name) 819 } 820 if ctx.GlobalIsSet(TxPoolRejournalFlag.Name) { 821 cfg.Rejournal = ctx.GlobalDuration(TxPoolRejournalFlag.Name) 822 } 823 if ctx.GlobalIsSet(TxPoolPriceLimitFlag.Name) { 824 cfg.PriceLimit = ctx.GlobalUint64(TxPoolPriceLimitFlag.Name) 825 } 826 if ctx.GlobalIsSet(TxPoolPriceBumpFlag.Name) { 827 cfg.PriceBump = ctx.GlobalUint64(TxPoolPriceBumpFlag.Name) 828 } 829 if ctx.GlobalIsSet(TxPoolAccountSlotsFlag.Name) { 830 cfg.AccountSlots = ctx.GlobalUint64(TxPoolAccountSlotsFlag.Name) 831 } 832 if ctx.GlobalIsSet(TxPoolGlobalSlotsFlag.Name) { 833 cfg.GlobalSlots = ctx.GlobalUint64(TxPoolGlobalSlotsFlag.Name) 834 } 835 if ctx.GlobalIsSet(TxPoolAccountQueueFlag.Name) { 836 cfg.AccountQueue = ctx.GlobalUint64(TxPoolAccountQueueFlag.Name) 837 } 838 if ctx.GlobalIsSet(TxPoolGlobalQueueFlag.Name) { 839 cfg.GlobalQueue = ctx.GlobalUint64(TxPoolGlobalQueueFlag.Name) 840 } 841 if ctx.GlobalIsSet(TxPoolLifetimeFlag.Name) { 842 cfg.Lifetime = ctx.GlobalDuration(TxPoolLifetimeFlag.Name) 843 } 844 } 845 846 func checkExclusive(ctx *cli.Context, flags ...cli.Flag) { 847 set := make([]string, 0, 1) 848 for _, flag := range flags { 849 if ctx.GlobalIsSet(flag.GetName()) { 850 set = append(set, "--"+flag.GetName()) 851 } 852 } 853 if len(set) > 1 { 854 Fatalf("flags %v can't be used at the same time", strings.Join(set, ", ")) 855 } 856 } 857 858 // SetShhConfig applies shh-related command line flags to the config. 859 func SetShhConfig(ctx *cli.Context, stack *node.Node, cfg *whisper.Config) { 860 if ctx.GlobalIsSet(WhisperMaxMessageSizeFlag.Name) { 861 cfg.MaxMessageSize = uint32(ctx.GlobalUint(WhisperMaxMessageSizeFlag.Name)) 862 } 863 if ctx.GlobalIsSet(WhisperMinPOWFlag.Name) { 864 cfg.MinimumAcceptedPOW = ctx.GlobalFloat64(WhisperMinPOWFlag.Name) 865 } 866 } 867 868 // SetEthConfig applies eth-related command line flags to the config. 869 func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *eth.Config) { 870 // Avoid conflicting network flags 871 checkExclusive(ctx, FastSyncFlag, LightModeFlag, SyncModeFlag) 872 873 ks := stack.AccountManager().Backends(keystore.KeyStoreType)[0].(*keystore.KeyStore) 874 setValidator(ctx, ks, cfg) 875 setCoinbase(ctx, ks, cfg) 876 setGPO(ctx, &cfg.GPO) 877 setTxPool(ctx, &cfg.TxPool) 878 879 switch { 880 case ctx.GlobalIsSet(SyncModeFlag.Name): 881 cfg.SyncMode = *GlobalTextMarshaler(ctx, SyncModeFlag.Name).(*downloader.SyncMode) 882 case ctx.GlobalBool(FastSyncFlag.Name): 883 cfg.SyncMode = downloader.FastSync 884 case ctx.GlobalBool(LightModeFlag.Name): 885 cfg.SyncMode = downloader.LightSync 886 } 887 if ctx.GlobalIsSet(LightServFlag.Name) { 888 cfg.LightServ = ctx.GlobalInt(LightServFlag.Name) 889 } 890 if ctx.GlobalIsSet(LightPeersFlag.Name) { 891 cfg.LightPeers = ctx.GlobalInt(LightPeersFlag.Name) 892 } 893 if ctx.GlobalIsSet(NetworkIdFlag.Name) { 894 cfg.NetworkId = ctx.GlobalUint64(NetworkIdFlag.Name) 895 } 896 897 if ctx.GlobalIsSet(CacheFlag.Name) { 898 cfg.DatabaseCache = ctx.GlobalInt(CacheFlag.Name) 899 } 900 cfg.DatabaseHandles = makeDatabaseHandles() 901 902 if ctx.GlobalIsSet(DocRootFlag.Name) { 903 cfg.DocRoot = ctx.GlobalString(DocRootFlag.Name) 904 } 905 if ctx.GlobalIsSet(ExtraDataFlag.Name) { 906 cfg.ExtraData = []byte(ctx.GlobalString(ExtraDataFlag.Name)) 907 } 908 if ctx.GlobalIsSet(GasPriceFlag.Name) { 909 cfg.GasPrice = GlobalBig(ctx, GasPriceFlag.Name) 910 } 911 if ctx.GlobalIsSet(VMEnableDebugFlag.Name) { 912 // TODO(fjl): force-enable this in --dev mode 913 cfg.EnablePreimageRecording = ctx.GlobalBool(VMEnableDebugFlag.Name) 914 } 915 } 916 917 // SetDashboardConfig applies dashboard related command line flags to the config. 918 func SetDashboardConfig(ctx *cli.Context, cfg *dashboard.Config) { 919 cfg.Host = ctx.GlobalString(DashboardAddrFlag.Name) 920 cfg.Port = ctx.GlobalInt(DashboardPortFlag.Name) 921 cfg.Refresh = ctx.GlobalDuration(DashboardRefreshFlag.Name) 922 } 923 924 // RegisterEthService adds an Ethereum client to the stack. 925 func RegisterEthService(stack *node.Node, cfg *eth.Config) { 926 var err error 927 if cfg.SyncMode == downloader.LightSync { 928 err = stack.Register(func(ctx *node.ServiceContext) (node.Service, error) { 929 return les.New(ctx, cfg) 930 }) 931 } else { 932 err = stack.Register(func(ctx *node.ServiceContext) (node.Service, error) { 933 fullNode, err := eth.New(ctx, cfg) 934 if fullNode != nil && cfg.LightServ > 0 { 935 ls, _ := les.NewLesServer(fullNode, cfg) 936 fullNode.AddLesServer(ls) 937 } 938 return fullNode, err 939 }) 940 } 941 if err != nil { 942 Fatalf("Failed to register the Ethereum service: %v", err) 943 } 944 } 945 946 // RegisterDashboardService adds a dashboard to the stack. 947 func RegisterDashboardService(stack *node.Node, cfg *dashboard.Config) { 948 stack.Register(func(ctx *node.ServiceContext) (node.Service, error) { 949 return dashboard.New(cfg) 950 }) 951 } 952 953 // RegisterShhService configures Whisper and adds it to the given node. 954 func RegisterShhService(stack *node.Node, cfg *whisper.Config) { 955 if err := stack.Register(func(n *node.ServiceContext) (node.Service, error) { 956 return whisper.New(cfg), nil 957 }); err != nil { 958 Fatalf("Failed to register the Whisper service: %v", err) 959 } 960 } 961 962 // RegisterEthStatsService configures the Ethereum Stats daemon and adds it to 963 // th egiven node. 964 func RegisterEthStatsService(stack *node.Node, url string) { 965 if err := stack.Register(func(ctx *node.ServiceContext) (node.Service, error) { 966 // Retrieve both eth and les services 967 var ethServ *eth.Ethereum 968 ctx.Service(ðServ) 969 970 var lesServ *les.LightEthereum 971 ctx.Service(&lesServ) 972 973 return ethstats.New(url, ethServ, lesServ) 974 }); err != nil { 975 Fatalf("Failed to register the Ethereum Stats service: %v", err) 976 } 977 } 978 979 // SetupNetwork configures the system for either the main net or some test network. 980 func SetupNetwork(ctx *cli.Context) { 981 // TODO(fjl): move target gas limit into config 982 params.TargetGasLimit = new(big.Int).SetUint64(ctx.GlobalUint64(TargetGasLimitFlag.Name)) 983 } 984 985 // MakeChainDatabase open an LevelDB using the flags passed to the client and will hard crash if it fails. 986 func MakeChainDatabase(ctx *cli.Context, stack *node.Node) ethdb.Database { 987 var ( 988 cache = ctx.GlobalInt(CacheFlag.Name) 989 handles = makeDatabaseHandles() 990 ) 991 name := "chaindata" 992 if ctx.GlobalBool(LightModeFlag.Name) { 993 name = "lightchaindata" 994 } 995 chainDb, err := stack.OpenDatabase(name, cache, handles) 996 if err != nil { 997 Fatalf("Could not open database: %v", err) 998 } 999 return chainDb 1000 } 1001 1002 // MakeChain creates a chain manager from set command line flags. 1003 func MakeChain(ctx *cli.Context, stack *node.Node) (chain *core.BlockChain, chainDb ethdb.Database) { 1004 var err error 1005 chainDb = MakeChainDatabase(ctx, stack) 1006 1007 config, _, err := core.SetupGenesisBlock(chainDb, nil) 1008 if err != nil { 1009 Fatalf("%v", err) 1010 } 1011 engine := dpos.New(config.Dpos, chainDb) 1012 vmcfg := vm.Config{EnablePreimageRecording: ctx.GlobalBool(VMEnableDebugFlag.Name)} 1013 chain, err = core.NewBlockChain(chainDb, config, engine, vmcfg) 1014 if err != nil { 1015 Fatalf("Can't create BlockChain: %v", err) 1016 } 1017 return chain, chainDb 1018 } 1019 1020 // MakeConsolePreloads retrieves the absolute paths for the console JavaScript 1021 // scripts to preload before starting. 1022 func MakeConsolePreloads(ctx *cli.Context) []string { 1023 // Skip preloading if there's nothing to preload 1024 if ctx.GlobalString(PreloadJSFlag.Name) == "" { 1025 return nil 1026 } 1027 // Otherwise resolve absolute paths and return them 1028 preloads := []string{} 1029 1030 assets := ctx.GlobalString(JSpathFlag.Name) 1031 for _, file := range strings.Split(ctx.GlobalString(PreloadJSFlag.Name), ",") { 1032 preloads = append(preloads, common.AbsolutePath(assets, strings.TrimSpace(file))) 1033 } 1034 return preloads 1035 } 1036 1037 // MigrateFlags sets the global flag from a local flag when it's set. 1038 // This is a temporary function used for migrating old command/flags to the 1039 // new format. 1040 // 1041 // e.g. geth account new --keystore /tmp/mykeystore --lightkdf 1042 // 1043 // is equivalent after calling this method with: 1044 // 1045 // geth --keystore /tmp/mykeystore --lightkdf account new 1046 // 1047 // This allows the use of the existing configuration functionality. 1048 // When all flags are migrated this function can be removed and the existing 1049 // configuration functionality must be changed that is uses local flags 1050 func MigrateFlags(action func(ctx *cli.Context) error) func(*cli.Context) error { 1051 return func(ctx *cli.Context) error { 1052 for _, name := range ctx.FlagNames() { 1053 if ctx.IsSet(name) { 1054 ctx.GlobalSet(name, ctx.String(name)) 1055 } 1056 } 1057 return action(ctx) 1058 } 1059 }