github.com/devfans/go-ethereum@v1.5.10-0.20170326212234-7419d0c38291/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 "os/user" 27 "path/filepath" 28 "runtime" 29 "strconv" 30 "strings" 31 32 "github.com/ethereum/go-ethereum/accounts" 33 "github.com/ethereum/go-ethereum/accounts/keystore" 34 "github.com/ethereum/go-ethereum/common" 35 "github.com/ethereum/go-ethereum/core" 36 "github.com/ethereum/go-ethereum/core/state" 37 "github.com/ethereum/go-ethereum/core/vm" 38 "github.com/ethereum/go-ethereum/crypto" 39 "github.com/ethereum/go-ethereum/eth" 40 "github.com/ethereum/go-ethereum/ethdb" 41 "github.com/ethereum/go-ethereum/ethstats" 42 "github.com/ethereum/go-ethereum/event" 43 "github.com/ethereum/go-ethereum/les" 44 "github.com/ethereum/go-ethereum/log" 45 "github.com/ethereum/go-ethereum/metrics" 46 "github.com/ethereum/go-ethereum/node" 47 "github.com/ethereum/go-ethereum/p2p/discover" 48 "github.com/ethereum/go-ethereum/p2p/discv5" 49 "github.com/ethereum/go-ethereum/p2p/nat" 50 "github.com/ethereum/go-ethereum/p2p/netutil" 51 "github.com/ethereum/go-ethereum/params" 52 "github.com/ethereum/go-ethereum/pow" 53 "github.com/ethereum/go-ethereum/rpc" 54 whisper "github.com/ethereum/go-ethereum/whisper/whisperv2" 55 "gopkg.in/urfave/cli.v1" 56 ) 57 58 func init() { 59 cli.AppHelpTemplate = `{{.Name}} {{if .Flags}}[global options] {{end}}command{{if .Flags}} [command options]{{end}} [arguments...] 60 61 VERSION: 62 {{.Version}} 63 64 COMMANDS: 65 {{range .Commands}}{{.Name}}{{with .ShortName}}, {{.}}{{end}}{{ "\t" }}{{.Usage}} 66 {{end}}{{if .Flags}} 67 GLOBAL OPTIONS: 68 {{range .Flags}}{{.}} 69 {{end}}{{end}} 70 ` 71 72 cli.CommandHelpTemplate = `{{.Name}}{{if .Subcommands}} command{{end}}{{if .Flags}} [command options]{{end}} [arguments...] 73 {{if .Description}}{{.Description}} 74 {{end}}{{if .Subcommands}} 75 SUBCOMMANDS: 76 {{range .Subcommands}}{{.Name}}{{with .ShortName}}, {{.}}{{end}}{{ "\t" }}{{.Usage}} 77 {{end}}{{end}}{{if .Flags}} 78 OPTIONS: 79 {{range .Flags}}{{.}} 80 {{end}}{{end}} 81 ` 82 } 83 84 // NewApp creates an app with sane defaults. 85 func NewApp(gitCommit, usage string) *cli.App { 86 app := cli.NewApp() 87 app.Name = filepath.Base(os.Args[0]) 88 app.Author = "" 89 //app.Authors = nil 90 app.Email = "" 91 app.Version = params.Version 92 if gitCommit != "" { 93 app.Version += "-" + gitCommit[:8] 94 } 95 app.Usage = usage 96 return app 97 } 98 99 // These are all the command line flags we support. 100 // If you add to this list, please remember to include the 101 // flag in the appropriate command definition. 102 // 103 // The flags are defined here so their names and help texts 104 // are the same for all commands. 105 106 var ( 107 // General settings 108 DataDirFlag = DirectoryFlag{ 109 Name: "datadir", 110 Usage: "Data directory for the databases and keystore", 111 Value: DirectoryString{node.DefaultDataDir()}, 112 } 113 KeyStoreDirFlag = DirectoryFlag{ 114 Name: "keystore", 115 Usage: "Directory for the keystore (default = inside the datadir)", 116 } 117 EthashCacheDirFlag = DirectoryFlag{ 118 Name: "ethash.cachedir", 119 Usage: "Directory to store the ethash verification caches (default = inside the datadir)", 120 } 121 EthashCachesInMemoryFlag = cli.IntFlag{ 122 Name: "ethash.cachesinmem", 123 Usage: "Number of recent ethash caches to keep in memory (16MB each)", 124 Value: 2, 125 } 126 EthashCachesOnDiskFlag = cli.IntFlag{ 127 Name: "ethash.cachesondisk", 128 Usage: "Number of recent ethash caches to keep on disk (16MB each)", 129 Value: 3, 130 } 131 EthashDatasetDirFlag = DirectoryFlag{ 132 Name: "ethash.dagdir", 133 Usage: "Directory to store the ethash mining DAGs (default = inside home folder)", 134 } 135 EthashDatasetsInMemoryFlag = cli.IntFlag{ 136 Name: "ethash.dagsinmem", 137 Usage: "Number of recent ethash mining DAGs to keep in memory (1+GB each)", 138 Value: 1, 139 } 140 EthashDatasetsOnDiskFlag = cli.IntFlag{ 141 Name: "ethash.dagsondisk", 142 Usage: "Number of recent ethash mining DAGs to keep on disk (1+GB each)", 143 Value: 2, 144 } 145 NetworkIdFlag = cli.IntFlag{ 146 Name: "networkid", 147 Usage: "Network identifier (integer, 1=Frontier, 2=Morden (disused), 3=Ropsten)", 148 Value: eth.NetworkId, 149 } 150 TestNetFlag = cli.BoolFlag{ 151 Name: "testnet", 152 Usage: "Ropsten network: pre-configured test network", 153 } 154 DevModeFlag = cli.BoolFlag{ 155 Name: "dev", 156 Usage: "Developer mode: pre-configured private network with several debugging flags", 157 } 158 IdentityFlag = cli.StringFlag{ 159 Name: "identity", 160 Usage: "Custom node name", 161 } 162 DocRootFlag = DirectoryFlag{ 163 Name: "docroot", 164 Usage: "Document Root for HTTPClient file scheme", 165 Value: DirectoryString{homeDir()}, 166 } 167 FastSyncFlag = cli.BoolFlag{ 168 Name: "fast", 169 Usage: "Enable fast syncing through state downloads", 170 } 171 LightModeFlag = cli.BoolFlag{ 172 Name: "light", 173 Usage: "Enable light client mode", 174 } 175 LightServFlag = cli.IntFlag{ 176 Name: "lightserv", 177 Usage: "Maximum percentage of time allowed for serving LES requests (0-90)", 178 Value: 0, 179 } 180 LightPeersFlag = cli.IntFlag{ 181 Name: "lightpeers", 182 Usage: "Maximum number of LES client peers", 183 Value: 20, 184 } 185 LightKDFFlag = cli.BoolFlag{ 186 Name: "lightkdf", 187 Usage: "Reduce key-derivation RAM & CPU usage at some expense of KDF strength", 188 } 189 // Performance tuning settings 190 CacheFlag = cli.IntFlag{ 191 Name: "cache", 192 Usage: "Megabytes of memory allocated to internal caching (min 16MB / database forced)", 193 Value: 128, 194 } 195 TrieCacheGenFlag = cli.IntFlag{ 196 Name: "trie-cache-gens", 197 Usage: "Number of trie node generations to keep in memory", 198 Value: int(state.MaxTrieCacheGen), 199 } 200 // Miner settings 201 MiningEnabledFlag = cli.BoolFlag{ 202 Name: "mine", 203 Usage: "Enable mining", 204 } 205 MinerThreadsFlag = cli.IntFlag{ 206 Name: "minerthreads", 207 Usage: "Number of CPU threads to use for mining", 208 Value: runtime.NumCPU(), 209 } 210 TargetGasLimitFlag = cli.Uint64Flag{ 211 Name: "targetgaslimit", 212 Usage: "Target gas limit sets the artificial target gas floor for the blocks to mine", 213 Value: params.GenesisGasLimit.Uint64(), 214 } 215 EtherbaseFlag = cli.StringFlag{ 216 Name: "etherbase", 217 Usage: "Public address for block mining rewards (default = first account created)", 218 Value: "0", 219 } 220 GasPriceFlag = BigFlag{ 221 Name: "gasprice", 222 Usage: "Minimal gas price to accept for mining a transactions", 223 Value: big.NewInt(20 * params.Shannon), 224 } 225 ExtraDataFlag = cli.StringFlag{ 226 Name: "extradata", 227 Usage: "Block extra data set by the miner (default = client version)", 228 } 229 // Account settings 230 UnlockedAccountFlag = cli.StringFlag{ 231 Name: "unlock", 232 Usage: "Comma separated list of accounts to unlock", 233 Value: "", 234 } 235 PasswordFileFlag = cli.StringFlag{ 236 Name: "password", 237 Usage: "Password file to use for non-inteactive password input", 238 Value: "", 239 } 240 241 VMForceJitFlag = cli.BoolFlag{ 242 Name: "forcejit", 243 Usage: "Force the JIT VM to take precedence", 244 } 245 VMJitCacheFlag = cli.IntFlag{ 246 Name: "jitcache", 247 Usage: "Amount of cached JIT VM programs", 248 Value: 64, 249 } 250 VMEnableJitFlag = cli.BoolFlag{ 251 Name: "jitvm", 252 Usage: "Enable the JIT VM", 253 } 254 VMEnableDebugFlag = cli.BoolFlag{ 255 Name: "vmdebug", 256 Usage: "Record information useful for VM and contract debugging", 257 } 258 // Logging and debug settings 259 EthStatsURLFlag = cli.StringFlag{ 260 Name: "ethstats", 261 Usage: "Reporting URL of a ethstats service (nodename:secret@host:port)", 262 } 263 MetricsEnabledFlag = cli.BoolFlag{ 264 Name: metrics.MetricsEnabledFlag, 265 Usage: "Enable metrics collection and reporting", 266 } 267 FakePoWFlag = cli.BoolFlag{ 268 Name: "fakepow", 269 Usage: "Disables proof-of-work verification", 270 } 271 NoCompactionFlag = cli.BoolFlag{ 272 Name: "nocompaction", 273 Usage: "Disables db compaction after import", 274 } 275 // RPC settings 276 RPCEnabledFlag = cli.BoolFlag{ 277 Name: "rpc", 278 Usage: "Enable the HTTP-RPC server", 279 } 280 RPCListenAddrFlag = cli.StringFlag{ 281 Name: "rpcaddr", 282 Usage: "HTTP-RPC server listening interface", 283 Value: node.DefaultHTTPHost, 284 } 285 RPCPortFlag = cli.IntFlag{ 286 Name: "rpcport", 287 Usage: "HTTP-RPC server listening port", 288 Value: node.DefaultHTTPPort, 289 } 290 RPCCORSDomainFlag = cli.StringFlag{ 291 Name: "rpccorsdomain", 292 Usage: "Comma separated list of domains from which to accept cross origin requests (browser enforced)", 293 Value: "", 294 } 295 RPCApiFlag = cli.StringFlag{ 296 Name: "rpcapi", 297 Usage: "API's offered over the HTTP-RPC interface", 298 Value: rpc.DefaultHTTPApis, 299 } 300 IPCDisabledFlag = cli.BoolFlag{ 301 Name: "ipcdisable", 302 Usage: "Disable the IPC-RPC server", 303 } 304 IPCApiFlag = cli.StringFlag{ 305 Name: "ipcapi", 306 Usage: "APIs offered over the IPC-RPC interface", 307 Value: rpc.DefaultIPCApis, 308 } 309 IPCPathFlag = DirectoryFlag{ 310 Name: "ipcpath", 311 Usage: "Filename for IPC socket/pipe within the datadir (explicit paths escape it)", 312 Value: DirectoryString{"geth.ipc"}, 313 } 314 WSEnabledFlag = cli.BoolFlag{ 315 Name: "ws", 316 Usage: "Enable the WS-RPC server", 317 } 318 WSListenAddrFlag = cli.StringFlag{ 319 Name: "wsaddr", 320 Usage: "WS-RPC server listening interface", 321 Value: node.DefaultWSHost, 322 } 323 WSPortFlag = cli.IntFlag{ 324 Name: "wsport", 325 Usage: "WS-RPC server listening port", 326 Value: node.DefaultWSPort, 327 } 328 WSApiFlag = cli.StringFlag{ 329 Name: "wsapi", 330 Usage: "API's offered over the WS-RPC interface", 331 Value: rpc.DefaultHTTPApis, 332 } 333 WSAllowedOriginsFlag = cli.StringFlag{ 334 Name: "wsorigins", 335 Usage: "Origins from which to accept websockets requests", 336 Value: "", 337 } 338 ExecFlag = cli.StringFlag{ 339 Name: "exec", 340 Usage: "Execute JavaScript statement (only in combination with console/attach)", 341 } 342 PreloadJSFlag = cli.StringFlag{ 343 Name: "preload", 344 Usage: "Comma separated list of JavaScript files to preload into the console", 345 } 346 347 // Network Settings 348 MaxPeersFlag = cli.IntFlag{ 349 Name: "maxpeers", 350 Usage: "Maximum number of network peers (network disabled if set to 0)", 351 Value: 25, 352 } 353 MaxPendingPeersFlag = cli.IntFlag{ 354 Name: "maxpendpeers", 355 Usage: "Maximum number of pending connection attempts (defaults used if set to 0)", 356 Value: 0, 357 } 358 ListenPortFlag = cli.IntFlag{ 359 Name: "port", 360 Usage: "Network listening port", 361 Value: 30303, 362 } 363 BootnodesFlag = cli.StringFlag{ 364 Name: "bootnodes", 365 Usage: "Comma separated enode URLs for P2P discovery bootstrap", 366 Value: "", 367 } 368 NodeKeyFileFlag = cli.StringFlag{ 369 Name: "nodekey", 370 Usage: "P2P node key file", 371 } 372 NodeKeyHexFlag = cli.StringFlag{ 373 Name: "nodekeyhex", 374 Usage: "P2P node key as hex (for testing)", 375 } 376 NATFlag = cli.StringFlag{ 377 Name: "nat", 378 Usage: "NAT port mapping mechanism (any|none|upnp|pmp|extip:<IP>)", 379 Value: "any", 380 } 381 NoDiscoverFlag = cli.BoolFlag{ 382 Name: "nodiscover", 383 Usage: "Disables the peer discovery mechanism (manual peer addition)", 384 } 385 DiscoveryV5Flag = cli.BoolFlag{ 386 Name: "v5disc", 387 Usage: "Enables the experimental RLPx V5 (Topic Discovery) mechanism", 388 } 389 NetrestrictFlag = cli.StringFlag{ 390 Name: "netrestrict", 391 Usage: "Restricts network communication to the given IP networks (CIDR masks)", 392 } 393 394 WhisperEnabledFlag = cli.BoolFlag{ 395 Name: "shh", 396 Usage: "Enable Whisper", 397 } 398 399 // ATM the url is left to the user and deployment to 400 JSpathFlag = cli.StringFlag{ 401 Name: "jspath", 402 Usage: "JavaScript root path for `loadScript`", 403 Value: ".", 404 } 405 SolcPathFlag = cli.StringFlag{ 406 Name: "solc", 407 Usage: "Solidity compiler command to be used", 408 Value: "solc", 409 } 410 411 // Gas price oracle settings 412 GpoMinGasPriceFlag = BigFlag{ 413 Name: "gpomin", 414 Usage: "Minimum suggested gas price", 415 Value: big.NewInt(20 * params.Shannon), 416 } 417 GpoMaxGasPriceFlag = BigFlag{ 418 Name: "gpomax", 419 Usage: "Maximum suggested gas price", 420 Value: big.NewInt(500 * params.Shannon), 421 } 422 GpoFullBlockRatioFlag = cli.IntFlag{ 423 Name: "gpofull", 424 Usage: "Full block threshold for gas price calculation (%)", 425 Value: 80, 426 } 427 GpobaseStepDownFlag = cli.IntFlag{ 428 Name: "gpobasedown", 429 Usage: "Suggested gas price base step down ratio (1/1000)", 430 Value: 10, 431 } 432 GpobaseStepUpFlag = cli.IntFlag{ 433 Name: "gpobaseup", 434 Usage: "Suggested gas price base step up ratio (1/1000)", 435 Value: 100, 436 } 437 GpobaseCorrectionFactorFlag = cli.IntFlag{ 438 Name: "gpobasecf", 439 Usage: "Suggested gas price base correction factor (%)", 440 Value: 110, 441 } 442 ) 443 444 // MakeDataDir retrieves the currently requested data directory, terminating 445 // if none (or the empty string) is specified. If the node is starting a testnet, 446 // the a subdirectory of the specified datadir will be used. 447 func MakeDataDir(ctx *cli.Context) string { 448 if path := ctx.GlobalString(DataDirFlag.Name); path != "" { 449 // TODO: choose a different location outside of the regular datadir. 450 if ctx.GlobalBool(TestNetFlag.Name) { 451 return filepath.Join(path, "testnet") 452 } 453 return path 454 } 455 Fatalf("Cannot determine default data directory, please set manually (--datadir)") 456 return "" 457 } 458 459 // MakeEthashCacheDir returns the directory to use for storing the ethash cache 460 // dumps. 461 func MakeEthashCacheDir(ctx *cli.Context) string { 462 if ctx.GlobalIsSet(EthashCacheDirFlag.Name) && ctx.GlobalString(EthashCacheDirFlag.Name) == "" { 463 return "" 464 } 465 if !ctx.GlobalIsSet(EthashCacheDirFlag.Name) { 466 return "ethash" 467 } 468 return ctx.GlobalString(EthashCacheDirFlag.Name) 469 } 470 471 // MakeEthashDatasetDir returns the directory to use for storing the full ethash 472 // dataset dumps. 473 func MakeEthashDatasetDir(ctx *cli.Context) string { 474 if !ctx.GlobalIsSet(EthashDatasetDirFlag.Name) { 475 home := os.Getenv("HOME") 476 if home == "" { 477 if user, err := user.Current(); err == nil { 478 home = user.HomeDir 479 } 480 } 481 if runtime.GOOS == "windows" { 482 return filepath.Join(home, "AppData", "Ethash") 483 } 484 return filepath.Join(home, ".ethash") 485 } 486 return ctx.GlobalString(EthashDatasetDirFlag.Name) 487 } 488 489 // MakeIPCPath creates an IPC path configuration from the set command line flags, 490 // returning an empty string if IPC was explicitly disabled, or the set path. 491 func MakeIPCPath(ctx *cli.Context) string { 492 if ctx.GlobalBool(IPCDisabledFlag.Name) { 493 return "" 494 } 495 return ctx.GlobalString(IPCPathFlag.Name) 496 } 497 498 // MakeNodeKey creates a node key from set command line flags, either loading it 499 // from a file or as a specified hex value. If neither flags were provided, this 500 // method returns nil and an emphemeral key is to be generated. 501 func MakeNodeKey(ctx *cli.Context) *ecdsa.PrivateKey { 502 var ( 503 hex = ctx.GlobalString(NodeKeyHexFlag.Name) 504 file = ctx.GlobalString(NodeKeyFileFlag.Name) 505 506 key *ecdsa.PrivateKey 507 err error 508 ) 509 switch { 510 case file != "" && hex != "": 511 Fatalf("Options %q and %q are mutually exclusive", NodeKeyFileFlag.Name, NodeKeyHexFlag.Name) 512 513 case file != "": 514 if key, err = crypto.LoadECDSA(file); err != nil { 515 Fatalf("Option %q: %v", NodeKeyFileFlag.Name, err) 516 } 517 518 case hex != "": 519 if key, err = crypto.HexToECDSA(hex); err != nil { 520 Fatalf("Option %q: %v", NodeKeyHexFlag.Name, err) 521 } 522 } 523 return key 524 } 525 526 // makeNodeUserIdent creates the user identifier from CLI flags. 527 func makeNodeUserIdent(ctx *cli.Context) string { 528 var comps []string 529 if identity := ctx.GlobalString(IdentityFlag.Name); len(identity) > 0 { 530 comps = append(comps, identity) 531 } 532 if ctx.GlobalBool(VMEnableJitFlag.Name) { 533 comps = append(comps, "JIT") 534 } 535 return strings.Join(comps, "/") 536 } 537 538 // MakeBootstrapNodes creates a list of bootstrap nodes from the command line 539 // flags, reverting to pre-configured ones if none have been specified. 540 func MakeBootstrapNodes(ctx *cli.Context) []*discover.Node { 541 urls := params.MainnetBootnodes 542 if ctx.GlobalIsSet(BootnodesFlag.Name) { 543 urls = strings.Split(ctx.GlobalString(BootnodesFlag.Name), ",") 544 } else if ctx.GlobalBool(TestNetFlag.Name) { 545 urls = params.TestnetBootnodes 546 } 547 548 bootnodes := make([]*discover.Node, 0, len(urls)) 549 for _, url := range urls { 550 node, err := discover.ParseNode(url) 551 if err != nil { 552 log.Error("Bootstrap URL invalid", "enode", url, "err", err) 553 continue 554 } 555 bootnodes = append(bootnodes, node) 556 } 557 return bootnodes 558 } 559 560 // MakeBootstrapNodesV5 creates a list of bootstrap nodes from the command line 561 // flags, reverting to pre-configured ones if none have been specified. 562 func MakeBootstrapNodesV5(ctx *cli.Context) []*discv5.Node { 563 urls := params.DiscoveryV5Bootnodes 564 if ctx.GlobalIsSet(BootnodesFlag.Name) { 565 urls = strings.Split(ctx.GlobalString(BootnodesFlag.Name), ",") 566 } 567 568 bootnodes := make([]*discv5.Node, 0, len(urls)) 569 for _, url := range urls { 570 node, err := discv5.ParseNode(url) 571 if err != nil { 572 log.Error("Bootstrap URL invalid", "enode", url, "err", err) 573 continue 574 } 575 bootnodes = append(bootnodes, node) 576 } 577 return bootnodes 578 } 579 580 // MakeListenAddress creates a TCP listening address string from set command 581 // line flags. 582 func MakeListenAddress(ctx *cli.Context) string { 583 return fmt.Sprintf(":%d", ctx.GlobalInt(ListenPortFlag.Name)) 584 } 585 586 // MakeDiscoveryV5Address creates a UDP listening address string from set command 587 // line flags for the V5 discovery protocol. 588 func MakeDiscoveryV5Address(ctx *cli.Context) string { 589 return fmt.Sprintf(":%d", ctx.GlobalInt(ListenPortFlag.Name)+1) 590 } 591 592 // MakeNAT creates a port mapper from set command line flags. 593 func MakeNAT(ctx *cli.Context) nat.Interface { 594 natif, err := nat.Parse(ctx.GlobalString(NATFlag.Name)) 595 if err != nil { 596 Fatalf("Option %s: %v", NATFlag.Name, err) 597 } 598 return natif 599 } 600 601 // MakeRPCModules splits input separated by a comma and trims excessive white 602 // space from the substrings. 603 func MakeRPCModules(input string) []string { 604 result := strings.Split(input, ",") 605 for i, r := range result { 606 result[i] = strings.TrimSpace(r) 607 } 608 return result 609 } 610 611 // MakeHTTPRpcHost creates the HTTP RPC listener interface string from the set 612 // command line flags, returning empty if the HTTP endpoint is disabled. 613 func MakeHTTPRpcHost(ctx *cli.Context) string { 614 if !ctx.GlobalBool(RPCEnabledFlag.Name) { 615 return "" 616 } 617 return ctx.GlobalString(RPCListenAddrFlag.Name) 618 } 619 620 // MakeWSRpcHost creates the WebSocket RPC listener interface string from the set 621 // command line flags, returning empty if the HTTP endpoint is disabled. 622 func MakeWSRpcHost(ctx *cli.Context) string { 623 if !ctx.GlobalBool(WSEnabledFlag.Name) { 624 return "" 625 } 626 return ctx.GlobalString(WSListenAddrFlag.Name) 627 } 628 629 // MakeDatabaseHandles raises out the number of allowed file handles per process 630 // for Geth and returns half of the allowance to assign to the database. 631 func MakeDatabaseHandles() int { 632 if err := raiseFdLimit(2048); err != nil { 633 Fatalf("Failed to raise file descriptor allowance: %v", err) 634 } 635 limit, err := getFdLimit() 636 if err != nil { 637 Fatalf("Failed to retrieve file descriptor allowance: %v", err) 638 } 639 if limit > 2048 { // cap database file descriptors even if more is available 640 limit = 2048 641 } 642 return limit / 2 // Leave half for networking and other stuff 643 } 644 645 // MakeAddress converts an account specified directly as a hex encoded string or 646 // a key index in the key store to an internal account representation. 647 func MakeAddress(ks *keystore.KeyStore, account string) (accounts.Account, error) { 648 // If the specified account is a valid address, return it 649 if common.IsHexAddress(account) { 650 return accounts.Account{Address: common.HexToAddress(account)}, nil 651 } 652 // Otherwise try to interpret the account as a keystore index 653 index, err := strconv.Atoi(account) 654 if err != nil || index < 0 { 655 return accounts.Account{}, fmt.Errorf("invalid account address or index %q", account) 656 } 657 accs := ks.Accounts() 658 if len(accs) <= index { 659 return accounts.Account{}, fmt.Errorf("index %d higher than number of accounts %d", index, len(accs)) 660 } 661 return accs[index], nil 662 } 663 664 // MakeEtherbase retrieves the etherbase either from the directly specified 665 // command line flags or from the keystore if CLI indexed. 666 func MakeEtherbase(ks *keystore.KeyStore, ctx *cli.Context) common.Address { 667 accounts := ks.Accounts() 668 if !ctx.GlobalIsSet(EtherbaseFlag.Name) && len(accounts) == 0 { 669 log.Warn("No etherbase set and no accounts found as default") 670 return common.Address{} 671 } 672 etherbase := ctx.GlobalString(EtherbaseFlag.Name) 673 if etherbase == "" { 674 return common.Address{} 675 } 676 // If the specified etherbase is a valid address, return it 677 account, err := MakeAddress(ks, etherbase) 678 if err != nil { 679 Fatalf("Option %q: %v", EtherbaseFlag.Name, err) 680 } 681 return account.Address 682 } 683 684 // MakeMinerExtra resolves extradata for the miner from the set command line flags 685 // or returns a default one composed on the client, runtime and OS metadata. 686 func MakeMinerExtra(extra []byte, ctx *cli.Context) []byte { 687 if ctx.GlobalIsSet(ExtraDataFlag.Name) { 688 return []byte(ctx.GlobalString(ExtraDataFlag.Name)) 689 } 690 return extra 691 } 692 693 // MakePasswordList reads password lines from the file specified by --password. 694 func MakePasswordList(ctx *cli.Context) []string { 695 path := ctx.GlobalString(PasswordFileFlag.Name) 696 if path == "" { 697 return nil 698 } 699 text, err := ioutil.ReadFile(path) 700 if err != nil { 701 Fatalf("Failed to read password file: %v", err) 702 } 703 lines := strings.Split(string(text), "\n") 704 // Sanitise DOS line endings. 705 for i := range lines { 706 lines[i] = strings.TrimRight(lines[i], "\r") 707 } 708 return lines 709 } 710 711 // MakeNode configures a node with no services from command line flags. 712 func MakeNode(ctx *cli.Context, name, gitCommit string) *node.Node { 713 vsn := params.Version 714 if gitCommit != "" { 715 vsn += "-" + gitCommit[:8] 716 } 717 718 // if we're running a light client or server, force enable the v5 peer discovery unless it is explicitly disabled with --nodiscover 719 // note that explicitly specifying --v5disc overrides --nodiscover, in which case the later only disables v4 discovery 720 forceV5Discovery := (ctx.GlobalBool(LightModeFlag.Name) || ctx.GlobalInt(LightServFlag.Name) > 0) && !ctx.GlobalBool(NoDiscoverFlag.Name) 721 722 config := &node.Config{ 723 DataDir: MakeDataDir(ctx), 724 KeyStoreDir: ctx.GlobalString(KeyStoreDirFlag.Name), 725 UseLightweightKDF: ctx.GlobalBool(LightKDFFlag.Name), 726 PrivateKey: MakeNodeKey(ctx), 727 Name: name, 728 Version: vsn, 729 UserIdent: makeNodeUserIdent(ctx), 730 NoDiscovery: ctx.GlobalBool(NoDiscoverFlag.Name) || ctx.GlobalBool(LightModeFlag.Name), // always disable v4 discovery in light client mode 731 DiscoveryV5: ctx.GlobalBool(DiscoveryV5Flag.Name) || forceV5Discovery, 732 DiscoveryV5Addr: MakeDiscoveryV5Address(ctx), 733 BootstrapNodes: MakeBootstrapNodes(ctx), 734 BootstrapNodesV5: MakeBootstrapNodesV5(ctx), 735 ListenAddr: MakeListenAddress(ctx), 736 NAT: MakeNAT(ctx), 737 MaxPeers: ctx.GlobalInt(MaxPeersFlag.Name), 738 MaxPendingPeers: ctx.GlobalInt(MaxPendingPeersFlag.Name), 739 IPCPath: MakeIPCPath(ctx), 740 HTTPHost: MakeHTTPRpcHost(ctx), 741 HTTPPort: ctx.GlobalInt(RPCPortFlag.Name), 742 HTTPCors: ctx.GlobalString(RPCCORSDomainFlag.Name), 743 HTTPModules: MakeRPCModules(ctx.GlobalString(RPCApiFlag.Name)), 744 WSHost: MakeWSRpcHost(ctx), 745 WSPort: ctx.GlobalInt(WSPortFlag.Name), 746 WSOrigins: ctx.GlobalString(WSAllowedOriginsFlag.Name), 747 WSModules: MakeRPCModules(ctx.GlobalString(WSApiFlag.Name)), 748 } 749 if ctx.GlobalBool(DevModeFlag.Name) { 750 if !ctx.GlobalIsSet(DataDirFlag.Name) { 751 config.DataDir = filepath.Join(os.TempDir(), "/ethereum_dev_mode") 752 } 753 // --dev mode does not need p2p networking. 754 config.MaxPeers = 0 755 config.ListenAddr = ":0" 756 } 757 if netrestrict := ctx.GlobalString(NetrestrictFlag.Name); netrestrict != "" { 758 list, err := netutil.ParseNetlist(netrestrict) 759 if err != nil { 760 Fatalf("Option %q: %v", NetrestrictFlag.Name, err) 761 } 762 config.NetRestrict = list 763 } 764 765 stack, err := node.New(config) 766 if err != nil { 767 Fatalf("Failed to create the protocol stack: %v", err) 768 } 769 return stack 770 } 771 772 // RegisterEthService configures eth.Ethereum from command line flags and adds it to the 773 // given node. 774 func RegisterEthService(ctx *cli.Context, stack *node.Node, extra []byte) { 775 // Avoid conflicting network flags 776 networks, netFlags := 0, []cli.BoolFlag{DevModeFlag, TestNetFlag} 777 for _, flag := range netFlags { 778 if ctx.GlobalBool(flag.Name) { 779 networks++ 780 } 781 } 782 if networks > 1 { 783 Fatalf("The %v flags are mutually exclusive", netFlags) 784 } 785 ks := stack.AccountManager().Backends(keystore.KeyStoreType)[0].(*keystore.KeyStore) 786 787 ethConf := ð.Config{ 788 Etherbase: MakeEtherbase(ks, ctx), 789 FastSync: ctx.GlobalBool(FastSyncFlag.Name), 790 LightMode: ctx.GlobalBool(LightModeFlag.Name), 791 LightServ: ctx.GlobalInt(LightServFlag.Name), 792 LightPeers: ctx.GlobalInt(LightPeersFlag.Name), 793 MaxPeers: ctx.GlobalInt(MaxPeersFlag.Name), 794 DatabaseCache: ctx.GlobalInt(CacheFlag.Name), 795 DatabaseHandles: MakeDatabaseHandles(), 796 NetworkId: ctx.GlobalInt(NetworkIdFlag.Name), 797 MinerThreads: ctx.GlobalInt(MinerThreadsFlag.Name), 798 ExtraData: MakeMinerExtra(extra, ctx), 799 DocRoot: ctx.GlobalString(DocRootFlag.Name), 800 GasPrice: GlobalBig(ctx, GasPriceFlag.Name), 801 GpoMinGasPrice: GlobalBig(ctx, GpoMinGasPriceFlag.Name), 802 GpoMaxGasPrice: GlobalBig(ctx, GpoMaxGasPriceFlag.Name), 803 GpoFullBlockRatio: ctx.GlobalInt(GpoFullBlockRatioFlag.Name), 804 GpobaseStepDown: ctx.GlobalInt(GpobaseStepDownFlag.Name), 805 GpobaseStepUp: ctx.GlobalInt(GpobaseStepUpFlag.Name), 806 GpobaseCorrectionFactor: ctx.GlobalInt(GpobaseCorrectionFactorFlag.Name), 807 SolcPath: ctx.GlobalString(SolcPathFlag.Name), 808 EthashCacheDir: MakeEthashCacheDir(ctx), 809 EthashCachesInMem: ctx.GlobalInt(EthashCachesInMemoryFlag.Name), 810 EthashCachesOnDisk: ctx.GlobalInt(EthashCachesOnDiskFlag.Name), 811 EthashDatasetDir: MakeEthashDatasetDir(ctx), 812 EthashDatasetsInMem: ctx.GlobalInt(EthashDatasetsInMemoryFlag.Name), 813 EthashDatasetsOnDisk: ctx.GlobalInt(EthashDatasetsOnDiskFlag.Name), 814 EnablePreimageRecording: ctx.GlobalBool(VMEnableDebugFlag.Name), 815 } 816 817 // Override any default configs in dev mode or the test net 818 switch { 819 case ctx.GlobalBool(TestNetFlag.Name): 820 if !ctx.GlobalIsSet(NetworkIdFlag.Name) { 821 ethConf.NetworkId = 3 822 } 823 ethConf.Genesis = core.DefaultTestnetGenesisBlock() 824 case ctx.GlobalBool(DevModeFlag.Name): 825 ethConf.Genesis = core.DevGenesisBlock() 826 if !ctx.GlobalIsSet(GasPriceFlag.Name) { 827 ethConf.GasPrice = new(big.Int) 828 } 829 ethConf.PowTest = true 830 } 831 // Override any global options pertaining to the Ethereum protocol 832 if gen := ctx.GlobalInt(TrieCacheGenFlag.Name); gen > 0 { 833 state.MaxTrieCacheGen = uint16(gen) 834 } 835 836 if ethConf.LightMode { 837 if err := stack.Register(func(ctx *node.ServiceContext) (node.Service, error) { 838 return les.New(ctx, ethConf) 839 }); err != nil { 840 Fatalf("Failed to register the Ethereum light node service: %v", err) 841 } 842 } else { 843 if err := stack.Register(func(ctx *node.ServiceContext) (node.Service, error) { 844 fullNode, err := eth.New(ctx, ethConf) 845 if fullNode != nil && ethConf.LightServ > 0 { 846 ls, _ := les.NewLesServer(fullNode, ethConf) 847 fullNode.AddLesServer(ls) 848 } 849 return fullNode, err 850 }); err != nil { 851 Fatalf("Failed to register the Ethereum full node service: %v", err) 852 } 853 } 854 } 855 856 // RegisterShhService configures Whisper and adds it to the given node. 857 func RegisterShhService(stack *node.Node) { 858 if err := stack.Register(func(*node.ServiceContext) (node.Service, error) { return whisper.New(), nil }); err != nil { 859 Fatalf("Failed to register the Whisper service: %v", err) 860 } 861 } 862 863 // RegisterEthStatsService configures the Ethereum Stats daemon and adds it to 864 // th egiven node. 865 func RegisterEthStatsService(stack *node.Node, url string) { 866 if err := stack.Register(func(ctx *node.ServiceContext) (node.Service, error) { 867 // Retrieve both eth and les services 868 var ethServ *eth.Ethereum 869 ctx.Service(ðServ) 870 871 var lesServ *les.LightEthereum 872 ctx.Service(&lesServ) 873 874 return ethstats.New(url, ethServ, lesServ) 875 }); err != nil { 876 Fatalf("Failed to register the Ethereum Stats service: %v", err) 877 } 878 } 879 880 // SetupNetwork configures the system for either the main net or some test network. 881 func SetupNetwork(ctx *cli.Context) { 882 params.TargetGasLimit = new(big.Int).SetUint64(ctx.GlobalUint64(TargetGasLimitFlag.Name)) 883 } 884 885 func ChainDbName(ctx *cli.Context) string { 886 if ctx.GlobalBool(LightModeFlag.Name) { 887 return "lightchaindata" 888 } else { 889 return "chaindata" 890 } 891 } 892 893 // MakeChainDatabase open an LevelDB using the flags passed to the client and will hard crash if it fails. 894 func MakeChainDatabase(ctx *cli.Context, stack *node.Node) ethdb.Database { 895 var ( 896 cache = ctx.GlobalInt(CacheFlag.Name) 897 handles = MakeDatabaseHandles() 898 name = ChainDbName(ctx) 899 ) 900 901 chainDb, err := stack.OpenDatabase(name, cache, handles) 902 if err != nil { 903 Fatalf("Could not open database: %v", err) 904 } 905 return chainDb 906 } 907 908 func MakeGenesis(ctx *cli.Context) *core.Genesis { 909 var genesis *core.Genesis 910 switch { 911 case ctx.GlobalBool(TestNetFlag.Name): 912 genesis = core.DefaultTestnetGenesisBlock() 913 case ctx.GlobalBool(DevModeFlag.Name): 914 genesis = core.DevGenesisBlock() 915 } 916 return genesis 917 } 918 919 // MakeChain creates a chain manager from set command line flags. 920 func MakeChain(ctx *cli.Context, stack *node.Node) (chain *core.BlockChain, chainDb ethdb.Database) { 921 var err error 922 chainDb = MakeChainDatabase(ctx, stack) 923 924 seal := pow.PoW(pow.FakePow{}) 925 if !ctx.GlobalBool(FakePoWFlag.Name) { 926 seal = pow.NewFullEthash("", 1, 0, "", 1, 0) 927 } 928 config, _, err := core.SetupGenesisBlock(chainDb, MakeGenesis(ctx)) 929 if err != nil { 930 Fatalf("%v", err) 931 } 932 vmcfg := vm.Config{EnablePreimageRecording: ctx.GlobalBool(VMEnableDebugFlag.Name)} 933 chain, err = core.NewBlockChain(chainDb, config, seal, new(event.TypeMux), vmcfg) 934 if err != nil { 935 Fatalf("Can't create BlockChain: %v", err) 936 } 937 return chain, chainDb 938 } 939 940 // MakeConsolePreloads retrieves the absolute paths for the console JavaScript 941 // scripts to preload before starting. 942 func MakeConsolePreloads(ctx *cli.Context) []string { 943 // Skip preloading if there's nothing to preload 944 if ctx.GlobalString(PreloadJSFlag.Name) == "" { 945 return nil 946 } 947 // Otherwise resolve absolute paths and return them 948 preloads := []string{} 949 950 assets := ctx.GlobalString(JSpathFlag.Name) 951 for _, file := range strings.Split(ctx.GlobalString(PreloadJSFlag.Name), ",") { 952 preloads = append(preloads, common.AbsolutePath(assets, strings.TrimSpace(file))) 953 } 954 return preloads 955 }