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