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