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