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