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