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