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