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