github.com/mandrigin/go-ethereum@v1.7.4-0.20180116162341-02aeb3d76652/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.RinkebyV5Bootnodes 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 // setDiscoveryV5Address creates a UDP listening address string from set command 640 // line flags for the V5 discovery protocol. 641 func setDiscoveryV5Address(ctx *cli.Context, cfg *p2p.Config) { 642 if ctx.GlobalIsSet(ListenPortFlag.Name) { 643 cfg.DiscoveryV5Addr = fmt.Sprintf(":%d", ctx.GlobalInt(ListenPortFlag.Name)+1) 644 } 645 } 646 647 // setNAT creates a port mapper from command line flags. 648 func setNAT(ctx *cli.Context, cfg *p2p.Config) { 649 if ctx.GlobalIsSet(NATFlag.Name) { 650 natif, err := nat.Parse(ctx.GlobalString(NATFlag.Name)) 651 if err != nil { 652 Fatalf("Option %s: %v", NATFlag.Name, err) 653 } 654 cfg.NAT = natif 655 } 656 } 657 658 // splitAndTrim splits input separated by a comma 659 // and trims excessive white space from the substrings. 660 func splitAndTrim(input string) []string { 661 result := strings.Split(input, ",") 662 for i, r := range result { 663 result[i] = strings.TrimSpace(r) 664 } 665 return result 666 } 667 668 // setHTTP creates the HTTP RPC listener interface string from the set 669 // command line flags, returning empty if the HTTP endpoint is disabled. 670 func setHTTP(ctx *cli.Context, cfg *node.Config) { 671 if ctx.GlobalBool(RPCEnabledFlag.Name) && cfg.HTTPHost == "" { 672 cfg.HTTPHost = "127.0.0.1" 673 if ctx.GlobalIsSet(RPCListenAddrFlag.Name) { 674 cfg.HTTPHost = ctx.GlobalString(RPCListenAddrFlag.Name) 675 } 676 } 677 678 if ctx.GlobalIsSet(RPCPortFlag.Name) { 679 cfg.HTTPPort = ctx.GlobalInt(RPCPortFlag.Name) 680 } 681 if ctx.GlobalIsSet(RPCCORSDomainFlag.Name) { 682 cfg.HTTPCors = splitAndTrim(ctx.GlobalString(RPCCORSDomainFlag.Name)) 683 } 684 if ctx.GlobalIsSet(RPCApiFlag.Name) { 685 cfg.HTTPModules = splitAndTrim(ctx.GlobalString(RPCApiFlag.Name)) 686 } 687 } 688 689 // setWS creates the WebSocket RPC listener interface string from the set 690 // command line flags, returning empty if the HTTP endpoint is disabled. 691 func setWS(ctx *cli.Context, cfg *node.Config) { 692 if ctx.GlobalBool(WSEnabledFlag.Name) && cfg.WSHost == "" { 693 cfg.WSHost = "127.0.0.1" 694 if ctx.GlobalIsSet(WSListenAddrFlag.Name) { 695 cfg.WSHost = ctx.GlobalString(WSListenAddrFlag.Name) 696 } 697 } 698 699 if ctx.GlobalIsSet(WSPortFlag.Name) { 700 cfg.WSPort = ctx.GlobalInt(WSPortFlag.Name) 701 } 702 if ctx.GlobalIsSet(WSAllowedOriginsFlag.Name) { 703 cfg.WSOrigins = splitAndTrim(ctx.GlobalString(WSAllowedOriginsFlag.Name)) 704 } 705 if ctx.GlobalIsSet(WSApiFlag.Name) { 706 cfg.WSModules = splitAndTrim(ctx.GlobalString(WSApiFlag.Name)) 707 } 708 } 709 710 // setIPC creates an IPC path configuration from the set command line flags, 711 // returning an empty string if IPC was explicitly disabled, or the set path. 712 func setIPC(ctx *cli.Context, cfg *node.Config) { 713 checkExclusive(ctx, IPCDisabledFlag, IPCPathFlag) 714 switch { 715 case ctx.GlobalBool(IPCDisabledFlag.Name): 716 cfg.IPCPath = "" 717 case ctx.GlobalIsSet(IPCPathFlag.Name): 718 cfg.IPCPath = ctx.GlobalString(IPCPathFlag.Name) 719 } 720 } 721 722 // makeDatabaseHandles raises out the number of allowed file handles per process 723 // for Geth and returns half of the allowance to assign to the database. 724 func makeDatabaseHandles() int { 725 if err := fdlimit.Raise(2048); err != nil { 726 Fatalf("Failed to raise file descriptor allowance: %v", err) 727 } 728 limit, err := fdlimit.Current() 729 if err != nil { 730 Fatalf("Failed to retrieve file descriptor allowance: %v", err) 731 } 732 if limit > 2048 { // cap database file descriptors even if more is available 733 limit = 2048 734 } 735 return limit / 2 // Leave half for networking and other stuff 736 } 737 738 // MakeAddress converts an account specified directly as a hex encoded string or 739 // a key index in the key store to an internal account representation. 740 func MakeAddress(ks *keystore.KeyStore, account string) (accounts.Account, error) { 741 // If the specified account is a valid address, return it 742 if common.IsHexAddress(account) { 743 return accounts.Account{Address: common.HexToAddress(account)}, nil 744 } 745 // Otherwise try to interpret the account as a keystore index 746 index, err := strconv.Atoi(account) 747 if err != nil || index < 0 { 748 return accounts.Account{}, fmt.Errorf("invalid account address or index %q", account) 749 } 750 log.Warn("-------------------------------------------------------------------") 751 log.Warn("Referring to accounts by order in the keystore folder is dangerous!") 752 log.Warn("This functionality is deprecated and will be removed in the future!") 753 log.Warn("Please use explicit addresses! (can search via `geth account list`)") 754 log.Warn("-------------------------------------------------------------------") 755 756 accs := ks.Accounts() 757 if len(accs) <= index { 758 return accounts.Account{}, fmt.Errorf("index %d higher than number of accounts %d", index, len(accs)) 759 } 760 return accs[index], nil 761 } 762 763 // setEtherbase retrieves the etherbase either from the directly specified 764 // command line flags or from the keystore if CLI indexed. 765 func setEtherbase(ctx *cli.Context, ks *keystore.KeyStore, cfg *eth.Config) { 766 if ctx.GlobalIsSet(EtherbaseFlag.Name) { 767 account, err := MakeAddress(ks, ctx.GlobalString(EtherbaseFlag.Name)) 768 if err != nil { 769 Fatalf("Option %q: %v", EtherbaseFlag.Name, err) 770 } 771 cfg.Etherbase = account.Address 772 } 773 } 774 775 // MakePasswordList reads password lines from the file specified by the global --password flag. 776 func MakePasswordList(ctx *cli.Context) []string { 777 path := ctx.GlobalString(PasswordFileFlag.Name) 778 if path == "" { 779 return nil 780 } 781 text, err := ioutil.ReadFile(path) 782 if err != nil { 783 Fatalf("Failed to read password file: %v", err) 784 } 785 lines := strings.Split(string(text), "\n") 786 // Sanitise DOS line endings. 787 for i := range lines { 788 lines[i] = strings.TrimRight(lines[i], "\r") 789 } 790 return lines 791 } 792 793 func SetP2PConfig(ctx *cli.Context, cfg *p2p.Config) { 794 setNodeKey(ctx, cfg) 795 setNAT(ctx, cfg) 796 setListenAddress(ctx, cfg) 797 setDiscoveryV5Address(ctx, cfg) 798 setBootstrapNodes(ctx, cfg) 799 setBootstrapNodesV5(ctx, cfg) 800 801 if ctx.GlobalIsSet(MaxPeersFlag.Name) { 802 cfg.MaxPeers = ctx.GlobalInt(MaxPeersFlag.Name) 803 } 804 if ctx.GlobalIsSet(MaxPendingPeersFlag.Name) { 805 cfg.MaxPendingPeers = ctx.GlobalInt(MaxPendingPeersFlag.Name) 806 } 807 if ctx.GlobalIsSet(NoDiscoverFlag.Name) || ctx.GlobalBool(LightModeFlag.Name) { 808 cfg.NoDiscovery = true 809 } 810 811 // if we're running a light client or server, force enable the v5 peer discovery 812 // unless it is explicitly disabled with --nodiscover note that explicitly specifying 813 // --v5disc overrides --nodiscover, in which case the later only disables v4 discovery 814 forceV5Discovery := (ctx.GlobalBool(LightModeFlag.Name) || ctx.GlobalInt(LightServFlag.Name) > 0) && !ctx.GlobalBool(NoDiscoverFlag.Name) 815 if ctx.GlobalIsSet(DiscoveryV5Flag.Name) { 816 cfg.DiscoveryV5 = ctx.GlobalBool(DiscoveryV5Flag.Name) 817 } else if forceV5Discovery { 818 cfg.DiscoveryV5 = true 819 } 820 821 if netrestrict := ctx.GlobalString(NetrestrictFlag.Name); netrestrict != "" { 822 list, err := netutil.ParseNetlist(netrestrict) 823 if err != nil { 824 Fatalf("Option %q: %v", NetrestrictFlag.Name, err) 825 } 826 cfg.NetRestrict = list 827 } 828 829 if ctx.GlobalBool(DeveloperFlag.Name) { 830 // --dev mode can't use p2p networking. 831 cfg.MaxPeers = 0 832 cfg.ListenAddr = ":0" 833 cfg.DiscoveryV5Addr = ":0" 834 cfg.NoDiscovery = true 835 cfg.DiscoveryV5 = false 836 } 837 } 838 839 // SetNodeConfig applies node-related command line flags to the config. 840 func SetNodeConfig(ctx *cli.Context, cfg *node.Config) { 841 SetP2PConfig(ctx, &cfg.P2P) 842 setIPC(ctx, cfg) 843 setHTTP(ctx, cfg) 844 setWS(ctx, cfg) 845 setNodeUserIdent(ctx, cfg) 846 847 switch { 848 case ctx.GlobalIsSet(DataDirFlag.Name): 849 cfg.DataDir = ctx.GlobalString(DataDirFlag.Name) 850 case ctx.GlobalBool(DeveloperFlag.Name): 851 cfg.DataDir = "" // unless explicitly requested, use memory databases 852 case ctx.GlobalBool(TestnetFlag.Name): 853 cfg.DataDir = filepath.Join(node.DefaultDataDir(), "testnet") 854 case ctx.GlobalBool(RinkebyFlag.Name): 855 cfg.DataDir = filepath.Join(node.DefaultDataDir(), "rinkeby") 856 } 857 858 if ctx.GlobalIsSet(KeyStoreDirFlag.Name) { 859 cfg.KeyStoreDir = ctx.GlobalString(KeyStoreDirFlag.Name) 860 } 861 if ctx.GlobalIsSet(LightKDFFlag.Name) { 862 cfg.UseLightweightKDF = ctx.GlobalBool(LightKDFFlag.Name) 863 } 864 if ctx.GlobalIsSet(NoUSBFlag.Name) { 865 cfg.NoUSB = ctx.GlobalBool(NoUSBFlag.Name) 866 } 867 } 868 869 func setGPO(ctx *cli.Context, cfg *gasprice.Config) { 870 if ctx.GlobalIsSet(GpoBlocksFlag.Name) { 871 cfg.Blocks = ctx.GlobalInt(GpoBlocksFlag.Name) 872 } 873 if ctx.GlobalIsSet(GpoPercentileFlag.Name) { 874 cfg.Percentile = ctx.GlobalInt(GpoPercentileFlag.Name) 875 } 876 } 877 878 func setTxPool(ctx *cli.Context, cfg *core.TxPoolConfig) { 879 if ctx.GlobalIsSet(TxPoolNoLocalsFlag.Name) { 880 cfg.NoLocals = ctx.GlobalBool(TxPoolNoLocalsFlag.Name) 881 } 882 if ctx.GlobalIsSet(TxPoolJournalFlag.Name) { 883 cfg.Journal = ctx.GlobalString(TxPoolJournalFlag.Name) 884 } 885 if ctx.GlobalIsSet(TxPoolRejournalFlag.Name) { 886 cfg.Rejournal = ctx.GlobalDuration(TxPoolRejournalFlag.Name) 887 } 888 if ctx.GlobalIsSet(TxPoolPriceLimitFlag.Name) { 889 cfg.PriceLimit = ctx.GlobalUint64(TxPoolPriceLimitFlag.Name) 890 } 891 if ctx.GlobalIsSet(TxPoolPriceBumpFlag.Name) { 892 cfg.PriceBump = ctx.GlobalUint64(TxPoolPriceBumpFlag.Name) 893 } 894 if ctx.GlobalIsSet(TxPoolAccountSlotsFlag.Name) { 895 cfg.AccountSlots = ctx.GlobalUint64(TxPoolAccountSlotsFlag.Name) 896 } 897 if ctx.GlobalIsSet(TxPoolGlobalSlotsFlag.Name) { 898 cfg.GlobalSlots = ctx.GlobalUint64(TxPoolGlobalSlotsFlag.Name) 899 } 900 if ctx.GlobalIsSet(TxPoolAccountQueueFlag.Name) { 901 cfg.AccountQueue = ctx.GlobalUint64(TxPoolAccountQueueFlag.Name) 902 } 903 if ctx.GlobalIsSet(TxPoolGlobalQueueFlag.Name) { 904 cfg.GlobalQueue = ctx.GlobalUint64(TxPoolGlobalQueueFlag.Name) 905 } 906 if ctx.GlobalIsSet(TxPoolLifetimeFlag.Name) { 907 cfg.Lifetime = ctx.GlobalDuration(TxPoolLifetimeFlag.Name) 908 } 909 } 910 911 func setEthash(ctx *cli.Context, cfg *eth.Config) { 912 if ctx.GlobalIsSet(EthashCacheDirFlag.Name) { 913 cfg.Ethash.CacheDir = ctx.GlobalString(EthashCacheDirFlag.Name) 914 } 915 if ctx.GlobalIsSet(EthashDatasetDirFlag.Name) { 916 cfg.Ethash.DatasetDir = ctx.GlobalString(EthashDatasetDirFlag.Name) 917 } 918 if ctx.GlobalIsSet(EthashCachesInMemoryFlag.Name) { 919 cfg.Ethash.CachesInMem = ctx.GlobalInt(EthashCachesInMemoryFlag.Name) 920 } 921 if ctx.GlobalIsSet(EthashCachesOnDiskFlag.Name) { 922 cfg.Ethash.CachesOnDisk = ctx.GlobalInt(EthashCachesOnDiskFlag.Name) 923 } 924 if ctx.GlobalIsSet(EthashDatasetsInMemoryFlag.Name) { 925 cfg.Ethash.DatasetsInMem = ctx.GlobalInt(EthashDatasetsInMemoryFlag.Name) 926 } 927 if ctx.GlobalIsSet(EthashDatasetsOnDiskFlag.Name) { 928 cfg.Ethash.DatasetsOnDisk = ctx.GlobalInt(EthashDatasetsOnDiskFlag.Name) 929 } 930 } 931 932 // checkExclusive verifies that only a single isntance of the provided flags was 933 // set by the user. Each flag might optionally be followed by a string type to 934 // specialize it further. 935 func checkExclusive(ctx *cli.Context, args ...interface{}) { 936 set := make([]string, 0, 1) 937 for i := 0; i < len(args); i++ { 938 // Make sure the next argument is a flag and skip if not set 939 flag, ok := args[i].(cli.Flag) 940 if !ok { 941 panic(fmt.Sprintf("invalid argument, not cli.Flag type: %T", args[i])) 942 } 943 // Check if next arg extends current and expand its name if so 944 name := flag.GetName() 945 946 if i+1 < len(args) { 947 switch option := args[i+1].(type) { 948 case string: 949 // Extended flag, expand the name and shift the arguments 950 if ctx.GlobalString(flag.GetName()) == option { 951 name += "=" + option 952 } 953 i++ 954 955 case cli.Flag: 956 default: 957 panic(fmt.Sprintf("invalid argument, not cli.Flag or string extension: %T", args[i+1])) 958 } 959 } 960 // Mark the flag if it's set 961 if ctx.GlobalIsSet(flag.GetName()) { 962 set = append(set, "--"+name) 963 } 964 } 965 if len(set) > 1 { 966 Fatalf("Flags %v can't be used at the same time", strings.Join(set, ", ")) 967 } 968 } 969 970 // SetShhConfig applies shh-related command line flags to the config. 971 func SetShhConfig(ctx *cli.Context, stack *node.Node, cfg *whisper.Config) { 972 if ctx.GlobalIsSet(WhisperMaxMessageSizeFlag.Name) { 973 cfg.MaxMessageSize = uint32(ctx.GlobalUint(WhisperMaxMessageSizeFlag.Name)) 974 } 975 if ctx.GlobalIsSet(WhisperMinPOWFlag.Name) { 976 cfg.MinimumAcceptedPOW = ctx.GlobalFloat64(WhisperMinPOWFlag.Name) 977 } 978 } 979 980 // SetEthConfig applies eth-related command line flags to the config. 981 func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *eth.Config) { 982 // Avoid conflicting network flags 983 checkExclusive(ctx, DeveloperFlag, TestnetFlag, RinkebyFlag) 984 checkExclusive(ctx, FastSyncFlag, LightModeFlag, SyncModeFlag) 985 checkExclusive(ctx, LightServFlag, LightModeFlag) 986 checkExclusive(ctx, LightServFlag, SyncModeFlag, "light") 987 988 ks := stack.AccountManager().Backends(keystore.KeyStoreType)[0].(*keystore.KeyStore) 989 setEtherbase(ctx, ks, cfg) 990 setGPO(ctx, &cfg.GPO) 991 setTxPool(ctx, &cfg.TxPool) 992 setEthash(ctx, cfg) 993 994 switch { 995 case ctx.GlobalIsSet(SyncModeFlag.Name): 996 cfg.SyncMode = *GlobalTextMarshaler(ctx, SyncModeFlag.Name).(*downloader.SyncMode) 997 case ctx.GlobalBool(FastSyncFlag.Name): 998 cfg.SyncMode = downloader.FastSync 999 case ctx.GlobalBool(LightModeFlag.Name): 1000 cfg.SyncMode = downloader.LightSync 1001 } 1002 if ctx.GlobalIsSet(LightServFlag.Name) { 1003 cfg.LightServ = ctx.GlobalInt(LightServFlag.Name) 1004 } 1005 if ctx.GlobalIsSet(LightPeersFlag.Name) { 1006 cfg.LightPeers = ctx.GlobalInt(LightPeersFlag.Name) 1007 } 1008 if ctx.GlobalIsSet(NetworkIdFlag.Name) { 1009 cfg.NetworkId = ctx.GlobalUint64(NetworkIdFlag.Name) 1010 } 1011 1012 if ctx.GlobalIsSet(CacheFlag.Name) { 1013 cfg.DatabaseCache = ctx.GlobalInt(CacheFlag.Name) 1014 } 1015 cfg.DatabaseHandles = makeDatabaseHandles() 1016 1017 if ctx.GlobalIsSet(MinerThreadsFlag.Name) { 1018 cfg.MinerThreads = ctx.GlobalInt(MinerThreadsFlag.Name) 1019 } 1020 if ctx.GlobalIsSet(DocRootFlag.Name) { 1021 cfg.DocRoot = ctx.GlobalString(DocRootFlag.Name) 1022 } 1023 if ctx.GlobalIsSet(ExtraDataFlag.Name) { 1024 cfg.ExtraData = []byte(ctx.GlobalString(ExtraDataFlag.Name)) 1025 } 1026 if ctx.GlobalIsSet(GasPriceFlag.Name) { 1027 cfg.GasPrice = GlobalBig(ctx, GasPriceFlag.Name) 1028 } 1029 if ctx.GlobalIsSet(VMEnableDebugFlag.Name) { 1030 // TODO(fjl): force-enable this in --dev mode 1031 cfg.EnablePreimageRecording = ctx.GlobalBool(VMEnableDebugFlag.Name) 1032 } 1033 1034 // Override any default configs for hard coded networks. 1035 switch { 1036 case ctx.GlobalBool(TestnetFlag.Name): 1037 if !ctx.GlobalIsSet(NetworkIdFlag.Name) { 1038 cfg.NetworkId = 3 1039 } 1040 cfg.Genesis = core.DefaultTestnetGenesisBlock() 1041 case ctx.GlobalBool(RinkebyFlag.Name): 1042 if !ctx.GlobalIsSet(NetworkIdFlag.Name) { 1043 cfg.NetworkId = 4 1044 } 1045 cfg.Genesis = core.DefaultRinkebyGenesisBlock() 1046 case ctx.GlobalBool(DeveloperFlag.Name): 1047 // Create new developer account or reuse existing one 1048 var ( 1049 developer accounts.Account 1050 err error 1051 ) 1052 if accs := ks.Accounts(); len(accs) > 0 { 1053 developer = ks.Accounts()[0] 1054 } else { 1055 developer, err = ks.NewAccount("") 1056 if err != nil { 1057 Fatalf("Failed to create developer account: %v", err) 1058 } 1059 } 1060 if err := ks.Unlock(developer, ""); err != nil { 1061 Fatalf("Failed to unlock developer account: %v", err) 1062 } 1063 log.Info("Using developer account", "address", developer.Address) 1064 1065 cfg.Genesis = core.DeveloperGenesisBlock(uint64(ctx.GlobalInt(DeveloperPeriodFlag.Name)), developer.Address) 1066 if !ctx.GlobalIsSet(GasPriceFlag.Name) { 1067 cfg.GasPrice = big.NewInt(1) 1068 } 1069 } 1070 // TODO(fjl): move trie cache generations into config 1071 if gen := ctx.GlobalInt(TrieCacheGenFlag.Name); gen > 0 { 1072 state.MaxTrieCacheGen = uint16(gen) 1073 } 1074 } 1075 1076 // SetDashboardConfig applies dashboard related command line flags to the config. 1077 func SetDashboardConfig(ctx *cli.Context, cfg *dashboard.Config) { 1078 cfg.Host = ctx.GlobalString(DashboardAddrFlag.Name) 1079 cfg.Port = ctx.GlobalInt(DashboardPortFlag.Name) 1080 cfg.Refresh = ctx.GlobalDuration(DashboardRefreshFlag.Name) 1081 cfg.Assets = ctx.GlobalString(DashboardAssetsFlag.Name) 1082 } 1083 1084 // RegisterEthService adds an Ethereum client to the stack. 1085 func RegisterEthService(stack *node.Node, cfg *eth.Config) { 1086 var err error 1087 if cfg.SyncMode == downloader.LightSync { 1088 err = stack.Register(func(ctx *node.ServiceContext) (node.Service, error) { 1089 return les.New(ctx, cfg) 1090 }) 1091 } else { 1092 err = stack.Register(func(ctx *node.ServiceContext) (node.Service, error) { 1093 fullNode, err := eth.New(ctx, cfg) 1094 if fullNode != nil && cfg.LightServ > 0 { 1095 ls, _ := les.NewLesServer(fullNode, cfg) 1096 fullNode.AddLesServer(ls) 1097 } 1098 return fullNode, err 1099 }) 1100 } 1101 if err != nil { 1102 Fatalf("Failed to register the Ethereum service: %v", err) 1103 } 1104 } 1105 1106 // RegisterDashboardService adds a dashboard to the stack. 1107 func RegisterDashboardService(stack *node.Node, cfg *dashboard.Config, commit string) { 1108 stack.Register(func(ctx *node.ServiceContext) (node.Service, error) { 1109 return dashboard.New(cfg, commit) 1110 }) 1111 } 1112 1113 // RegisterShhService configures Whisper and adds it to the given node. 1114 func RegisterShhService(stack *node.Node, cfg *whisper.Config) { 1115 if err := stack.Register(func(n *node.ServiceContext) (node.Service, error) { 1116 return whisper.New(cfg), nil 1117 }); err != nil { 1118 Fatalf("Failed to register the Whisper service: %v", err) 1119 } 1120 } 1121 1122 // RegisterEthStatsService configures the Ethereum Stats daemon and adds it to 1123 // th egiven node. 1124 func RegisterEthStatsService(stack *node.Node, url string) { 1125 if err := stack.Register(func(ctx *node.ServiceContext) (node.Service, error) { 1126 // Retrieve both eth and les services 1127 var ethServ *eth.Ethereum 1128 ctx.Service(ðServ) 1129 1130 var lesServ *les.LightEthereum 1131 ctx.Service(&lesServ) 1132 1133 return ethstats.New(url, ethServ, lesServ) 1134 }); err != nil { 1135 Fatalf("Failed to register the Ethereum Stats service: %v", err) 1136 } 1137 } 1138 1139 // SetupNetwork configures the system for either the main net or some test network. 1140 func SetupNetwork(ctx *cli.Context) { 1141 // TODO(fjl): move target gas limit into config 1142 params.TargetGasLimit = ctx.GlobalUint64(TargetGasLimitFlag.Name) 1143 } 1144 1145 // MakeChainDatabase open an LevelDB using the flags passed to the client and will hard crash if it fails. 1146 func MakeChainDatabase(ctx *cli.Context, stack *node.Node) ethdb.Database { 1147 var ( 1148 cache = ctx.GlobalInt(CacheFlag.Name) 1149 handles = makeDatabaseHandles() 1150 ) 1151 name := "chaindata" 1152 if ctx.GlobalBool(LightModeFlag.Name) { 1153 name = "lightchaindata" 1154 } 1155 chainDb, err := stack.OpenDatabase(name, cache, handles) 1156 if err != nil { 1157 Fatalf("Could not open database: %v", err) 1158 } 1159 return chainDb 1160 } 1161 1162 func MakeGenesis(ctx *cli.Context) *core.Genesis { 1163 var genesis *core.Genesis 1164 switch { 1165 case ctx.GlobalBool(TestnetFlag.Name): 1166 genesis = core.DefaultTestnetGenesisBlock() 1167 case ctx.GlobalBool(RinkebyFlag.Name): 1168 genesis = core.DefaultRinkebyGenesisBlock() 1169 case ctx.GlobalBool(DeveloperFlag.Name): 1170 Fatalf("Developer chains are ephemeral") 1171 } 1172 return genesis 1173 } 1174 1175 // MakeChain creates a chain manager from set command line flags. 1176 func MakeChain(ctx *cli.Context, stack *node.Node) (chain *core.BlockChain, chainDb ethdb.Database) { 1177 var err error 1178 chainDb = MakeChainDatabase(ctx, stack) 1179 1180 config, _, err := core.SetupGenesisBlock(chainDb, MakeGenesis(ctx)) 1181 if err != nil { 1182 Fatalf("%v", err) 1183 } 1184 var engine consensus.Engine 1185 if config.Clique != nil { 1186 engine = clique.New(config.Clique, chainDb) 1187 } else { 1188 engine = ethash.NewFaker() 1189 if !ctx.GlobalBool(FakePoWFlag.Name) { 1190 engine = ethash.New(ethash.Config{ 1191 CacheDir: stack.ResolvePath(eth.DefaultConfig.Ethash.CacheDir), 1192 CachesInMem: eth.DefaultConfig.Ethash.CachesInMem, 1193 CachesOnDisk: eth.DefaultConfig.Ethash.CachesOnDisk, 1194 DatasetDir: stack.ResolvePath(eth.DefaultConfig.Ethash.DatasetDir), 1195 DatasetsInMem: eth.DefaultConfig.Ethash.DatasetsInMem, 1196 DatasetsOnDisk: eth.DefaultConfig.Ethash.DatasetsOnDisk, 1197 }) 1198 } 1199 } 1200 vmcfg := vm.Config{EnablePreimageRecording: ctx.GlobalBool(VMEnableDebugFlag.Name)} 1201 chain, err = core.NewBlockChain(chainDb, config, engine, vmcfg) 1202 if err != nil { 1203 Fatalf("Can't create BlockChain: %v", err) 1204 } 1205 return chain, chainDb 1206 } 1207 1208 // MakeConsolePreloads retrieves the absolute paths for the console JavaScript 1209 // scripts to preload before starting. 1210 func MakeConsolePreloads(ctx *cli.Context) []string { 1211 // Skip preloading if there's nothing to preload 1212 if ctx.GlobalString(PreloadJSFlag.Name) == "" { 1213 return nil 1214 } 1215 // Otherwise resolve absolute paths and return them 1216 preloads := []string{} 1217 1218 assets := ctx.GlobalString(JSpathFlag.Name) 1219 for _, file := range strings.Split(ctx.GlobalString(PreloadJSFlag.Name), ",") { 1220 preloads = append(preloads, common.AbsolutePath(assets, strings.TrimSpace(file))) 1221 } 1222 return preloads 1223 } 1224 1225 // MigrateFlags sets the global flag from a local flag when it's set. 1226 // This is a temporary function used for migrating old command/flags to the 1227 // new format. 1228 // 1229 // e.g. geth account new --keystore /tmp/mykeystore --lightkdf 1230 // 1231 // is equivalent after calling this method with: 1232 // 1233 // geth --keystore /tmp/mykeystore --lightkdf account new 1234 // 1235 // This allows the use of the existing configuration functionality. 1236 // When all flags are migrated this function can be removed and the existing 1237 // configuration functionality must be changed that is uses local flags 1238 func MigrateFlags(action func(ctx *cli.Context) error) func(*cli.Context) error { 1239 return func(ctx *cli.Context) error { 1240 for _, name := range ctx.FlagNames() { 1241 if ctx.IsSet(name) { 1242 ctx.GlobalSet(name, ctx.String(name)) 1243 } 1244 } 1245 return action(ctx) 1246 } 1247 }