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