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